From 35500a87c60d84efe8077c9bda064ca02da4b69e Mon Sep 17 00:00:00 2001 From: Jeff Hutchinson Date: Tue, 30 Mar 2021 19:33:19 -0400 Subject: [PATCH] initial port of the new interpreter --- Engine/source/T3D/gameBase/gameConnection.cpp | 13 +- Engine/source/app/net/net.cpp | 4 +- Engine/source/app/net/tcpObject.cpp | 4 +- Engine/source/app/net/tcpObject.h | 2 +- Engine/source/console/SimXMLDocument.cpp | 2 +- Engine/source/console/SimXMLDocument.h | 2 +- Engine/source/console/ast.h | 278 +- Engine/source/console/astAlloc.cpp | 180 +- Engine/source/console/astNodes.cpp | 1297 +++---- Engine/source/console/codeBlock.cpp | 1517 ++++----- Engine/source/console/codeInterpreter.cpp | 3018 ----------------- Engine/source/console/codeInterpreter.h | 262 -- Engine/source/console/compiledEval.cpp | 1909 ++++++++++- Engine/source/console/compiler.h | 24 +- Engine/source/console/console.cpp | 229 +- Engine/source/console/consoleInternal.cpp | 165 +- Engine/source/console/consoleInternal.h | 83 +- Engine/source/console/consoleLogger.cpp | 8 +- Engine/source/console/consoleLogger.h | 2 +- Engine/source/console/consoleValueStack.h | 121 + Engine/source/console/sim.h | 9 +- Engine/source/console/simManager.cpp | 23 +- Engine/source/console/simSet.cpp | 12 +- Engine/source/console/simSet.h | 4 +- Engine/source/console/stringStack.cpp | 225 -- Engine/source/console/stringStack.h | 44 - Engine/source/console/test/ScriptTest.cpp | 2 + Engine/source/console/test/consoleTest.cpp | 3 + Engine/source/console/test/engineAPITest.cpp | 4 +- Engine/source/core/strings/stringFunctions.h | 5 + Engine/source/environment/waterObject.cpp | 2 +- Engine/source/environment/waterObject.h | 2 +- Engine/source/gui/core/guiControl.cpp | 2 +- Engine/source/gui/core/guiControl.h | 2 +- Engine/source/gui/worldEditor/worldEditor.cpp | 6 +- Engine/source/gui/worldEditor/worldEditor.h | 2 +- Engine/source/platformWin32/winMath.cpp | 19 +- Engine/source/sfx/sfxSource.cpp | 2 +- Engine/source/sfx/sfxSource.h | 2 +- Engine/source/sfx/sfxTrack.cpp | 2 +- Engine/source/sfx/sfxTrack.h | 2 +- .../shaderGen/GLSL/customFeatureGLSL.cpp | 6 +- .../source/shaderGen/GLSL/customFeatureGLSL.h | 2 +- .../shaderGen/HLSL/customFeatureHLSL.cpp | 6 +- .../source/shaderGen/HLSL/customFeatureHLSL.h | 2 +- .../source/shaderGen/customShaderFeature.cpp | 2 +- Engine/source/shaderGen/customShaderFeature.h | 2 +- 47 files changed, 3675 insertions(+), 5839 deletions(-) delete mode 100644 Engine/source/console/codeInterpreter.cpp delete mode 100644 Engine/source/console/codeInterpreter.h create mode 100644 Engine/source/console/consoleValueStack.h diff --git a/Engine/source/T3D/gameBase/gameConnection.cpp b/Engine/source/T3D/gameBase/gameConnection.cpp index 01ae0ee17..e4a4c9f5e 100644 --- a/Engine/source/T3D/gameBase/gameConnection.cpp +++ b/Engine/source/T3D/gameBase/gameConnection.cpp @@ -331,7 +331,7 @@ DefineEngineStringlyVariadicMethod(GameConnection, setConnectArgs, void, 3, 17, "@see GameConnection::onConnect()\n\n") { - StringStackWrapper args(argc - 2, argv + 2); + ConsoleValueToStringArrayWrapper args(argc - 2, argv + 2); object->setConnectArgs(args.count(), args); } @@ -494,11 +494,17 @@ bool GameConnection::readConnectRequest(BitStream *stream, const char **errorStr *errorString = "CR_INVALID_ARGS"; return false; } - ConsoleValueRef connectArgv[MaxConnectArgs + 3]; + ConsoleValue connectArgv[MaxConnectArgs + 3]; ConsoleValue connectArgvValue[MaxConnectArgs + 3]; + // TODO(JTH): Fix pls. + AssertISV(false, "TODO: FIX CONSOLE VALUE"); + return false; + + /* for(U32 i = 0; i < mConnectArgc+3; i++) { + connectArgv[i].value = &connectArgvValue[i]; connectArgvValue[i].init(); } @@ -524,6 +530,7 @@ bool GameConnection::readConnectRequest(BitStream *stream, const char **errorStr return false; } return true; + */ } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -1088,7 +1095,7 @@ bool GameConnection::readDemoStartBlock(BitStream *stream) void GameConnection::demoPlaybackComplete() { static const char* demoPlaybackArgv[1] = { "demoPlaybackComplete" }; - static StringStackConsoleWrapper demoPlaybackCmd(1, demoPlaybackArgv); + static StringArrayToConsoleValueWrapper demoPlaybackCmd(1, demoPlaybackArgv); Sim::postCurrentEvent(Sim::getRootGroup(), new SimConsoleEvent(demoPlaybackCmd.argc, demoPlaybackCmd.argv, false)); Parent::demoPlaybackComplete(); diff --git a/Engine/source/app/net/net.cpp b/Engine/source/app/net/net.cpp index 3de813e89..1e2255323 100644 --- a/Engine/source/app/net/net.cpp +++ b/Engine/source/app/net/net.cpp @@ -251,7 +251,7 @@ DefineEngineStringlyVariadicFunction( commandToServer, void, 2, RemoteCommandEve NetConnection *conn = NetConnection::getConnectionToServer(); if(!conn) return; - StringStackWrapper args(argc - 1, argv + 1); + ConsoleValueToStringArrayWrapper args(argc - 1, argv + 1); RemoteCommandEvent::sendRemoteCommand(conn, args.count(), args); } @@ -289,7 +289,7 @@ DefineEngineStringlyVariadicFunction( commandToClient, void, 3, RemoteCommandEve NetConnection *conn; if(!Sim::findObject(argv[1], conn)) return; - StringStackWrapper args(argc - 2, argv + 2); + ConsoleValueToStringArrayWrapper args(argc - 2, argv + 2); RemoteCommandEvent::sendRemoteCommand(conn, args.count(), args); } diff --git a/Engine/source/app/net/tcpObject.cpp b/Engine/source/app/net/tcpObject.cpp index 07c8908eb..1b77e3bad 100644 --- a/Engine/source/app/net/tcpObject.cpp +++ b/Engine/source/app/net/tcpObject.cpp @@ -236,13 +236,13 @@ TCPObject::~TCPObject() } } -bool TCPObject::processArguments(S32 argc, ConsoleValueRef *argv) +bool TCPObject::processArguments(S32 argc, ConsoleValue *argv) { if(argc == 0) return true; else if(argc == 1) { - addToTable(NetSocket::fromHandle(dAtoi(argv[0]))); + addToTable(NetSocket::fromHandle(argv[0].getInt())); return true; } return false; diff --git a/Engine/source/app/net/tcpObject.h b/Engine/source/app/net/tcpObject.h index 9a8b5e40d..a869f48be 100644 --- a/Engine/source/app/net/tcpObject.h +++ b/Engine/source/app/net/tcpObject.h @@ -83,7 +83,7 @@ public: void disconnect(); State getState() { return mState; } - bool processArguments(S32 argc, ConsoleValueRef *argv); + bool processArguments(S32 argc, ConsoleValue *argv); void send(const U8 *buffer, U32 bufferLen); ///Send an entire file over tcp diff --git a/Engine/source/console/SimXMLDocument.cpp b/Engine/source/console/SimXMLDocument.cpp index df45888d1..66a116dfe 100644 --- a/Engine/source/console/SimXMLDocument.cpp +++ b/Engine/source/console/SimXMLDocument.cpp @@ -158,7 +158,7 @@ SimXMLDocument::~SimXMLDocument() // ----------------------------------------------------------------------------- // Included for completeness. // ----------------------------------------------------------------------------- -bool SimXMLDocument::processArguments(S32 argc, ConsoleValueRef *argv) +bool SimXMLDocument::processArguments(S32 argc, ConsoleValue *argv) { return argc == 0; } diff --git a/Engine/source/console/SimXMLDocument.h b/Engine/source/console/SimXMLDocument.h index 342917cff..d31104a68 100644 --- a/Engine/source/console/SimXMLDocument.h +++ b/Engine/source/console/SimXMLDocument.h @@ -57,7 +57,7 @@ class SimXMLDocument: public SimObject // tie in to the script language. The .cc file has more in depth // comments on these. //----------------------------------------------------------------------- - bool processArguments(S32 argc, ConsoleValueRef *argv); + bool processArguments(S32 argc, ConsoleValue *argv); bool onAdd(); void onRemove(); static void initPersistFields(); diff --git a/Engine/source/console/ast.h b/Engine/source/console/ast.h index f81971413..558446534 100644 --- a/Engine/source/console/ast.h +++ b/Engine/source/console/ast.h @@ -39,8 +39,15 @@ enum TypeReq TypeReqNone, TypeReqUInt, TypeReqFloat, - TypeReqString, - TypeReqVar + TypeReqString +}; + +enum ExprNodeName +{ + NameExprNode, + NameFloatNode, + NameIntNode, + NameVarNode }; /// Representation of a node for the scripting language parser. @@ -52,7 +59,7 @@ enum TypeReq /// each representing a different language construct. struct StmtNode { - StmtNode *mNext; ///< Next entry in parse tree. + StmtNode* next; ///< Next entry in parse tree. StmtNode(); virtual ~StmtNode() {} @@ -61,8 +68,8 @@ struct StmtNode /// @{ /// - void append(StmtNode *next); - StmtNode *getNext() const { return mNext; } + void append(StmtNode* next); + StmtNode* getNext() const { return next; } /// @} @@ -79,93 +86,95 @@ struct StmtNode /// @name Breaking /// @{ - void addBreakLine(CodeStream &codeStream); + void addBreakLine(CodeStream& codeStream); /// @} /// @name Compilation /// @{ - virtual U32 compileStmt(CodeStream &codeStream, U32 ip) = 0; + virtual U32 compileStmt(CodeStream& codeStream, U32 ip) = 0; virtual void setPackage(StringTableEntry packageName); /// @} }; /// Helper macro #ifndef DEBUG_AST_NODES -# define DBG_STMT_TYPE(s) virtual String dbgStmtType() const { return String(#s); } +# define DBG_STMT_TYPE(s) virtual const char* dbgStmtType() const { return "#s"; } #else # define DBG_STMT_TYPE(s) #endif struct BreakStmtNode : StmtNode { - static BreakStmtNode *alloc(S32 lineNumber); + static BreakStmtNode* alloc(S32 lineNumber); - U32 compileStmt(CodeStream &codeStream, U32 ip); + 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); + U32 compileStmt(CodeStream& codeStream, U32 ip); DBG_STMT_TYPE(ContinueStmtNode); }; /// A mathematical expression. struct ExprNode : StmtNode { + ExprNode* optimizedNode; - U32 compileStmt(CodeStream &codeStream, U32 ip); + U32 compileStmt(CodeStream& codeStream, U32 ip); - virtual U32 compile(CodeStream &codeStream, U32 ip, TypeReq type) = 0; + virtual U32 compile(CodeStream& codeStream, U32 ip, TypeReq type) = 0; virtual TypeReq getPreferredType() = 0; + virtual ExprNodeName getExprNodeNameEnum() const { return NameExprNode; } }; struct ReturnStmtNode : StmtNode { - ExprNode *expr; + ExprNode* expr; - static ReturnStmtNode *alloc(S32 lineNumber, ExprNode *expr); + static ReturnStmtNode* alloc(S32 lineNumber, ExprNode* expr); - U32 compileStmt(CodeStream &codeStream, U32 ip); + U32 compileStmt(CodeStream& codeStream, U32 ip); DBG_STMT_TYPE(ReturnStmtNode); }; struct IfStmtNode : StmtNode { - ExprNode *testExpr; - StmtNode *ifBlock, *elseBlock; + ExprNode* testExpr; + StmtNode* ifBlock, * elseBlock; U32 endifOffset; U32 elseOffset; bool integer; bool propagate; - 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); + 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); + U32 compileStmt(CodeStream& codeStream, U32 ip); DBG_STMT_TYPE(IfStmtNode); }; struct LoopStmtNode : StmtNode { - ExprNode *testExpr; - ExprNode *initExpr; - ExprNode *endLoopExpr; - StmtNode *loopBlock; + ExprNode* testExpr; + ExprNode* initExpr; + ExprNode* endLoopExpr; + StmtNode* loopBlock; bool isDoLoop; U32 breakOffset; U32 continueOffset; 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); + U32 compileStmt(CodeStream& codeStream, U32 ip); DBG_STMT_TYPE(LoopStmtNode); }; @@ -189,35 +198,38 @@ struct IterStmtNode : StmtNode static IterStmtNode* alloc(S32 lineNumber, StringTableEntry varName, ExprNode* containerExpr, StmtNode* body, bool isStringIter); - U32 compileStmt(CodeStream &codeStream, U32 ip); + U32 compileStmt(CodeStream& codeStream, U32 ip); }; /// A binary mathematical expression (ie, left op right). struct BinaryExprNode : ExprNode { S32 op; - ExprNode *left; - ExprNode *right; + ExprNode* left; + ExprNode* right; }; 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); + + bool optimize(); - U32 compile(CodeStream &codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(FloatBinaryExprNode); }; struct ConditionalExprNode : ExprNode { - ExprNode *testExpr; - ExprNode *trueExpr; - ExprNode *falseExpr; + ExprNode* testExpr; + 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 U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); virtual TypeReq getPreferredType(); DBG_STMT_TYPE(ConditionalExprNode); }; @@ -227,11 +239,13 @@ 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); + bool optimize(); + + U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(IntBinaryExprNode); }; @@ -239,9 +253,9 @@ 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); + U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(StreqExprNode); }; @@ -249,19 +263,19 @@ 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); + U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(StrcatExprNode); }; 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); + U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(CommaCatExprNode); }; @@ -269,12 +283,12 @@ struct CommaCatExprNode : BinaryExprNode struct IntUnaryExprNode : ExprNode { S32 op; - ExprNode *expr; + 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); + U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(IntUnaryExprNode); }; @@ -282,11 +296,11 @@ struct IntUnaryExprNode : ExprNode struct FloatUnaryExprNode : ExprNode { S32 op; - ExprNode *expr; + 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); + U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(FloatUnaryExprNode); }; @@ -294,12 +308,13 @@ struct FloatUnaryExprNode : ExprNode struct VarNode : ExprNode { StringTableEntry varName; - ExprNode *arrayIndex; + 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); + U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); + virtual ExprNodeName getExprNodeNameEnum() const { return NameVarNode; } DBG_STMT_TYPE(VarNode); }; @@ -308,10 +323,11 @@ 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); + U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); + virtual ExprNodeName getExprNodeNameEnum() const { return NameIntNode; } DBG_STMT_TYPE(IntNode); }; @@ -320,24 +336,25 @@ 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); + U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); + virtual ExprNodeName getExprNodeNameEnum() const { return NameFloatNode; } DBG_STMT_TYPE(FloatNode); }; struct StrConstNode : ExprNode { - char *str; + char* str; F64 fVal; U32 index; 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); + U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(StrConstNode); }; @@ -348,9 +365,9 @@ 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); + U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(ConstantNode); }; @@ -358,13 +375,13 @@ struct ConstantNode : ExprNode struct AssignExprNode : ExprNode { StringTableEntry varName; - ExprNode *expr; - ExprNode *arrayIndex; + ExprNode* expr; + 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); + U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(AssignExprNode); }; @@ -373,22 +390,22 @@ struct AssignDecl { S32 lineNumber; S32 token; - ExprNode *expr; + ExprNode* expr; bool integer; }; struct AssignOpExprNode : ExprNode { StringTableEntry varName; - ExprNode *expr; - ExprNode *arrayIndex; + ExprNode* expr; + ExprNode* arrayIndex; S32 op; 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); + U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(AssignOpExprNode); }; @@ -396,22 +413,22 @@ struct AssignOpExprNode : ExprNode struct TTagSetStmtNode : StmtNode { StringTableEntry tag; - ExprNode *valueExpr; - ExprNode *stringExpr; + 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); + U32 compileStmt(CodeStream& codeStream, U32 ip); DBG_STMT_TYPE(TTagSetStmtNode); }; struct TTagDerefNode : ExprNode { - ExprNode *expr; + ExprNode* expr; - static TTagDerefNode *alloc(S32 lineNumber, ExprNode *expr); + static TTagDerefNode* alloc(S32 lineNumber, ExprNode* expr); - U32 compile(CodeStream &codeStream, U32 ip, TypeReq type); + U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(TTagDerefNode); }; @@ -420,9 +437,9 @@ 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); + U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(TTagExprNode); }; @@ -431,42 +448,31 @@ struct FuncCallExprNode : ExprNode { StringTableEntry funcName; StringTableEntry nameSpace; - ExprNode *args; + ExprNode* args; U32 callType; enum { FunctionCall, + StaticCall, MethodCall, 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); + 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; + 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); + U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(AssertCallExprNode); }; @@ -474,19 +480,19 @@ struct AssertCallExprNode : ExprNode struct SlotDecl { S32 lineNumber; - ExprNode *object; + ExprNode* object; StringTableEntry slotName; - ExprNode *array; + ExprNode* array; }; struct SlotAccessNode : ExprNode { - ExprNode *objectExpr, *arrayExpr; + 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); + U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(SlotAccessNode); }; @@ -494,101 +500,99 @@ struct SlotAccessNode : ExprNode struct InternalSlotDecl { S32 lineNumber; - ExprNode *object; - ExprNode *slotExpr; + ExprNode* object; + ExprNode* slotExpr; bool recurse; }; struct InternalSlotAccessNode : ExprNode { - ExprNode *objectExpr, *slotExpr; + 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); + U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(InternalSlotAccessNode); }; struct SlotAssignNode : ExprNode { - ExprNode *objectExpr, *arrayExpr; + ExprNode* objectExpr, * arrayExpr; StringTableEntry slotName; - ExprNode *valueExpr; + 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); + U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(SlotAssignNode); }; struct SlotAssignOpNode : ExprNode { - ExprNode *objectExpr, *arrayExpr; + ExprNode* objectExpr, * arrayExpr; StringTableEntry slotName; S32 op; - ExprNode *valueExpr; + ExprNode* valueExpr; 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); + U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); TypeReq getPreferredType(); DBG_STMT_TYPE(SlotAssignOpNode); }; struct ObjectDeclNode : ExprNode { - ExprNode *classNameExpr; + ExprNode* classNameExpr; StringTableEntry parentObject; - ExprNode *objectNameExpr; - ExprNode *argList; - SlotAssignNode *slotDecls; - ObjectDeclNode *subObjects; + ExprNode* objectNameExpr; + ExprNode* argList; + SlotAssignNode* slotDecls; + ObjectDeclNode* subObjects; bool isDatablock; U32 failOffset; 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); + U32 compile(CodeStream& codeStream, U32 ip, TypeReq type); + U32 compileSubObject(CodeStream& codeStream, U32 ip, bool); TypeReq getPreferredType(); DBG_STMT_TYPE(ObjectDeclNode); }; struct ObjectBlockDecl { - SlotAssignNode *slots; - ObjectDeclNode *decls; + SlotAssignNode* slots; + ObjectDeclNode* decls; }; struct FunctionDeclStmtNode : StmtNode { StringTableEntry fnName; - VarNode *args; - StmtNode *stmts; + VarNode* args; + StmtNode* stmts; StringTableEntry nameSpace; StringTableEntry package; 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); + U32 compileStmt(CodeStream& codeStream, U32 ip); void setPackage(StringTableEntry packageName); DBG_STMT_TYPE(FunctionDeclStmtNode); }; -extern StmtNode *gStatementList; -extern StmtNode *gAnonFunctionList; -extern U32 gAnonFunctionID; +extern StmtNode* gStatementList; extern ExprEvalState gEvalState; #endif diff --git a/Engine/source/console/astAlloc.cpp b/Engine/source/console/astAlloc.cpp index 521b6dbcc..58d5a0d7f 100644 --- a/Engine/source/console/astAlloc.cpp +++ b/Engine/source/console/astAlloc.cpp @@ -1,5 +1,5 @@ //----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC +// Copyright (c) 2013 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 @@ -20,7 +20,6 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "platform/platform.h" #include "console/console.h" #include "console/compiler.h" #include "console/consoleInternal.h" @@ -38,25 +37,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 +63,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 +77,9 @@ IfStmtNode *IfStmtNode::alloc(S32 lineNumber, ExprNode *testExpr, StmtNode *ifBl 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; @@ -111,11 +110,12 @@ IterStmtNode* IterStmtNode::alloc(S32 lineNumber, StringTableEntry varName, Expr 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; + ret->optimizedNode = NULL; ret->op = op; ret->left = left; @@ -124,11 +124,12 @@ FloatBinaryExprNode *FloatBinaryExprNode::alloc(S32 lineNumber, S32 op, ExprNode 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; + ret->optimizedNode = NULL; ret->op = op; ret->left = left; @@ -137,11 +138,12 @@ IntBinaryExprNode *IntBinaryExprNode::alloc(S32 lineNumber, S32 op, ExprNode *le 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->optimizedNode = NULL; ret->left = left; ret->right = right; ret->eq = eq; @@ -149,11 +151,12 @@ StreqExprNode *StreqExprNode::alloc(S32 lineNumber, ExprNode *left, ExprNode *ri return ret; } -StrcatExprNode *StrcatExprNode::alloc(S32 lineNumber, ExprNode *left, ExprNode *right, S32 appendChar) +StrcatExprNode* StrcatExprNode::alloc(S32 lineNumber, ExprNode* left, ExprNode* right, int appendChar) { - StrcatExprNode *ret = (StrcatExprNode *)consoleAlloc(sizeof(StrcatExprNode)); + StrcatExprNode* ret = (StrcatExprNode*)consoleAlloc(sizeof(StrcatExprNode)); constructInPlace(ret); ret->dbgLineNumber = lineNumber; + ret->optimizedNode = NULL; ret->left = left; ret->right = right; ret->appendChar = appendChar; @@ -161,61 +164,67 @@ 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->optimizedNode = NULL; ret->left = left; ret->right = right; 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->optimizedNode = NULL; ret->op = op; ret->expr = expr; 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->optimizedNode = NULL; ret->op = op; ret->expr = expr; 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->optimizedNode = NULL; ret->varName = varName; ret->arrayIndex = arrayIndex; 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->optimizedNode = NULL; 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->optimizedNode = NULL; ret->testExpr = testExpr; ret->trueExpr = trueExpr; ret->falseExpr = falseExpr; @@ -223,44 +232,50 @@ ConditionalExprNode *ConditionalExprNode::alloc(S32 lineNumber, ExprNode *testEx 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->optimizedNode = NULL; 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); + S32 len = dStrlen(str); + ret->dbgLineNumber = lineNumber; - dsize_t retStrLen = dStrlen(str) + 1; - ret->str = (char *)consoleAlloc(retStrLen); + ret->optimizedNode = NULL; + ret->str = (char*)consoleAlloc(len + 1); ret->tag = tag; ret->doc = doc; - dStrcpy(ret->str, str, retStrLen); + dStrcpy(ret->str, str, len); + ret->str[len] = '\0'; 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->optimizedNode = NULL; 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->optimizedNode = NULL; ret->varName = varName; ret->expr = expr; ret->arrayIndex = arrayIndex; @@ -268,11 +283,12 @@ 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->optimizedNode = NULL; ret->varName = varName; ret->expr = expr; ret->arrayIndex = arrayIndex; @@ -280,9 +296,9 @@ AssignOpExprNode *AssignOpExprNode::alloc(S32 lineNumber, StringTableEntry varNa 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; @@ -291,59 +307,54 @@ TTagSetStmtNode *TTagSetStmtNode::alloc(S32 lineNumber, StringTableEntry tag, Ex 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->optimizedNode = NULL; 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->optimizedNode = NULL; 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->optimizedNode = NULL; ret->funcName = funcName; ret->nameSpace = nameSpace; ret->args = args; if (dot) ret->callType = MethodCall; - else + else if (nameSpace != NULL) { - if (nameSpace && !dStricmp(nameSpace, "Parent")) + if (dStricmp(nameSpace, "Parent") == 0) ret->callType = ParentCall; else - ret->callType = FunctionCall; + ret->callType = StaticCall; } + else + ret->callType = FunctionCall; return ret; } -FuncPointerCallExprNode *FuncPointerCallExprNode::alloc(S32 lineNumber, ExprNode *funcPointer, ExprNode *args) +AssertCallExprNode* AssertCallExprNode::alloc(S32 lineNumber, ExprNode* testExpr, const char* message) { - FuncPointerCallExprNode *ret = (FuncPointerCallExprNode *)consoleAlloc(sizeof(FuncPointerCallExprNode)); - constructInPlace(ret); - ret->dbgLineNumber = lineNumber; - ret->funcPointer = funcPointer; - ret->args = args; - return ret; -} +#ifdef TORQUE_ENABLE_SCRIPTASSERTS -AssertCallExprNode *AssertCallExprNode::alloc(S32 lineNumber, ExprNode *testExpr, const char *message) -{ -#ifdef TORQUE_ENABLE_SCRIPTASSERTS - - AssertCallExprNode *ret = (AssertCallExprNode *)consoleAlloc(sizeof(FuncCallExprNode)); + AssertCallExprNode* ret = (AssertCallExprNode*)consoleAlloc(sizeof(FuncCallExprNode)); constructInPlace(ret); ret->dbgLineNumber = lineNumber; ret->testExpr = testExpr; @@ -357,10 +368,11 @@ AssertCallExprNode *AssertCallExprNode::alloc(S32 lineNumber, ExprNode *testExpr #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->optimizedNode = NULL; ret->dbgLineNumber = lineNumber; ret->objectExpr = objectExpr; ret->arrayExpr = arrayExpr; @@ -368,22 +380,24 @@ SlotAccessNode *SlotAccessNode::alloc(S32 lineNumber, ExprNode *objectExpr, Expr 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->optimizedNode = NULL; ret->objectExpr = objectExpr; ret->slotExpr = slotExpr; ret->recurse = recurse; 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->optimizedNode = NULL; ret->objectExpr = objectExpr; ret->arrayExpr = arrayExpr; ret->slotName = slotName; @@ -392,11 +406,12 @@ SlotAssignNode *SlotAssignNode::alloc(S32 lineNumber, ExprNode *objectExpr, Expr 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->optimizedNode = NULL; ret->objectExpr = objectExpr; ret->arrayExpr = arrayExpr; ret->slotName = slotName; @@ -405,11 +420,12 @@ 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->optimizedNode = NULL; ret->classNameExpr = classNameExpr; ret->objectNameExpr = objectNameExpr; ret->argList = argList; @@ -422,13 +438,13 @@ ObjectDeclNode *ObjectDeclNode::alloc(S32 lineNumber, ExprNode *classNameExpr, E if (parentObject) ret->parentObject = parentObject; else - ret->parentObject = StringTable->EmptyString(); + ret->parentObject = StringTable->insert(""); 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; diff --git a/Engine/source/console/astNodes.cpp b/Engine/source/console/astNodes.cpp index 51bde9d61..28e6b4960 100644 --- a/Engine/source/console/astNodes.cpp +++ b/Engine/source/console/astNodes.cpp @@ -44,94 +44,66 @@ struct Token namespace Compiler { - U32 compileBlock(StmtNode *block, CodeStream &codeStream, U32 ip) + U32 compileBlock(StmtNode* block, CodeStream& codeStream, U32 ip) { - for (StmtNode *walk = block; walk; walk = walk->getNext()) + for (StmtNode* walk = block; walk; walk = walk->getNext()) ip = walk->compileStmt(codeStream, ip); return codeStream.tell(); } - - inline bool isSimpleVarLookup(ExprNode *arrayExpr, StringTableEntry &varName) - { - if (arrayExpr == nullptr) - { - varName = StringTable->insert(""); - return false; - } - - // No double arrays allowed for optimization. - VarNode *var = dynamic_cast(arrayExpr); - if (var && !var->arrayIndex) - { - StringTableEntry arrayVar = StringTable->insert(var->varName); - precompileIdent(arrayVar); - varName = arrayVar; - return true; - } - return false; - } - - // Do not allow 'recursive' %this optimizations. It can lead to weird bytecode - // generation since we can only optimize one expression at a time. - static bool OnlyOneThisOptimization = false; - - inline bool isThisVar(ExprNode *objectExpr) - { - // If we are currently optimizing a this var, don't allow extra optimization. - if (objectExpr == nullptr || OnlyOneThisOptimization) - return false; - - VarNode *thisVar = dynamic_cast(objectExpr); - if (thisVar && thisVar->varName == StringTable->insert("%this")) - return true; - return false; - } - - inline void optimizeThisPointer(CodeStream &codeStream, ExprNode *arrayExpr, U32 &ip, StringTableEntry slotName) - { - OnlyOneThisOptimization = true; - - // Is the array a simple variable? If so, we can optimize that. - StringTableEntry varName = nullptr; - bool simple = false; - - if (arrayExpr) - { - simple = isSimpleVarLookup(arrayExpr, varName); - if (!simple) - { - // Less optimized array setting. - codeStream.emit(OP_ADVANCE_STR); - ip = arrayExpr->compile(codeStream, ip, TypeReqString); - } - } - - codeStream.emit(OP_SETCURFIELD_THIS); - codeStream.emitSTE(slotName); - - if (arrayExpr) - { - if (simple) - { - codeStream.emit(OP_SETCURFIELD_ARRAY_VAR); - codeStream.emitSTE(varName); - } - else - { - codeStream.emit(OP_SETCURFIELD_ARRAY); - codeStream.emit(OP_TERMINATE_REWIND_STR); - } - } - - OnlyOneThisOptimization = false; - } } using namespace Compiler; +class FuncVars +{ + struct Var + { + S32 reg; + TypeReq currentType; + bool isConstant; + }; + +public: + S32 assign(StringTableEntry var, TypeReq currentType, bool isConstant = false) + { + std::unordered_map::iterator found = vars.find(var); + if (found != vars.end()) + { + AssertISV(!found->second.isConstant, avar("Reassigning variable %s when it is a constant", var)); + return found->second.reg; + } + + S32 id = counter++; + vars[var] = { id, currentType, isConstant }; + return id; + } + + S32 lookup(StringTableEntry var) + { + std::unordered_map::iterator found = vars.find(var); + AssertISV(found != vars.end(), avar("Variable %s referenced before used when compiling script.", var)); + return found->second.reg; + } + + TypeReq lookupType(StringTableEntry var) + { + std::unordered_map::iterator found = vars.find(var); + AssertISV(found != vars.end(), avar("Variable %s referenced before used when compiling script.", var)); + return found->second.currentType; + } + + inline S32 count() { return counter; } + +private: + std::unordered_map vars; + S32 counter = 0; +}; + +FuncVars* gFuncVars = NULL; + //----------------------------------------------------------------------------- -void StmtNode::addBreakLine(CodeStream &code) +void StmtNode::addBreakLine(CodeStream& code) { code.addBreakLine(dbgLineNumber, code.tell()); } @@ -140,21 +112,20 @@ void StmtNode::addBreakLine(CodeStream &code) StmtNode::StmtNode() { - mNext = NULL; + next = NULL; dbgFileName = CodeBlock::smCurrentParser->getCurrentFile(); - dbgLineNumber = 0; } void StmtNode::setPackage(StringTableEntry) { } -void StmtNode::append(StmtNode *next) +void StmtNode::append(StmtNode* next) { - StmtNode *walk = this; - while (walk->mNext) - walk = walk->mNext; - walk->mNext = next; + StmtNode* walk = this; + while (walk->next) + walk = walk->next; + walk->next = next; } @@ -175,64 +146,42 @@ static U32 conversionOp(TypeReq src, TypeReq dst) { switch (dst) { - case TypeReqUInt: - return OP_STR_TO_UINT; - case TypeReqFloat: - return OP_STR_TO_FLT; - case TypeReqNone: - return OP_STR_TO_NONE; - case TypeReqVar: - return OP_SAVEVAR_STR; - default: - break; + case TypeReqUInt: + return OP_STR_TO_UINT; + case TypeReqFloat: + return OP_STR_TO_FLT; + case TypeReqNone: + return OP_STR_TO_NONE; + default: + break; } } else if (src == TypeReqFloat) { switch (dst) { - case TypeReqUInt: - return OP_FLT_TO_UINT; - case TypeReqString: - return OP_FLT_TO_STR; - case TypeReqNone: - return OP_FLT_TO_NONE; - case TypeReqVar: - return OP_SAVEVAR_FLT; - default: - break; + case TypeReqUInt: + return OP_FLT_TO_UINT; + case TypeReqString: + return OP_FLT_TO_STR; + case TypeReqNone: + return OP_FLT_TO_NONE; + default: + break; } } else if (src == TypeReqUInt) { switch (dst) { - case TypeReqFloat: - return OP_UINT_TO_FLT; - case TypeReqString: - return OP_UINT_TO_STR; - case TypeReqNone: - return OP_UINT_TO_NONE; - case TypeReqVar: - return OP_SAVEVAR_UINT; - default: - break; - } - } - else if (src == TypeReqVar) - { - switch (dst) - { - case TypeReqUInt: - return OP_LOADVAR_UINT; - case TypeReqFloat: - return OP_LOADVAR_FLT; - case TypeReqString: - return OP_LOADVAR_STR; - case TypeReqNone: - return OP_COPYVAR_TO_NONE; - default: - break; + case TypeReqFloat: + return OP_UINT_TO_FLT; + case TypeReqString: + return OP_UINT_TO_STR; + case TypeReqNone: + return OP_UINT_TO_NONE; + default: + break; } } return OP_INVALID; @@ -240,7 +189,7 @@ static U32 conversionOp(TypeReq src, TypeReq dst) //------------------------------------------------------------ -U32 BreakStmtNode::compileStmt(CodeStream &codeStream, U32 ip) +U32 BreakStmtNode::compileStmt(CodeStream& codeStream, U32 ip) { if (codeStream.inLoop()) { @@ -257,7 +206,7 @@ U32 BreakStmtNode::compileStmt(CodeStream &codeStream, U32 ip) //------------------------------------------------------------ -U32 ContinueStmtNode::compileStmt(CodeStream &codeStream, U32 ip) +U32 ContinueStmtNode::compileStmt(CodeStream& codeStream, U32 ip) { if (codeStream.inLoop()) { @@ -274,7 +223,7 @@ U32 ContinueStmtNode::compileStmt(CodeStream &codeStream, U32 ip) //------------------------------------------------------------ -U32 ExprNode::compileStmt(CodeStream &codeStream, U32 ip) +U32 ExprNode::compileStmt(CodeStream& codeStream, U32 ip) { addBreakLine(codeStream); return compile(codeStream, ip, TypeReqNone); @@ -282,7 +231,7 @@ U32 ExprNode::compileStmt(CodeStream &codeStream, U32 ip) //------------------------------------------------------------ -U32 ReturnStmtNode::compileStmt(CodeStream &codeStream, U32 ip) +U32 ReturnStmtNode::compileStmt(CodeStream& codeStream, U32 ip) { addBreakLine(codeStream); if (!expr) @@ -295,15 +244,15 @@ U32 ReturnStmtNode::compileStmt(CodeStream &codeStream, U32 ip) // Return the correct type switch (walkType) { - case TypeReqUInt: - codeStream.emit(OP_RETURN_UINT); - break; - case TypeReqFloat: - codeStream.emit(OP_RETURN_FLT); - break; - default: - codeStream.emit(OP_RETURN); - break; + case TypeReqUInt: + codeStream.emit(OP_RETURN_UINT); + break; + case TypeReqFloat: + codeStream.emit(OP_RETURN_FLT); + break; + default: + codeStream.emit(OP_RETURN); + break; } } return codeStream.tell(); @@ -311,10 +260,10 @@ U32 ReturnStmtNode::compileStmt(CodeStream &codeStream, U32 ip) //------------------------------------------------------------ -ExprNode *IfStmtNode::getSwitchOR(ExprNode *left, ExprNode *list, bool string) +ExprNode* IfStmtNode::getSwitchOR(ExprNode* left, ExprNode* list, bool string) { - ExprNode *nextExpr = (ExprNode *)list->getNext(); - ExprNode *test; + ExprNode* nextExpr = (ExprNode*)list->getNext(); + ExprNode* test; if (string) test = StreqExprNode::alloc(left->dbgLineNumber, left, list, true); else @@ -324,14 +273,14 @@ ExprNode *IfStmtNode::getSwitchOR(ExprNode *left, ExprNode *list, bool string) return IntBinaryExprNode::alloc(test->dbgLineNumber, opOR, test, getSwitchOR(left, nextExpr, string)); } -void IfStmtNode::propagateSwitchExpr(ExprNode *left, bool string) +void IfStmtNode::propagateSwitchExpr(ExprNode* left, bool string) { testExpr = getSwitchOR(left, testExpr, string); if (propagate && elseBlock) - ((IfStmtNode *)elseBlock)->propagateSwitchExpr(left, string); + ((IfStmtNode*)elseBlock)->propagateSwitchExpr(left, string); } -U32 IfStmtNode::compileStmt(CodeStream &codeStream, U32 ip) +U32 IfStmtNode::compileStmt(CodeStream& codeStream, U32 ip) { U32 endifIp, elseIp; addBreakLine(codeStream); @@ -373,7 +322,7 @@ U32 IfStmtNode::compileStmt(CodeStream &codeStream, U32 ip) //------------------------------------------------------------ -U32 LoopStmtNode::compileStmt(CodeStream &codeStream, U32 ip) +U32 LoopStmtNode::compileStmt(CodeStream& codeStream, U32 ip) { if (testExpr->getPreferredType() == TypeReqUInt) { @@ -446,7 +395,7 @@ U32 LoopStmtNode::compileStmt(CodeStream &codeStream, U32 ip) //------------------------------------------------------------ -U32 IterStmtNode::compileStmt(CodeStream &codeStream, U32 ip) +U32 IterStmtNode::compileStmt(CodeStream& codeStream, U32 ip) { // Instruction sequence: // @@ -491,7 +440,7 @@ U32 IterStmtNode::compileStmt(CodeStream &codeStream, U32 ip) //------------------------------------------------------------ -U32 ConditionalExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) +U32 ConditionalExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type) { // code is testExpr // JMPIFNOT falseStart @@ -528,25 +477,31 @@ TypeReq ConditionalExprNode::getPreferredType() //------------------------------------------------------------ -U32 FloatBinaryExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) +U32 FloatBinaryExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type) { + if (optimize()) + { + ip = optimizedNode->compile(codeStream, ip, type); + return codeStream.tell(); + } + ip = right->compile(codeStream, ip, TypeReqFloat); ip = left->compile(codeStream, ip, TypeReqFloat); U32 operand = OP_INVALID; switch (op) { - case '+': - operand = OP_ADD; - break; - case '-': - operand = OP_SUB; - break; - case '/': - operand = OP_DIV; - break; - case '*': - operand = OP_MUL; - break; + case '+': + operand = OP_ADD; + break; + case '-': + operand = OP_SUB; + break; + case '/': + operand = OP_DIV; + break; + case '*': + operand = OP_MUL; + break; } codeStream.emit(operand); if (type != TypeReqFloat) @@ -566,59 +521,64 @@ void IntBinaryExprNode::getSubTypeOperand() subType = TypeReqUInt; switch (op) { - case '^': - operand = OP_XOR; - break; - case '%': - operand = OP_MOD; - break; - case '&': - operand = OP_BITAND; - break; - case '|': - operand = OP_BITOR; - break; - case '<': - operand = OP_CMPLT; - subType = TypeReqFloat; - break; - case '>': - operand = OP_CMPGR; - subType = TypeReqFloat; - break; - case opGE: - operand = OP_CMPGE; - subType = TypeReqFloat; - break; - case opLE: - operand = OP_CMPLE; - subType = TypeReqFloat; - break; - case opEQ: - operand = OP_CMPEQ; - subType = TypeReqFloat; - break; - case opNE: - operand = OP_CMPNE; - subType = TypeReqFloat; - break; - case opOR: - operand = OP_OR; - break; - case opAND: - operand = OP_AND; - break; - case opSHR: - operand = OP_SHR; - break; - case opSHL: - operand = OP_SHL; - break; + case '^': + operand = OP_XOR; + break; + case '%': + operand = OP_MOD; + break; + case '&': + operand = OP_BITAND; + break; + case '|': + operand = OP_BITOR; + break; + case '<': + operand = OP_CMPLT; + subType = TypeReqFloat; + break; + case '>': + operand = OP_CMPGR; + subType = TypeReqFloat; + break; + case opGE: + operand = OP_CMPGE; + subType = TypeReqFloat; + break; + case opLE: + operand = OP_CMPLE; + subType = TypeReqFloat; + break; + case opEQ: + operand = OP_CMPEQ; + subType = TypeReqFloat; + break; + case opNE: + operand = OP_CMPNE; + subType = TypeReqFloat; + break; + case opOR: + operand = OP_OR; + break; + case opAND: + operand = OP_AND; + break; + case opSHR: + operand = OP_SHR; + break; + case opSHL: + operand = OP_SHL; + break; } } -U32 IntBinaryExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) +U32 IntBinaryExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type) { + // TODO: What if we do other optimizations and this doesn't work for it..this + // so far only works for simple MOD optimizations... + if (optimize()) + right = optimizedNode; + getSubTypeOperand(); if (operand == OP_OR || operand == OP_AND) @@ -647,7 +607,7 @@ TypeReq IntBinaryExprNode::getPreferredType() //------------------------------------------------------------ -U32 StreqExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) +U32 StreqExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type) { // eval str left // OP_ADVANCE_STR_NUL @@ -673,7 +633,7 @@ TypeReq StreqExprNode::getPreferredType() //------------------------------------------------------------ -U32 StrcatExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) +U32 StrcatExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type) { ip = left->compile(codeStream, ip, TypeReqString); if (!appendChar) @@ -699,7 +659,7 @@ TypeReq StrcatExprNode::getPreferredType() //------------------------------------------------------------ -U32 CommaCatExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) +U32 CommaCatExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type) { ip = left->compile(codeStream, ip, TypeReqString); codeStream.emit(OP_ADVANCE_STR_COMMA); @@ -725,7 +685,7 @@ TypeReq CommaCatExprNode::getPreferredType() //------------------------------------------------------------ -U32 IntUnaryExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) +U32 IntUnaryExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type) { integer = true; TypeReq prefType = expr->getPreferredType(); @@ -749,7 +709,7 @@ TypeReq IntUnaryExprNode::getPreferredType() //------------------------------------------------------------ -U32 FloatUnaryExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) +U32 FloatUnaryExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type) { ip = expr->compile(codeStream, ip, TypeReqFloat); codeStream.emit(OP_NEG); @@ -765,22 +725,16 @@ TypeReq FloatUnaryExprNode::getPreferredType() //------------------------------------------------------------ -U32 VarNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) +U32 VarNode::compile(CodeStream& codeStream, U32 ip, TypeReq type) { - // if this has an arrayIndex and we are not short circuiting from a constant. - // if we are a var node - // OP_SETCURVAR_ARRAY_VARLOOKUP - // varName - // varNodeVarName - - // else - // OP_LOADIMMED_IDENT - // varName - // OP_ADVANCE_STR - // evaluate arrayIndex TypeReqString - // OP_REWIND_STR - // OP_SETCURVAR_ARRAY - // OP_LOADVAR (type) + // if this has an arrayIndex... + // OP_LOADIMMED_IDENT + // varName + // OP_ADVANCE_STR + // evaluate arrayIndex TypeReqString + // OP_REWIND_STR + // OP_SETCURVAR_ARRAY + // OP_LOADVAR (type) // else // OP_SETCURVAR @@ -790,56 +744,24 @@ U32 VarNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) if (type == TypeReqNone) return codeStream.tell(); - bool shortCircuit = false; - if (arrayIndex) - { - // If we have a constant, shortcircuit the array logic. - - IntNode *intNode = dynamic_cast(arrayIndex); - StrConstNode *strNode = dynamic_cast(arrayIndex); - if (intNode) - { - varName = StringTable->insert(avar("%s%d", varName, intNode->value)); - shortCircuit = true; - } - else if (strNode) - { - varName = StringTable->insert(avar("%s%s", varName, strNode->str)); - shortCircuit = true; - } - } - precompileIdent(varName); - if (arrayIndex && !shortCircuit) + bool oldVariables = arrayIndex || varName[0] == '$'; + + if (oldVariables) { - // Ok, lets try to optimize %var[%someothervar] as this is - // a common case for array usage. - StringTableEntry varNodeVarName; - if (isSimpleVarLookup(arrayIndex, varNodeVarName)) + codeStream.emit(arrayIndex ? OP_LOADIMMED_IDENT : OP_SETCURVAR); + codeStream.emitSTE(varName); + + if (arrayIndex) { - codeStream.emit(OP_SETCURVAR_ARRAY_VARLOOKUP); - codeStream.emitSTE(varName); - codeStream.emitSTE(varNodeVarName); - } - else - { - codeStream.emit(OP_LOADIMMED_IDENT); - codeStream.emitSTE(varName); codeStream.emit(OP_ADVANCE_STR); ip = arrayIndex->compile(codeStream, ip, TypeReqString); codeStream.emit(OP_REWIND_STR); codeStream.emit(OP_SETCURVAR_ARRAY); } - } - else - { - codeStream.emit(OP_SETCURVAR); - codeStream.emitSTE(varName); - } - - switch (type) - { + switch (type) + { case TypeReqUInt: codeStream.emit(OP_LOADVAR_UINT); break; @@ -849,25 +771,36 @@ U32 VarNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) case TypeReqString: codeStream.emit(OP_LOADVAR_STR); break; - case TypeReqVar: - codeStream.emit(OP_LOADVAR_VAR); - break; case TypeReqNone: break; default: break; + } } + else + { + switch (type) + { + case TypeReqUInt: codeStream.emit(OP_LOAD_LOCAL_VAR_UINT); break; + case TypeReqFloat: codeStream.emit(OP_LOAD_LOCAL_VAR_FLT); break; + default: codeStream.emit(OP_LOAD_LOCAL_VAR_STR); + } + + codeStream.emit(gFuncVars->lookup(varName)); + } + return codeStream.tell(); } TypeReq VarNode::getPreferredType() { - return TypeReqNone; // no preferred type + bool oldVariables = arrayIndex || varName[0] == '$'; + return oldVariables ? TypeReqNone : gFuncVars->lookupType(varName); } //------------------------------------------------------------ -U32 IntNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) +U32 IntNode::compile(CodeStream& codeStream, U32 ip, TypeReq type) { if (type == TypeReqString) index = getCurrentStringTable()->addIntString(value); @@ -876,20 +809,20 @@ U32 IntNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) switch (type) { - case TypeReqUInt: - codeStream.emit(OP_LOADIMMED_UINT); - codeStream.emit(value); - break; - case TypeReqString: - codeStream.emit(OP_LOADIMMED_STR); - codeStream.emit(index); - break; - case TypeReqFloat: - codeStream.emit(OP_LOADIMMED_FLT); - codeStream.emit(index); - break; - case TypeReqNone: - break; + case TypeReqUInt: + codeStream.emit(OP_LOADIMMED_UINT); + codeStream.emit(value); + break; + case TypeReqString: + codeStream.emit(OP_LOADIMMED_STR); + codeStream.emit(index); + break; + case TypeReqFloat: + codeStream.emit(OP_LOADIMMED_FLT); + codeStream.emit(index); + break; + case TypeReqNone: + break; } return codeStream.tell(); } @@ -901,7 +834,7 @@ TypeReq IntNode::getPreferredType() //------------------------------------------------------------ -U32 FloatNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) +U32 FloatNode::compile(CodeStream& codeStream, U32 ip, TypeReq type) { if (type == TypeReqString) index = getCurrentStringTable()->addFloatString(value); @@ -910,20 +843,20 @@ U32 FloatNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) switch (type) { - case TypeReqUInt: - codeStream.emit(OP_LOADIMMED_UINT); - codeStream.emit(U32(value)); - break; - case TypeReqString: - codeStream.emit(OP_LOADIMMED_STR); - codeStream.emit(index); - break; - case TypeReqFloat: - codeStream.emit(OP_LOADIMMED_FLT); - codeStream.emit(index); - break; - case TypeReqNone: - break; + case TypeReqUInt: + codeStream.emit(OP_LOADIMMED_UINT); + codeStream.emit(U32(value)); + break; + case TypeReqString: + codeStream.emit(OP_LOADIMMED_STR); + codeStream.emit(index); + break; + case TypeReqFloat: + codeStream.emit(OP_LOADIMMED_FLT); + codeStream.emit(index); + break; + case TypeReqNone: + break; } return codeStream.tell(); } @@ -935,7 +868,7 @@ TypeReq FloatNode::getPreferredType() //------------------------------------------------------------ -U32 StrConstNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) +U32 StrConstNode::compile(CodeStream& codeStream, U32 ip, TypeReq type) { // Early out for documentation block. if (doc) @@ -966,20 +899,20 @@ U32 StrConstNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) // Otherwise, deal with it normally as a string literal case. switch (type) { - case TypeReqString: - codeStream.emit(tag ? OP_TAG_TO_STR : OP_LOADIMMED_STR); - codeStream.emit(index); - break; - case TypeReqUInt: - codeStream.emit(OP_LOADIMMED_UINT); - codeStream.emit(U32(fVal)); - break; - case TypeReqFloat: - codeStream.emit(OP_LOADIMMED_FLT); - codeStream.emit(index); - break; - case TypeReqNone: - break; + case TypeReqString: + codeStream.emit(tag ? OP_TAG_TO_STR : OP_LOADIMMED_STR); + codeStream.emit(index); + break; + case TypeReqUInt: + codeStream.emit(OP_LOADIMMED_UINT); + codeStream.emit(U32(fVal)); + break; + case TypeReqFloat: + codeStream.emit(OP_LOADIMMED_FLT); + codeStream.emit(index); + break; + case TypeReqNone: + break; } return codeStream.tell(); } @@ -991,7 +924,7 @@ TypeReq StrConstNode::getPreferredType() //------------------------------------------------------------ -U32 ConstantNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) +U32 ConstantNode::compile(CodeStream& codeStream, U32 ip, TypeReq type) { if (type == TypeReqString) { @@ -1006,20 +939,20 @@ U32 ConstantNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) switch (type) { - case TypeReqString: - codeStream.emit(OP_LOADIMMED_IDENT); - codeStream.emitSTE(value); - break; - case TypeReqUInt: - codeStream.emit(OP_LOADIMMED_UINT); - codeStream.emit(U32(fVal)); - break; - case TypeReqFloat: - codeStream.emit(OP_LOADIMMED_FLT); - codeStream.emit(index); - break; - case TypeReqNone: - break; + case TypeReqString: + codeStream.emit(OP_LOADIMMED_IDENT); + codeStream.emitSTE(value); + break; + case TypeReqUInt: + codeStream.emit(OP_LOADIMMED_UINT); + codeStream.emit(U32(fVal)); + break; + case TypeReqFloat: + codeStream.emit(OP_LOADIMMED_FLT); + codeStream.emit(index); + break; + case TypeReqNone: + break; } return ip; } @@ -1031,49 +964,23 @@ TypeReq ConstantNode::getPreferredType() //------------------------------------------------------------ -U32 AssignExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) +U32 AssignExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type) { subType = expr->getPreferredType(); if (subType == TypeReqNone) subType = type; if (subType == TypeReqNone) - { - // What we need to do in this case is turn it into a VarNode reference. - // Unfortunately other nodes such as field access (SlotAccessNode) - // cannot be optimized in the same manner as all fields are exposed - // and set as strings. - if (dynamic_cast(expr) != NULL) - { - subType = TypeReqVar; - } - else - { - subType = TypeReqString; - } - } + subType = TypeReqString; - //if we are an array index and we are gonna short circuit - // eval expr - // compute new varName - // OP_SETCURVAR_CREATE - // varName - // OP_SAVEVAR - - //else if it's an array expr and we don't short circuit, the formula is: + // if it's an array expr, the formula is: // eval expr // (push and pop if it's TypeReqString) OP_ADVANCE_STR - // if array lookup is varnode - // OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP - // varName - // varNodeVarName - // else - // OP_LOADIMMED_IDENT - // varName - // OP_ADVANCE_STR - // eval array - // OP_REWIND_STR - // OP_SETCURVAR_ARRAY_CREATE - // endif + // OP_LOADIMMED_IDENT + // varName + // OP_ADVANCE_STR + // eval array + // OP_REWIND_STR + // OP_SETCURVAR_ARRAY_CREATE // OP_TERMINATE_REWIND_STR // OP_SAVEVAR @@ -1083,45 +990,19 @@ U32 AssignExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) // varname // OP_SAVEVAR - ip = expr->compile(codeStream, ip, subType); - - bool shortCircuit = false; - if (arrayIndex) - { - // If we have a constant, shortcircuit the array logic. - - IntNode *intNode = dynamic_cast(arrayIndex); - StrConstNode *strNode = dynamic_cast(arrayIndex); - if (intNode) - { - varName = StringTable->insert(avar("%s%d", varName, intNode->value)); - shortCircuit = true; - } - else if (strNode) - { - varName = StringTable->insert(avar("%s%s", varName, strNode->str)); - shortCircuit = true; - } - } - precompileIdent(varName); - if (arrayIndex && !shortCircuit) - { - if (subType == TypeReqString) - codeStream.emit(OP_ADVANCE_STR); + ip = expr->compile(codeStream, ip, subType); - // Ok, lets try to optimize %var[%someothervar] as this is - // a common case for array usage. - StringTableEntry varNodeVarName; - if (isSimpleVarLookup(arrayIndex, varNodeVarName)) - { - codeStream.emit(OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP); - codeStream.emitSTE(varName); - codeStream.emitSTE(varNodeVarName); - } - else + bool oldVariables = arrayIndex || varName[0] == '$'; + + if (oldVariables) + { + if (arrayIndex) { + if (subType == TypeReqString) + codeStream.emit(OP_ADVANCE_STR); + codeStream.emit(OP_LOADIMMED_IDENT); codeStream.emitSTE(varName); @@ -1129,35 +1010,37 @@ U32 AssignExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) ip = arrayIndex->compile(codeStream, ip, TypeReqString); codeStream.emit(OP_REWIND_STR); codeStream.emit(OP_SETCURVAR_ARRAY_CREATE); + if (subType == TypeReqString) + codeStream.emit(OP_TERMINATE_REWIND_STR); + } + else + { + codeStream.emit(OP_SETCURVAR_CREATE); + codeStream.emitSTE(varName); + } + switch (subType) + { + case TypeReqString: codeStream.emit(OP_SAVEVAR_STR); break; + case TypeReqUInt: codeStream.emit(OP_SAVEVAR_UINT); break; + case TypeReqFloat: codeStream.emit(OP_SAVEVAR_FLT); break; } - - if (subType == TypeReqString) - codeStream.emit(OP_TERMINATE_REWIND_STR); } else { - codeStream.emit(OP_SETCURVAR_CREATE); - codeStream.emitSTE(varName); - } - switch (subType) - { - case TypeReqString: - codeStream.emit(OP_SAVEVAR_STR); - break; - case TypeReqUInt: - codeStream.emit(OP_SAVEVAR_UINT); - break; - case TypeReqFloat: - codeStream.emit(OP_SAVEVAR_FLT); - break; - case TypeReqVar: - codeStream.emit(OP_SAVEVAR_VAR); - break; - case TypeReqNone: - break; + switch (subType) + { + case TypeReqUInt: codeStream.emit(OP_SAVE_LOCAL_VAR_UINT); break; + case TypeReqFloat: codeStream.emit(OP_SAVE_LOCAL_VAR_FLT); break; + default: codeStream.emit(OP_SAVE_LOCAL_VAR_STR); + } + codeStream.emit(gFuncVars->assign(varName, subType == TypeReqNone ? TypeReqString : subType)); } + if (type != subType) - codeStream.emit(conversionOp(subType, type)); + { + U32 conOp = conversionOp(subType, type); + codeStream.emit(conOp); + } return ip; } @@ -1168,163 +1051,99 @@ TypeReq AssignExprNode::getPreferredType() //------------------------------------------------------------ -static void getAssignOpTypeOp(S32 op, TypeReq &type, U32 &operand) +static void getAssignOpTypeOp(S32 op, TypeReq& type, U32& operand) { switch (op) { - case '+': - case opPLUSPLUS: - type = TypeReqFloat; - operand = OP_ADD; - break; - case '-': - case opMINUSMINUS: - type = TypeReqFloat; - operand = OP_SUB; - break; - case '*': - type = TypeReqFloat; - operand = OP_MUL; - break; - case '/': - type = TypeReqFloat; - operand = OP_DIV; - break; - case '%': - type = TypeReqUInt; - operand = OP_MOD; - break; - case '&': - type = TypeReqUInt; - operand = OP_BITAND; - break; - case '^': - type = TypeReqUInt; - operand = OP_XOR; - break; - case '|': - type = TypeReqUInt; - operand = OP_BITOR; - break; - case opSHL: - type = TypeReqUInt; - operand = OP_SHL; - break; - case opSHR: - type = TypeReqUInt; - operand = OP_SHR; - break; + case '+': + case opPLUSPLUS: + type = TypeReqFloat; + operand = OP_ADD; + break; + case '-': + type = TypeReqFloat; + operand = OP_SUB; + break; + case '*': + type = TypeReqFloat; + operand = OP_MUL; + break; + case '/': + type = TypeReqFloat; + operand = OP_DIV; + break; + case '%': + type = TypeReqUInt; + operand = OP_MOD; + break; + case '&': + type = TypeReqUInt; + operand = OP_BITAND; + break; + case '^': + type = TypeReqUInt; + operand = OP_XOR; + break; + case '|': + type = TypeReqUInt; + operand = OP_BITOR; + break; + case opSHL: + type = TypeReqUInt; + operand = OP_SHL; + break; + case opSHR: + type = TypeReqUInt; + operand = OP_SHR; + break; } } -U32 AssignOpExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) +U32 AssignOpExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type) { // goes like this... - // - // IF no array index && (op == OPPLUSPLUS or op == OPMINUSMINUS) - // if op == OPPLUSPLUS - // OP_INC - // varName - // else if op == OPMINUSMINUS - // OP_DEC - // varName - // else - // OP_INVALID - // endif - // ELSE - // eval expr as float or int - // if there's an arrayIndex and we don't short circuit - // if arrayIndex is a var node - // OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP - // varName - // varNodeVarName - // else - // OP_LOADIMMED_IDENT - // varName - // OP_ADVANCE_STR - // eval arrayIndex stringwise - // OP_REWIND_STR - // OP_SETCURVAR_ARRAY_CREATE - // endif - // else - // OP_SETCURVAR_CREATE - // varName - // endif - // OP_LOADVAR_FLT or UINT - // operand - // OP_SAVEVAR_FLT or UINT - // ENDIF - // - // if subtype != type - // convert type - // endif + // eval expr as float or int + // if there's an arrayIndex + + // OP_LOADIMMED_IDENT + // varName + // OP_ADVANCE_STR + // eval arrayIndex stringwise + // OP_REWIND_STR + // OP_SETCURVAR_ARRAY_CREATE + + // else + // OP_SETCURVAR_CREATE + // varName + + // OP_LOADVAR_FLT or UINT + // operand + // OP_SAVEVAR_FLT or UINT // conversion OP if necessary. getAssignOpTypeOp(op, subType, operand); + precompileIdent(varName); - // ++ or -- optimization support for non indexed variables. - if ((!arrayIndex) && (op == opPLUSPLUS || op == opMINUSMINUS)) + bool oldVariables = arrayIndex || varName[0] == '$'; + + if (op == opPLUSPLUS && !oldVariables) { - precompileIdent(varName); + const S32 varIdx = gFuncVars->assign(varName, TypeReqFloat); - if (op == opPLUSPLUS) - { - codeStream.emit(OP_INC); - codeStream.emitSTE(varName); - } - else if (op == opMINUSMINUS) - { - codeStream.emit(OP_DEC); - codeStream.emitSTE(varName); - } - else - { - // This should NEVER happen. This is just for sanity. - AssertISV(false, "Tried to use ++ or -- but something weird happened."); - codeStream.emit(OP_INVALID); - } + codeStream.emit(OP_INC); + codeStream.emit(varIdx); } else { ip = expr->compile(codeStream, ip, subType); - bool shortCircuit = false; - if (arrayIndex) + if (oldVariables) { - // If we have a constant, shortcircuit the array logic. - - IntNode *intNode = dynamic_cast(arrayIndex); - StrConstNode *strNode = dynamic_cast(arrayIndex); - if (intNode) + if (!arrayIndex) { - varName = StringTable->insert(avar("%s%d", varName, intNode->value)); - shortCircuit = true; - } - else if (strNode) - { - varName = StringTable->insert(avar("%s%s", varName, strNode->str)); - shortCircuit = true; - } - } - - precompileIdent(varName); - - if (!arrayIndex || shortCircuit) - { - codeStream.emit(OP_SETCURVAR_CREATE); - codeStream.emitSTE(varName); - } - else - { - // Ok, lets try to optimize %var[%someothervar] as this is - // a common case for array usage. - StringTableEntry varNodeVarName; - if (isSimpleVarLookup(arrayIndex, varNodeVarName)) - { - codeStream.emit(OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP); + codeStream.emit(OP_SETCURVAR_CREATE); codeStream.emitSTE(varName); - codeStream.emitSTE(varNodeVarName); } else { @@ -1336,13 +1155,27 @@ U32 AssignOpExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) codeStream.emit(OP_REWIND_STR); codeStream.emit(OP_SETCURVAR_ARRAY_CREATE); } + codeStream.emit((subType == TypeReqFloat) ? OP_LOADVAR_FLT : OP_LOADVAR_UINT); + codeStream.emit(operand); + codeStream.emit((subType == TypeReqFloat) ? OP_SAVEVAR_FLT : OP_SAVEVAR_UINT); + } + else + { + const bool isFloat = subType == TypeReqFloat; + const S32 varIdx = gFuncVars->assign(varName, subType == TypeReqNone ? TypeReqString : subType); + + codeStream.emit(isFloat ? OP_LOAD_LOCAL_VAR_FLT : OP_LOAD_LOCAL_VAR_UINT); + codeStream.emit(varIdx); + codeStream.emit(operand); + codeStream.emit(isFloat ? OP_SAVE_LOCAL_VAR_FLT : OP_SAVE_LOCAL_VAR_UINT); + codeStream.emit(varIdx); + } + + if (subType != type) + { + codeStream.emit(conversionOp(subType, type)); } - codeStream.emit((subType == TypeReqFloat) ? OP_LOADVAR_FLT : OP_LOADVAR_UINT); - codeStream.emit(operand); - codeStream.emit((subType == TypeReqFloat) ? OP_SAVEVAR_FLT : OP_SAVEVAR_UINT); } - if (subType != type) - codeStream.emit(conversionOp(subType, type)); return codeStream.tell(); } @@ -1385,7 +1218,7 @@ TypeReq TTagExprNode::getPreferredType() //------------------------------------------------------------ -U32 FuncCallExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) +U32 FuncCallExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type) { // OP_PUSH_FRAME // arg OP_PUSH arg OP_PUSH arg OP_PUSH @@ -1399,69 +1232,38 @@ U32 FuncCallExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) precompileIdent(funcName); precompileIdent(nameSpace); + S32 count = 0; + for (ExprNode* walk = args; walk; walk = static_cast(walk->getNext())) + count++; + codeStream.emit(OP_PUSH_FRAME); + codeStream.emit(count); - bool isThisCall = false; - - ExprNode *walk = args; - - // Try to optimize the this pointer call if it is a variable - // that we are loading. - if (callType == MethodCall) - { - // We cannot optimize array indices because it can have quite - // a bit of code to figure out the array index. - VarNode *var = dynamic_cast(args); - if (var && !var->arrayIndex) - { - precompileIdent(var->varName); - - // Are we a %this call? - isThisCall = (var->varName == StringTable->insert("%this")); - - codeStream.emit(OP_PUSH_THIS); - codeStream.emitSTE(var->varName); - - // inc args since we took care of first arg. - walk = (ExprNode*)walk ->getNext(); - } - } - - for (; walk; walk = (ExprNode *)walk->getNext()) + for (ExprNode* walk = args; walk; walk = static_cast(walk->getNext())) { TypeReq walkType = walk->getPreferredType(); - if (walkType == TypeReqNone) walkType = TypeReqString; + if (walkType == TypeReqNone) + walkType = TypeReqString; + ip = walk->compile(codeStream, ip, walkType); switch (walk->getPreferredType()) { - case TypeReqFloat: - codeStream.emit(OP_PUSH_FLT); - break; - case TypeReqUInt: - codeStream.emit(OP_PUSH_UINT); - break; - default: - codeStream.emit(OP_PUSH); - break; + case TypeReqFloat: + codeStream.emit(OP_PUSH_FLT); + break; + case TypeReqUInt: + codeStream.emit(OP_PUSH_UINT); + break; + default: + codeStream.emit(OP_PUSH); + break; } } - if (isThisCall) - { - codeStream.emit(OP_CALLFUNC_THIS); - codeStream.emitSTE(funcName); - } - else - { - if (callType == MethodCall || callType == ParentCall) - codeStream.emit(OP_CALLFUNC); - else - codeStream.emit(OP_CALLFUNC_RESOLVE); - - codeStream.emitSTE(funcName); - codeStream.emitSTE(nameSpace); - codeStream.emit(callType); - } + codeStream.emit(OP_CALLFUNC); + codeStream.emitSTE(funcName); + codeStream.emitSTE(nameSpace); + codeStream.emit(callType); if (type != TypeReqString) codeStream.emit(conversionOp(TypeReqString, type)); @@ -1473,53 +1275,10 @@ TypeReq FuncCallExprNode::getPreferredType() return TypeReqString; } -//------------------------------------------------------------ - -U32 FuncPointerCallExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) -{ - // OP_PUSH_FRAME - // arg OP_PUSH arg OP_PUSH arg OP_PUSH - // eval all the args, then call the function. - - // eval fn pointer - // OP_CALLFUNC_POINTER - - codeStream.emit(OP_PUSH_FRAME); - for (ExprNode *walk = args; walk; walk = (ExprNode *)walk->getNext()) - { - TypeReq walkType = walk->getPreferredType(); - if (walkType == TypeReqNone) walkType = TypeReqString; - ip = walk->compile(codeStream, ip, walkType); - switch (walk->getPreferredType()) - { - case TypeReqFloat: - codeStream.emit(OP_PUSH_FLT); - break; - case TypeReqUInt: - codeStream.emit(OP_PUSH_UINT); - break; - default: - codeStream.emit(OP_PUSH); - break; - } - } - - ip = funcPointer->compile(codeStream, ip, TypeReqString); - codeStream.emit(OP_CALLFUNC_POINTER); - - if (type != TypeReqString) - codeStream.emit(conversionOp(TypeReqString, type)); - return codeStream.tell(); -} - -TypeReq FuncPointerCallExprNode::getPreferredType() -{ - return TypeReqString; -} //------------------------------------------------------------ -U32 AssertCallExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) +U32 AssertCallExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type) { #ifdef TORQUE_ENABLE_SCRIPTASSERTS @@ -1541,59 +1300,51 @@ TypeReq AssertCallExprNode::getPreferredType() //------------------------------------------------------------ -U32 SlotAccessNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) +U32 SlotAccessNode::compile(CodeStream& codeStream, U32 ip, TypeReq type) { if (type == TypeReqNone) return ip; precompileIdent(slotName); - // check if object is %this. If we are, we can do additional optimizations. - if (isThisVar(objectExpr)) + if (arrayExpr) { - optimizeThisPointer(codeStream, arrayExpr, ip, slotName); + // eval array + // OP_ADVANCE_STR + // evaluate object expression sub (OP_SETCURFIELD) + // OP_TERMINATE_REWIND_STR + // OP_SETCURFIELDARRAY + // total add of 4 + array precomp + + ip = arrayExpr->compile(codeStream, ip, TypeReqString); + codeStream.emit(OP_ADVANCE_STR); } - else + ip = objectExpr->compile(codeStream, ip, TypeReqString); + codeStream.emit(OP_SETCUROBJECT); + + codeStream.emit(OP_SETCURFIELD); + + codeStream.emitSTE(slotName); + + if (arrayExpr) { - if (arrayExpr) - { - // eval array - // OP_ADVANCE_STR - // evaluate object expression sub (OP_SETCURFIELD) - // OP_TERMINATE_REWIND_STR - // OP_SETCURFIELDARRAY - // total add of 4 + array precomp - - ip = arrayExpr->compile(codeStream, ip, TypeReqString); - codeStream.emit(OP_ADVANCE_STR); - } - ip = objectExpr->compile(codeStream, ip, TypeReqString); - codeStream.emit(OP_SETCUROBJECT); - - codeStream.emit(OP_SETCURFIELD); - - codeStream.emitSTE(slotName); - - if (arrayExpr) - { - codeStream.emit(OP_TERMINATE_REWIND_STR); - codeStream.emit(OP_SETCURFIELD_ARRAY); - } + codeStream.emit(OP_TERMINATE_REWIND_STR); + codeStream.emit(OP_SETCURFIELD_ARRAY); } switch (type) { - case TypeReqUInt: - codeStream.emit(OP_LOADFIELD_UINT); - break; - case TypeReqFloat: - codeStream.emit(OP_LOADFIELD_FLT); - break; - case TypeReqString: - codeStream.emit(OP_LOADFIELD_STR); - break; - case TypeReqNone: - break; + case TypeReqUInt: + codeStream.emit(OP_LOADFIELD_UINT); + break; + case TypeReqFloat: + codeStream.emit(OP_LOADFIELD_FLT); + break; + case TypeReqString: + codeStream.emit(OP_LOADFIELD_STR); + break; + case TypeReqNone: + break; } return codeStream.tell(); } @@ -1605,7 +1356,7 @@ TypeReq SlotAccessNode::getPreferredType() //----------------------------------------------------------------------------- -U32 InternalSlotAccessNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) +U32 InternalSlotAccessNode::compile(CodeStream& codeStream, U32 ip, TypeReq type) { if (type == TypeReqNone) return ip; @@ -1629,7 +1380,7 @@ TypeReq InternalSlotAccessNode::getPreferredType() //----------------------------------------------------------------------------- -U32 SlotAssignNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) +U32 SlotAssignNode::compile(CodeStream& codeStream, U32 ip, TypeReq type) { // first eval the expression TypeReqString @@ -1662,38 +1413,29 @@ U32 SlotAssignNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) precompileIdent(slotName); ip = valueExpr->compile(codeStream, ip, TypeReqString); - - if (isThisVar(objectExpr)) + codeStream.emit(OP_ADVANCE_STR); + if (arrayExpr) { - optimizeThisPointer(codeStream, arrayExpr, ip, slotName); + ip = arrayExpr->compile(codeStream, ip, TypeReqString); + codeStream.emit(OP_ADVANCE_STR); + } + if (objectExpr) + { + ip = objectExpr->compile(codeStream, ip, TypeReqString); + codeStream.emit(OP_SETCUROBJECT); } else + codeStream.emit(OP_SETCUROBJECT_NEW); + codeStream.emit(OP_SETCURFIELD); + codeStream.emitSTE(slotName); + + if (arrayExpr) { - codeStream.emit(OP_ADVANCE_STR); - if (arrayExpr) - { - ip = arrayExpr->compile(codeStream, ip, TypeReqString); - codeStream.emit(OP_ADVANCE_STR); - } - if (objectExpr) - { - ip = objectExpr->compile(codeStream, ip, TypeReqString); - codeStream.emit(OP_SETCUROBJECT); - } - else - codeStream.emit(OP_SETCUROBJECT_NEW); - codeStream.emit(OP_SETCURFIELD); - codeStream.emitSTE(slotName); - - if (arrayExpr) - { - codeStream.emit(OP_TERMINATE_REWIND_STR); - codeStream.emit(OP_SETCURFIELD_ARRAY); - } - codeStream.emit(OP_TERMINATE_REWIND_STR); + codeStream.emit(OP_SETCURFIELD_ARRAY); } + codeStream.emit(OP_TERMINATE_REWIND_STR); codeStream.emit(OP_SAVEFIELD_STR); if (typeID != -1) @@ -1714,7 +1456,7 @@ TypeReq SlotAssignNode::getPreferredType() //------------------------------------------------------------ -U32 SlotAssignOpNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) +U32 SlotAssignOpNode::compile(CodeStream& codeStream, U32 ip, TypeReq type) { // first eval the expression as its type @@ -1743,28 +1485,20 @@ U32 SlotAssignOpNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) precompileIdent(slotName); ip = valueExpr->compile(codeStream, ip, subType); - - if (isThisVar(objectExpr)) + if (arrayExpr) { - optimizeThisPointer(codeStream, arrayExpr, ip, slotName); + ip = arrayExpr->compile(codeStream, ip, TypeReqString); + codeStream.emit(OP_ADVANCE_STR); } - else - { - if (arrayExpr) - { - ip = arrayExpr->compile(codeStream, ip, TypeReqString); - codeStream.emit(OP_ADVANCE_STR); - } - ip = objectExpr->compile(codeStream, ip, TypeReqString); - codeStream.emit(OP_SETCUROBJECT); - codeStream.emit(OP_SETCURFIELD); - codeStream.emitSTE(slotName); + ip = objectExpr->compile(codeStream, ip, TypeReqString); + codeStream.emit(OP_SETCUROBJECT); + codeStream.emit(OP_SETCURFIELD); + codeStream.emitSTE(slotName); - if (arrayExpr) - { - codeStream.emit(OP_TERMINATE_REWIND_STR); - codeStream.emit(OP_SETCURFIELD_ARRAY); - } + if (arrayExpr) + { + codeStream.emit(OP_TERMINATE_REWIND_STR); + codeStream.emit(OP_SETCURFIELD_ARRAY); } codeStream.emit((subType == TypeReqFloat) ? OP_LOADFIELD_FLT : OP_LOADFIELD_UINT); codeStream.emit(operand); @@ -1782,7 +1516,7 @@ TypeReq SlotAssignOpNode::getPreferredType() //------------------------------------------------------------ -U32 ObjectDeclNode::compileSubObject(CodeStream &codeStream, U32 ip, bool root) +U32 ObjectDeclNode::compileSubObject(CodeStream& codeStream, U32 ip, bool root) { // goes @@ -1808,29 +1542,34 @@ U32 ObjectDeclNode::compileSubObject(CodeStream &codeStream, U32 ip, bool root) // To fix the stack issue [7/9/2007 Black] // OP_FINISH_OBJECT <-- fail point jumps to this opcode + S32 count = 2; // 2 OP_PUSH's + for (ExprNode* exprWalk = argList; exprWalk; exprWalk = (ExprNode*)exprWalk->getNext()) + count++; + codeStream.emit(OP_PUSH_FRAME); + codeStream.emit(count); ip = classNameExpr->compile(codeStream, ip, TypeReqString); codeStream.emit(OP_PUSH); ip = objectNameExpr->compile(codeStream, ip, TypeReqString); codeStream.emit(OP_PUSH); - for (ExprNode *exprWalk = argList; exprWalk; exprWalk = (ExprNode *)exprWalk->getNext()) + for (ExprNode* exprWalk = argList; exprWalk; exprWalk = (ExprNode*)exprWalk->getNext()) { TypeReq walkType = exprWalk->getPreferredType(); if (walkType == TypeReqNone) walkType = TypeReqString; ip = exprWalk->compile(codeStream, ip, walkType); switch (exprWalk->getPreferredType()) { - case TypeReqFloat: - codeStream.emit(OP_PUSH_FLT); - break; - case TypeReqUInt: - codeStream.emit(OP_PUSH_UINT); - break; - default: - codeStream.emit(OP_PUSH); - break; + case TypeReqFloat: + codeStream.emit(OP_PUSH_FLT); + break; + case TypeReqUInt: + codeStream.emit(OP_PUSH_UINT); + break; + default: + codeStream.emit(OP_PUSH); + break; } } codeStream.emit(OP_CREATE_OBJECT); @@ -1841,11 +1580,11 @@ U32 ObjectDeclNode::compileSubObject(CodeStream &codeStream, U32 ip, bool root) codeStream.emit(isSingleton); codeStream.emit(dbgLineNumber); const U32 failIp = codeStream.emit(0); - for (SlotAssignNode *slotWalk = slotDecls; slotWalk; slotWalk = (SlotAssignNode *)slotWalk->getNext()) + for (SlotAssignNode* slotWalk = slotDecls; slotWalk; slotWalk = (SlotAssignNode*)slotWalk->getNext()) ip = slotWalk->compile(codeStream, ip, TypeReqNone); codeStream.emit(OP_ADD_OBJECT); codeStream.emit(root); - for (ObjectDeclNode *objectWalk = subObjects; objectWalk; objectWalk = (ObjectDeclNode *)objectWalk->getNext()) + for (ObjectDeclNode* objectWalk = subObjects; objectWalk; objectWalk = (ObjectDeclNode*)objectWalk->getNext()) ip = objectWalk->compileSubObject(codeStream, ip, false); codeStream.emit(OP_END_OBJECT); codeStream.emit(root || isDatablock); @@ -1857,7 +1596,7 @@ U32 ObjectDeclNode::compileSubObject(CodeStream &codeStream, U32 ip, bool root) return codeStream.tell(); } -U32 ObjectDeclNode::compile(CodeStream &codeStream, U32 ip, TypeReq type) +U32 ObjectDeclNode::compile(CodeStream& codeStream, U32 ip, TypeReq type) { // root object decl does: @@ -1881,7 +1620,7 @@ TypeReq ObjectDeclNode::getPreferredType() //------------------------------------------------------------ -U32 FunctionDeclStmtNode::compileStmt(CodeStream &codeStream, U32 ip) +U32 FunctionDeclStmtNode::compileStmt(CodeStream& codeStream, U32 ip) { // OP_FUNC_DECL // func name @@ -1896,10 +1635,14 @@ U32 FunctionDeclStmtNode::compileStmt(CodeStream &codeStream, U32 ip) setCurrentStringTable(&getFunctionStringTable()); setCurrentFloatTable(&getFunctionFloatTable()); + FuncVars vars; + gFuncVars = &vars; + argc = 0; - for (VarNode *walk = args; walk; walk = (VarNode *)((StmtNode*)walk)->getNext()) + for (VarNode* walk = args; walk; walk = (VarNode*)((StmtNode*)walk)->getNext()) { precompileIdent(walk->varName); + gFuncVars->assign(walk->varName, TypeReqNone); argc++; } @@ -1919,9 +1662,11 @@ U32 FunctionDeclStmtNode::compileStmt(CodeStream &codeStream, U32 ip) codeStream.emit(U32(bool(stmts != NULL) ? 1 : 0) + U32(dbgLineNumber << 1)); const U32 endIp = codeStream.emit(0); codeStream.emit(argc); - for (VarNode *walk = args; walk; walk = (VarNode *)((StmtNode*)walk)->getNext()) + const U32 localNumVarsIP = codeStream.emit(0); + for (VarNode* walk = args; walk; walk = (VarNode*)((StmtNode*)walk)->getNext()) { - codeStream.emitSTE(walk->varName); + StringTableEntry name = walk->varName; + codeStream.emit(gFuncVars->lookup(name)); } CodeBlock::smInFunction = true; ip = compileBlock(stmts, codeStream, ip); @@ -1933,10 +1678,12 @@ U32 FunctionDeclStmtNode::compileStmt(CodeStream &codeStream, U32 ip) CodeBlock::smInFunction = false; codeStream.emit(OP_RETURN_VOID); + codeStream.patch(localNumVarsIP, gFuncVars->count()); codeStream.patch(endIp, codeStream.tell()); setCurrentStringTable(&getGlobalStringTable()); setCurrentFloatTable(&getGlobalFloatTable()); + gFuncVars = NULL; return ip; } diff --git a/Engine/source/console/codeBlock.cpp b/Engine/source/console/codeBlock.cpp index b4dd6b2c6..997519231 100644 --- a/Engine/source/console/codeBlock.cpp +++ b/Engine/source/console/codeBlock.cpp @@ -477,7 +477,6 @@ bool CodeBlock::compile(const char *codeFileName, StringTableEntry fileName, con STEtoCode = compileSTEtoCode; gStatementList = NULL; - gAnonFunctionList = NULL; // Set up the parser. smCurrentParser = getParserForFile(fileName); @@ -487,17 +486,6 @@ bool CodeBlock::compile(const char *codeFileName, StringTableEntry fileName, con smCurrentParser->setScanBuffer(script, fileName); smCurrentParser->restart(NULL); smCurrentParser->parse(); - if (gStatementList) - { - if (gAnonFunctionList) - { - // Prepend anonymous functions to statement list, so they're defined already when - // the statements run. - gAnonFunctionList->append(gStatementList); - gStatementList = gAnonFunctionList; - } - } - if (gSyntaxError) { @@ -575,11 +563,9 @@ bool CodeBlock::compile(const char *codeFileName, StringTableEntry fileName, con st.close(); return true; - - } -ConsoleValueRef CodeBlock::compileExec(StringTableEntry fileName, const char *inString, bool noCalls, S32 setFrame) +void CodeBlock::compileExec(StringTableEntry fileName, const char *inString, ConsoleValue &returnValue, bool noCalls, S32 setFrame) { AssertFatal(Con::isMainThread(), "Compiling code on a secondary thread"); @@ -620,7 +606,6 @@ ConsoleValueRef CodeBlock::compileExec(StringTableEntry fileName, const char *in addToCodeList(); gStatementList = NULL; - gAnonFunctionList = NULL; // Set up the parser. smCurrentParser = getParserForFile(fileName); @@ -630,21 +615,11 @@ ConsoleValueRef CodeBlock::compileExec(StringTableEntry fileName, const char *in smCurrentParser->setScanBuffer(string, fileName); smCurrentParser->restart(NULL); smCurrentParser->parse(); - if (gStatementList) - { - if (gAnonFunctionList) - { - // Prepend anonymous functions to statement list, so they're defined already when - // the statements run. - gAnonFunctionList->append(gStatementList); - gStatementList = gAnonFunctionList; - } - } if (!gStatementList) { delete this; - return ConsoleValueRef(); + return; } resetTables(); @@ -678,7 +653,7 @@ ConsoleValueRef CodeBlock::compileExec(StringTableEntry fileName, const char *in if (lastIp + 1 != codeSize) Con::warnf(ConsoleLogEntry::General, "precompile size mismatch, precompile: %d compile: %d", codeSize, lastIp); - return exec(0, fileName, NULL, 0, 0, noCalls, NULL, setFrame); + exec(0, fileName, NULL, 0, 0, noCalls, NULL, returnValue, setFrame); } //------------------------------------------------------------------------- @@ -739,775 +714,723 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn) switch (code[ip++]) { - case OP_FUNC_DECL: - { - StringTableEntry fnName = CodeToSTE(code, ip); - StringTableEntry fnNamespace = CodeToSTE(code, ip + 2); - StringTableEntry fnPackage = CodeToSTE(code, ip + 4); - bool hasBody = bool(code[ip + 6]); - U32 newIp = code[ip + 7]; - U32 argc = code[ip + 8]; - endFuncIp = newIp; - - Con::printf("%i: OP_FUNC_DECL name=%s nspace=%s package=%s hasbody=%i newip=%i argc=%i", - ip - 1, fnName, fnNamespace, fnPackage, hasBody, newIp, argc); - - // Skip args. - - ip += 9 + (argc * 2); - smInFunction = true; - break; - } - - case OP_CREATE_OBJECT: - { - 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]; - U32 failJump = code[ip + 6]; - - Con::printf("%i: OP_CREATE_OBJECT objParent=%s isDataBlock=%i isInternal=%i isSingleton=%i lineNumber=%i failJump=%i", - ip - 1, objParent, isDataBlock, isInternal, isSingleton, lineNumber, failJump); - - ip += 7; - break; - } - - case OP_ADD_OBJECT: - { - bool placeAtRoot = code[ip++]; - Con::printf("%i: OP_ADD_OBJECT placeAtRoot=%i", ip - 1, placeAtRoot); - break; - } - - case OP_END_OBJECT: - { - bool placeAtRoot = code[ip++]; - Con::printf("%i: OP_END_OBJECT placeAtRoot=%i", ip - 1, placeAtRoot); - break; - } - - case OP_FINISH_OBJECT: - { - Con::printf("%i: OP_FINISH_OBJECT", ip - 1); - break; - } - - case OP_JMPIFFNOT: - { - Con::printf("%i: OP_JMPIFFNOT ip=%i", ip - 1, code[ip]); - ++ip; - break; - } - - case OP_JMPIFNOT: - { - Con::printf("%i: OP_JMPIFNOT ip=%i", ip - 1, code[ip]); - ++ip; - break; - } - - case OP_JMPIFF: - { - Con::printf("%i: OP_JMPIFF ip=%i", ip - 1, code[ip]); - ++ip; - break; - } - - case OP_JMPIF: - { - Con::printf("%i: OP_JMPIF ip=%i", ip - 1, code[ip]); - ++ip; - break; - } - - case OP_JMPIFNOT_NP: - { - Con::printf("%i: OP_JMPIFNOT_NP ip=%i", ip - 1, code[ip]); - ++ip; - break; - } - - case OP_JMPIF_NP: - { - Con::printf("%i: OP_JMPIF_NP ip=%i", ip - 1, code[ip]); - ++ip; - break; - } - - case OP_JMP: - { - Con::printf("%i: OP_JMP ip=%i", ip - 1, code[ip]); - ++ip; - break; - } - - case OP_RETURN: - { - Con::printf("%i: OP_RETURN", ip - 1); - - if (upToReturn) - return; - - break; - } - - case OP_RETURN_VOID: - { - Con::printf("%i: OP_RETURNVOID", ip - 1); - - if (upToReturn) - return; - - break; - } - - case OP_RETURN_UINT: - { - Con::printf("%i: OP_RETURNUINT", ip - 1); - - if (upToReturn) - return; - - break; - } - - case OP_RETURN_FLT: - { - Con::printf("%i: OP_RETURNFLT", ip - 1); - - if (upToReturn) - return; - - break; - } - - case OP_CMPEQ: - { - Con::printf("%i: OP_CMPEQ", ip - 1); - break; - } - - case OP_CMPGR: - { - Con::printf("%i: OP_CMPGR", ip - 1); - break; - } - - case OP_CMPGE: - { - Con::printf("%i: OP_CMPGE", ip - 1); - break; - } - - case OP_CMPLT: - { - Con::printf("%i: OP_CMPLT", ip - 1); - break; - } - - case OP_CMPLE: - { - Con::printf("%i: OP_CMPLE", ip - 1); - break; - } - - case OP_CMPNE: - { - Con::printf("%i: OP_CMPNE", ip - 1); - break; - } - - case OP_XOR: - { - Con::printf("%i: OP_XOR", ip - 1); - break; - } - - case OP_MOD: - { - Con::printf("%i: OP_MOD", ip - 1); - break; - } - - case OP_BITAND: - { - Con::printf("%i: OP_BITAND", ip - 1); - break; - } - - case OP_BITOR: - { - Con::printf("%i: OP_BITOR", ip - 1); - break; - } - - case OP_NOT: - { - Con::printf("%i: OP_NOT", ip - 1); - break; - } - - case OP_NOTF: - { - Con::printf("%i: OP_NOTF", ip - 1); - break; - } - - case OP_ONESCOMPLEMENT: - { - Con::printf("%i: OP_ONESCOMPLEMENT", ip - 1); - break; - } - - case OP_SHR: - { - Con::printf("%i: OP_SHR", ip - 1); - break; - } - - case OP_SHL: - { - Con::printf("%i: OP_SHL", ip - 1); - break; - } - - case OP_AND: - { - Con::printf("%i: OP_AND", ip - 1); - break; - } - - case OP_OR: - { - Con::printf("%i: OP_OR", ip - 1); - break; - } - - case OP_ADD: - { - Con::printf("%i: OP_ADD", ip - 1); - break; - } - - case OP_SUB: - { - Con::printf("%i: OP_SUB", ip - 1); - break; - } - - case OP_MUL: - { - Con::printf("%i: OP_MUL", ip - 1); - break; - } - - case OP_DIV: - { - Con::printf("%i: OP_DIV", ip - 1); - break; - } - - case OP_NEG: - { - Con::printf("%i: OP_NEG", ip - 1); - break; - } - - case OP_INC: - { - Con::printf("%i: OP_INC varName=%s", ip - 1, CodeToSTE(code, ip)); - ip += 2; - break; - } - - case OP_DEC: - { - Con::printf("%i: OP_DEC varName=%s", ip - 1, CodeToSTE(code, ip)); - ip += 2; - break; - } - - case OP_SETCURVAR: - { - StringTableEntry var = CodeToSTE(code, ip); - - Con::printf("%i: OP_SETCURVAR var=%s", ip - 1, var); - ip += 2; - break; - } - - case OP_SETCURVAR_CREATE: - { - StringTableEntry var = CodeToSTE(code, ip); - - Con::printf("%i: OP_SETCURVAR_CREATE var=%s", ip - 1, var); - ip += 2; - break; - } - - case OP_SETCURVAR_ARRAY: - { - Con::printf("%i: OP_SETCURVAR_ARRAY", ip - 1); - break; - } - - case OP_SETCURVAR_ARRAY_VARLOOKUP: - { - StringTableEntry arrayName = CodeToSTE(code, ip); - StringTableEntry arrayLookup = CodeToSTE(code, ip + 2); - - Con::printf("%i: OP_SETCURVAR_ARRAY_VARLOOKUP arrayName=%s arrayLookup=%s", ip - 1, arrayName, arrayLookup); - ip += 4; - break; - } - - case OP_SETCURVAR_ARRAY_CREATE: - { - Con::printf("%i: OP_SETCURVAR_ARRAY_CREATE", ip - 1); - break; - } - - case OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP: - { - StringTableEntry arrayName = CodeToSTE(code, ip); - StringTableEntry arrayLookup = CodeToSTE(code, ip + 2); - - Con::printf("%i: OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP arrayName=%s arrayLookup=%s", ip - 1, arrayName, arrayLookup); - ip += 4; - break; - } - - case OP_LOADVAR_UINT: - { - Con::printf("%i: OP_LOADVAR_UINT", ip - 1); - break; - } - - case OP_LOADVAR_FLT: - { - Con::printf("%i: OP_LOADVAR_FLT", ip - 1); - break; - } - - case OP_LOADVAR_STR: - { - Con::printf("%i: OP_LOADVAR_STR", ip - 1); - break; - } - - case OP_LOADVAR_VAR: - { - Con::printf("%i: OP_LOADVAR_VAR", ip - 1); - break; - } - - case OP_SAVEVAR_UINT: - { - Con::printf("%i: OP_SAVEVAR_UINT", ip - 1); - break; - } - - case OP_SAVEVAR_FLT: - { - Con::printf("%i: OP_SAVEVAR_FLT", ip - 1); - break; - } - - case OP_SAVEVAR_STR: - { - Con::printf("%i: OP_SAVEVAR_STR", ip - 1); - break; - } - - case OP_SAVEVAR_VAR: - { - Con::printf("%i: OP_SAVEVAR_VAR", ip - 1); - break; - } - - case OP_SETCUROBJECT: - { - Con::printf("%i: OP_SETCUROBJECT", ip - 1); - break; - } - - case OP_SETCUROBJECT_NEW: - { - Con::printf("%i: OP_SETCUROBJECT_NEW", ip - 1); - break; - } - - case OP_SETCUROBJECT_INTERNAL: - { - Con::printf("%i: OP_SETCUROBJECT_INTERNAL", ip - 1); - ++ip; - break; - } - - case OP_SETCURFIELD: - { - StringTableEntry curField = CodeToSTE(code, ip); - Con::printf("%i: OP_SETCURFIELD field=%s", ip - 1, curField); - ip += 2; - break; - } - - case OP_SETCURFIELD_ARRAY: - { - Con::printf("%i: OP_SETCURFIELD_ARRAY", ip - 1); - break; - } - - case OP_SETCURFIELD_ARRAY_VAR: - { - StringTableEntry var = CodeToSTE(code, ip); - Con::printf("%i: OP_SETCURFIELD_ARRAY_VAR var=%s", ip - 1, var); - ip += 2; - break; - } - - case OP_SETCURFIELD_THIS: - { - StringTableEntry curField = CodeToSTE(code, ip); - Con::printf("%i: OP_SETCURFIELD_THIS field=%s", ip - 1, curField); - ip += 2; - break; - } - - case OP_SETCURFIELD_TYPE: - { - U32 type = code[ip]; - Con::printf("%i: OP_SETCURFIELD_TYPE type=%i", ip - 1, type); - ++ip; - break; - } - - case OP_LOADFIELD_UINT: - { - Con::printf("%i: OP_LOADFIELD_UINT", ip - 1); - break; - } - - case OP_LOADFIELD_FLT: - { - Con::printf("%i: OP_LOADFIELD_FLT", ip - 1); - break; - } - - case OP_LOADFIELD_STR: - { - Con::printf("%i: OP_LOADFIELD_STR", ip - 1); - break; - } - - case OP_SAVEFIELD_UINT: - { - Con::printf("%i: OP_SAVEFIELD_UINT", ip - 1); - break; - } - - case OP_SAVEFIELD_FLT: - { - Con::printf("%i: OP_SAVEFIELD_FLT", ip - 1); - break; - } - - case OP_SAVEFIELD_STR: - { - Con::printf("%i: OP_SAVEFIELD_STR", ip - 1); - break; - } - - case OP_STR_TO_UINT: - { - Con::printf("%i: OP_STR_TO_UINT", ip - 1); - break; - } - - case OP_STR_TO_FLT: - { - Con::printf("%i: OP_STR_TO_FLT", ip - 1); - break; - } - - case OP_STR_TO_NONE: - { - Con::printf("%i: OP_STR_TO_NONE", ip - 1); - break; - } - - case OP_FLT_TO_UINT: - { - Con::printf("%i: OP_FLT_TO_UINT", ip - 1); - break; - } - - case OP_FLT_TO_STR: - { - Con::printf("%i: OP_FLT_TO_STR", ip - 1); - break; - } - - case OP_FLT_TO_NONE: - { - Con::printf("%i: OP_FLT_TO_NONE", ip - 1); - break; - } - - case OP_UINT_TO_FLT: - { - Con::printf("%i: OP_SAVEFIELD_STR", ip - 1); - break; - } - - case OP_UINT_TO_STR: - { - Con::printf("%i: OP_UINT_TO_STR", ip - 1); - break; - } - - case OP_UINT_TO_NONE: - { - Con::printf("%i: OP_UINT_TO_NONE", ip - 1); - break; - } - - case OP_COPYVAR_TO_NONE: - { - Con::printf("%i: OP_COPYVAR_TO_NONE", ip - 1); - break; - } - - case OP_LOADIMMED_UINT: - { - U32 val = code[ip]; - Con::printf("%i: OP_LOADIMMED_UINT val=%i", ip - 1, val); - ++ip; - break; - } - - case OP_LOADIMMED_FLT: - { - F64 val = (smInFunction ? functionFloats : globalFloats)[code[ip]]; - Con::printf("%i: OP_LOADIMMED_FLT val=%f", ip - 1, val); - ++ip; - break; - } - - case OP_TAG_TO_STR: - { - const char* str = (smInFunction ? functionStrings : globalStrings) + code[ip]; - Con::printf("%i: OP_TAG_TO_STR str=%s", ip - 1, str); - ++ip; - break; - } - - case OP_LOADIMMED_STR: - { - const char* str = (smInFunction ? functionStrings : globalStrings) + code[ip]; - Con::printf("%i: OP_LOADIMMED_STR str=%s", ip - 1, str); - ++ip; - break; - } - - case OP_DOCBLOCK_STR: - { - const char* str = (smInFunction ? functionStrings : globalStrings) + code[ip]; - Con::printf("%i: OP_DOCBLOCK_STR str=%s", ip - 1, str); - ++ip; - break; - } - - case OP_LOADIMMED_IDENT: - { - StringTableEntry str = CodeToSTE(code, ip); - Con::printf("%i: OP_LOADIMMED_IDENT str=%s", ip - 1, str); - ip += 2; - break; - } - - case OP_CALLFUNC_RESOLVE: - { - StringTableEntry fnNamespace = CodeToSTE(code, ip + 2); - StringTableEntry fnName = CodeToSTE(code, ip); - U32 callType = code[ip + 2]; - - Con::printf("%i: OP_CALLFUNC_RESOLVE name=%s nspace=%s callType=%s", ip - 1, fnName, fnNamespace, - callType == FuncCallExprNode::FunctionCall ? "FunctionCall" - : callType == FuncCallExprNode::MethodCall ? "MethodCall" : "ParentCall"); - - ip += 5; - break; - } - - case OP_CALLFUNC: - { - StringTableEntry fnNamespace = CodeToSTE(code, ip + 2); - StringTableEntry fnName = CodeToSTE(code, ip); - U32 callType = code[ip + 4]; - - Con::printf("%i: OP_CALLFUNC name=%s nspace=%s callType=%s", ip - 1, fnName, fnNamespace, - callType == FuncCallExprNode::FunctionCall ? "FunctionCall" - : callType == FuncCallExprNode::MethodCall ? "MethodCall" : "ParentCall"); - - ip += 5; - break; - } - - case OP_CALLFUNC_POINTER: - { - Con::printf("%i: OP_CALLFUNC_POINTER", ip - 1); - break; - } - - case OP_CALLFUNC_THIS: - { - StringTableEntry fnName = CodeToSTE(code, ip); - Con::printf("%i: OP_CALLFUNC_THIS name=%s ", ip - 1, fnName); - - ip += 2; - break; - } - - case OP_ADVANCE_STR: - { - Con::printf("%i: OP_ADVANCE_STR", ip - 1); - break; - } - - case OP_ADVANCE_STR_APPENDCHAR: - { - char ch = code[ip]; - Con::printf("%i: OP_ADVANCE_STR_APPENDCHAR char=%c", ip - 1, ch); - ++ip; - break; - } - - case OP_ADVANCE_STR_COMMA: - { - Con::printf("%i: OP_ADVANCE_STR_COMMA", ip - 1); - break; - } - - case OP_ADVANCE_STR_NUL: - { - Con::printf("%i: OP_ADVANCE_STR_NUL", ip - 1); - break; - } - - case OP_REWIND_STR: - { - Con::printf("%i: OP_REWIND_STR", ip - 1); - break; - } - - case OP_TERMINATE_REWIND_STR: - { - Con::printf("%i: OP_TERMINATE_REWIND_STR", ip - 1); - break; - } - - case OP_COMPARE_STR: - { - Con::printf("%i: OP_COMPARE_STR", ip - 1); - break; - } - - case OP_PUSH: - { - Con::printf("%i: OP_PUSH", ip - 1); - break; - } - - case OP_PUSH_UINT: - { - Con::printf("%i: OP_PUSH_UINT", ip - 1); - break; - } - - case OP_PUSH_FLT: - { - Con::printf("%i: OP_PUSH_FLT", ip - 1); - break; - } - - case OP_PUSH_VAR: - { - Con::printf("%i: OP_PUSH_VAR", ip - 1); - break; - } - - case OP_PUSH_THIS: - { - Con::printf("%i: OP_PUSH_THIS varName=%s", ip - 1, CodeToSTE(code, ip)); - ip += 2; - break; - } - - case OP_PUSH_FRAME: - { - Con::printf("%i: OP_PUSH_FRAME", ip - 1); - break; - } - - case OP_ASSERT: - { - const char* message = (smInFunction ? functionStrings : globalStrings) + code[ip]; - Con::printf("%i: OP_ASSERT message=%s", ip - 1, message); - ++ip; - break; - } - - case OP_BREAK: - { - Con::printf("%i: OP_BREAK", ip - 1); - break; - } - - case OP_ITER_BEGIN: - { - StringTableEntry varName = CodeToSTE(code, ip); - U32 failIp = code[ip + 2]; - - Con::printf("%i: OP_ITER_BEGIN varName=%s failIp=%i", ip - 1, varName, failIp); - - ip += 3; - break; - } - - case OP_ITER_BEGIN_STR: - { - StringTableEntry varName = CodeToSTE(code, ip); - U32 failIp = code[ip + 2]; - - Con::printf("%i: OP_ITER_BEGIN varName=%s failIp=%i", ip - 1, varName, failIp); - - ip += 3; - break; - } - - case OP_ITER: - { - U32 breakIp = code[ip]; - - Con::printf("%i: OP_ITER breakIp=%i", ip - 1, breakIp); - - ++ip; - break; - } - - case OP_ITER_END: - { - Con::printf("%i: OP_ITER_END", ip - 1); - break; - } - - default: - Con::printf("%i: !!INVALID!!", ip - 1); - break; + case OP_FUNC_DECL: + { + StringTableEntry fnName = CodeToSTE(code, ip); + StringTableEntry fnNamespace = CodeToSTE(code, ip + 2); + StringTableEntry fnPackage = CodeToSTE(code, ip + 4); + bool hasBody = bool(code[ip + 6]); + U32 newIp = code[ip + 7]; + U32 argc = code[ip + 8]; + U32 regCount = code[ip + 9]; + endFuncIp = newIp; + + Con::printf("%i: OP_FUNC_DECL name=%s nspace=%s package=%s hasbody=%i newip=%i argc=%i regCount=%i", + ip - 1, fnName, fnNamespace, fnPackage, hasBody, newIp, argc, regCount); + + // Skip args. + + ip += 10 + argc; + smInFunction = true; + break; + } + + case OP_CREATE_OBJECT: + { + 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]; + U32 failJump = code[ip + 6]; + + Con::printf("%i: OP_CREATE_OBJECT objParent=%s isDataBlock=%i isInternal=%i isSingleton=%i lineNumber=%i failJump=%i", + ip - 1, objParent, isDataBlock, isInternal, isSingleton, lineNumber, failJump); + + ip += 7; + break; + } + + case OP_ADD_OBJECT: + { + bool placeAtRoot = code[ip++]; + Con::printf("%i: OP_ADD_OBJECT placeAtRoot=%i", ip - 1, placeAtRoot); + break; + } + + case OP_END_OBJECT: + { + bool placeAtRoot = code[ip++]; + Con::printf("%i: OP_END_OBJECT placeAtRoot=%i", ip - 1, placeAtRoot); + break; + } + + case OP_FINISH_OBJECT: + { + Con::printf("%i: OP_FINISH_OBJECT", ip - 1); + break; + } + + case OP_JMPIFFNOT: + { + Con::printf("%i: OP_JMPIFFNOT ip=%i", ip - 1, code[ip]); + ++ip; + break; + } + + case OP_JMPIFNOT: + { + Con::printf("%i: OP_JMPIFNOT ip=%i", ip - 1, code[ip]); + ++ip; + break; + } + + case OP_JMPIFF: + { + Con::printf("%i: OP_JMPIFF ip=%i", ip - 1, code[ip]); + ++ip; + break; + } + + case OP_JMPIF: + { + Con::printf("%i: OP_JMPIF ip=%i", ip - 1, code[ip]); + ++ip; + break; + } + + case OP_JMPIFNOT_NP: + { + Con::printf("%i: OP_JMPIFNOT_NP ip=%i", ip - 1, code[ip]); + ++ip; + break; + } + + case OP_JMPIF_NP: + { + Con::printf("%i: OP_JMPIF_NP ip=%i", ip - 1, code[ip]); + ++ip; + break; + } + + case OP_JMP: + { + Con::printf("%i: OP_JMP ip=%i", ip - 1, code[ip]); + ++ip; + break; + } + + case OP_RETURN: + { + Con::printf("%i: OP_RETURN", ip - 1); + + if (upToReturn) + return; + + break; + } + + case OP_RETURN_VOID: + { + Con::printf("%i: OP_RETURNVOID", ip - 1); + + if (upToReturn) + return; + + break; + } + + case OP_RETURN_UINT: + { + Con::printf("%i: OP_RETURNUINT", ip - 1); + + if (upToReturn) + return; + + break; + } + + case OP_RETURN_FLT: + { + Con::printf("%i: OP_RETURNFLT", ip - 1); + + if (upToReturn) + return; + + break; + } + + case OP_CMPEQ: + { + Con::printf("%i: OP_CMPEQ", ip - 1); + break; + } + + case OP_CMPGR: + { + Con::printf("%i: OP_CMPGR", ip - 1); + break; + } + + case OP_CMPGE: + { + Con::printf("%i: OP_CMPGE", ip - 1); + break; + } + + case OP_CMPLT: + { + Con::printf("%i: OP_CMPLT", ip - 1); + break; + } + + case OP_CMPLE: + { + Con::printf("%i: OP_CMPLE", ip - 1); + break; + } + + case OP_CMPNE: + { + Con::printf("%i: OP_CMPNE", ip - 1); + break; + } + + case OP_XOR: + { + Con::printf("%i: OP_XOR", ip - 1); + break; + } + + case OP_MOD: + { + Con::printf("%i: OP_MOD", ip - 1); + break; + } + + case OP_BITAND: + { + Con::printf("%i: OP_BITAND", ip - 1); + break; + } + + case OP_BITOR: + { + Con::printf("%i: OP_BITOR", ip - 1); + break; + } + + case OP_NOT: + { + Con::printf("%i: OP_NOT", ip - 1); + break; + } + + case OP_NOTF: + { + Con::printf("%i: OP_NOTF", ip - 1); + break; + } + + case OP_ONESCOMPLEMENT: + { + Con::printf("%i: OP_ONESCOMPLEMENT", ip - 1); + break; + } + + case OP_SHR: + { + Con::printf("%i: OP_SHR", ip - 1); + break; + } + + case OP_SHL: + { + Con::printf("%i: OP_SHL", ip - 1); + break; + } + + case OP_AND: + { + Con::printf("%i: OP_AND", ip - 1); + break; + } + + case OP_OR: + { + Con::printf("%i: OP_OR", ip - 1); + break; + } + + case OP_ADD: + { + Con::printf("%i: OP_ADD", ip - 1); + break; + } + + case OP_SUB: + { + Con::printf("%i: OP_SUB", ip - 1); + break; + } + + case OP_MUL: + { + Con::printf("%i: OP_MUL", ip - 1); + break; + } + + case OP_DIV: + { + Con::printf("%i: OP_DIV", ip - 1); + break; + } + + case OP_NEG: + { + Con::printf("%i: OP_NEG", ip - 1); + break; + } + + case OP_INC: + { + Con::printf("%i: OP_INC reg=%i", ip - 1, code[ip]); + ++ip; + break; + } + + case OP_SETCURVAR: + { + StringTableEntry var = CodeToSTE(code, ip); + + Con::printf("%i: OP_SETCURVAR var=%s", ip - 1, var); + ip += 2; + break; + } + + case OP_SETCURVAR_CREATE: + { + StringTableEntry var = CodeToSTE(code, ip); + + Con::printf("%i: OP_SETCURVAR_CREATE var=%s", ip - 1, var); + ip += 2; + break; + } + + case OP_SETCURVAR_ARRAY: + { + Con::printf("%i: OP_SETCURVAR_ARRAY", ip - 1); + break; + } + + case OP_SETCURVAR_ARRAY_CREATE: + { + Con::printf("%i: OP_SETCURVAR_ARRAY_CREATE", ip - 1); + break; + } + + case OP_LOADVAR_UINT: + { + Con::printf("%i: OP_LOADVAR_UINT", ip - 1); + break; + } + + case OP_LOADVAR_FLT: + { + Con::printf("%i: OP_LOADVAR_FLT", ip - 1); + break; + } + + case OP_LOADVAR_STR: + { + Con::printf("%i: OP_LOADVAR_STR", ip - 1); + break; + } + + case OP_SAVEVAR_UINT: + { + Con::printf("%i: OP_SAVEVAR_UINT", ip - 1); + break; + } + + case OP_SAVEVAR_FLT: + { + Con::printf("%i: OP_SAVEVAR_FLT", ip - 1); + break; + } + + case OP_SAVEVAR_STR: + { + Con::printf("%i: OP_SAVEVAR_STR", ip - 1); + break; + } + + case OP_LOAD_LOCAL_VAR_UINT: + { + Con::printf("%i: OP_LOAD_LOCAL_VAR_UINT reg=%i", ip - 1, code[ip]); + ++ip; + break; + } + + case OP_LOAD_LOCAL_VAR_FLT: + { + Con::printf("%i: OP_LOAD_LOCAL_VAR_FLT reg=%i", ip - 1, code[ip]); + ++ip; + break; + } + + case OP_LOAD_LOCAL_VAR_STR: + { + Con::printf("%i: OP_LOAD_LOCAL_VAR_STR reg=%i", ip - 1, code[ip]); + ++ip; + break; + } + + case OP_SAVE_LOCAL_VAR_UINT: + { + Con::printf("%i: OP_SAVE_LOCAL_VAR_UINT reg=%i", ip - 1, code[ip]); + ++ip; + break; + } + + case OP_SAVE_LOCAL_VAR_FLT: + { + Con::printf("%i: OP_SAVE_LOCAL_VAR_FLT reg=%i", ip - 1, code[ip]); + ++ip; + break; + } + + case OP_SAVE_LOCAL_VAR_STR: + { + Con::printf("%i: OP_SAVE_LOCAL_VAR_STR reg=%i", ip - 1, code[ip]); + ++ip; + break; + } + + case OP_SETCUROBJECT: + { + Con::printf("%i: OP_SETCUROBJECT", ip - 1); + break; + } + + case OP_SETCUROBJECT_NEW: + { + Con::printf("%i: OP_SETCUROBJECT_NEW", ip - 1); + break; + } + + case OP_SETCUROBJECT_INTERNAL: + { + Con::printf("%i: OP_SETCUROBJECT_INTERNAL", ip - 1); + ++ip; + break; + } + + case OP_SETCURFIELD: + { + StringTableEntry curField = CodeToSTE(code, ip); + Con::printf("%i: OP_SETCURFIELD field=%s", ip - 1, curField); + ip += 2; + break; + } + + case OP_SETCURFIELD_ARRAY: + { + Con::printf("%i: OP_SETCURFIELD_ARRAY", ip - 1); + break; + } + + case OP_SETCURFIELD_TYPE: + { + U32 type = code[ip]; + Con::printf("%i: OP_SETCURFIELD_TYPE type=%i", ip - 1, type); + ++ip; + break; + } + + case OP_LOADFIELD_UINT: + { + Con::printf("%i: OP_LOADFIELD_UINT", ip - 1); + break; + } + + case OP_LOADFIELD_FLT: + { + Con::printf("%i: OP_LOADFIELD_FLT", ip - 1); + break; + } + + case OP_LOADFIELD_STR: + { + Con::printf("%i: OP_LOADFIELD_STR", ip - 1); + break; + } + + case OP_SAVEFIELD_UINT: + { + Con::printf("%i: OP_SAVEFIELD_UINT", ip - 1); + break; + } + + case OP_SAVEFIELD_FLT: + { + Con::printf("%i: OP_SAVEFIELD_FLT", ip - 1); + break; + } + + case OP_SAVEFIELD_STR: + { + Con::printf("%i: OP_SAVEFIELD_STR", ip - 1); + break; + } + + case OP_STR_TO_UINT: + { + Con::printf("%i: OP_STR_TO_UINT", ip - 1); + break; + } + + case OP_STR_TO_FLT: + { + Con::printf("%i: OP_STR_TO_FLT", ip - 1); + break; + } + + case OP_STR_TO_NONE: + { + Con::printf("%i: OP_STR_TO_NONE", ip - 1); + break; + } + + case OP_FLT_TO_UINT: + { + Con::printf("%i: OP_FLT_TO_UINT", ip - 1); + break; + } + + case OP_FLT_TO_STR: + { + Con::printf("%i: OP_FLT_TO_STR", ip - 1); + break; + } + + case OP_FLT_TO_NONE: + { + Con::printf("%i: OP_FLT_TO_NONE", ip - 1); + break; + } + + case OP_UINT_TO_FLT: + { + Con::printf("%i: OP_UINT_TO_FLT", ip - 1); + break; + } + + case OP_UINT_TO_STR: + { + Con::printf("%i: OP_UINT_TO_STR", ip - 1); + break; + } + + case OP_UINT_TO_NONE: + { + Con::printf("%i: OP_UINT_TO_NONE", ip - 1); + break; + } + + case OP_LOADIMMED_UINT: + { + U32 val = code[ip]; + Con::printf("%i: OP_LOADIMMED_UINT val=%i", ip - 1, val); + ++ip; + break; + } + + case OP_LOADIMMED_FLT: + { + F64 val = (smInFunction ? functionFloats : globalFloats)[code[ip]]; + Con::printf("%i: OP_LOADIMMED_FLT val=%f", ip - 1, val); + ++ip; + break; + } + + case OP_TAG_TO_STR: + { + const char* str = (smInFunction ? functionStrings : globalStrings) + code[ip]; + Con::printf("%i: OP_TAG_TO_STR str=%s", ip - 1, str); + ++ip; + break; + } + + case OP_LOADIMMED_STR: + { + const char* str = (smInFunction ? functionStrings : globalStrings) + code[ip]; + Con::printf("%i: OP_LOADIMMED_STR str=%s", ip - 1, str); + ++ip; + break; + } + + case OP_DOCBLOCK_STR: + { + const char* str = (smInFunction ? functionStrings : globalStrings) + code[ip]; + Con::printf("%i: OP_DOCBLOCK_STR str=%s", ip - 1, str); + ++ip; + break; + } + + case OP_LOADIMMED_IDENT: + { + StringTableEntry str = CodeToSTE(code, ip); + Con::printf("%i: OP_LOADIMMED_IDENT str=%s", ip - 1, str); + ip += 2; + break; + } + + case OP_CALLFUNC: + { + StringTableEntry fnNamespace = CodeToSTE(code, ip + 2); + StringTableEntry fnName = CodeToSTE(code, ip); + U32 callType = code[ip + 4]; + + StringTableEntry callTypeName; + switch (callType) + { + case FuncCallExprNode::FunctionCall: callTypeName = "FunctionCall"; break; + case FuncCallExprNode::MethodCall: callTypeName = "MethodCall"; break; + case FuncCallExprNode::ParentCall: callTypeName = "ParentCall"; break; + case FuncCallExprNode::StaticCall: callTypeName = "StaticCall"; break; + } + + Con::printf("%i: OP_CALLFUNC name=%s nspace=%s callType=%s", ip - 1, fnName, fnNamespace, callTypeName); + + ip += 5; + break; + } + + case OP_ADVANCE_STR: + { + Con::printf("%i: OP_ADVANCE_STR", ip - 1); + break; + } + + case OP_ADVANCE_STR_APPENDCHAR: + { + char ch = code[ip]; + Con::printf("%i: OP_ADVANCE_STR_APPENDCHAR char=%c", ip - 1, ch); + ++ip; + break; + } + + case OP_ADVANCE_STR_COMMA: + { + Con::printf("%i: OP_ADVANCE_STR_COMMA", ip - 1); + break; + } + + case OP_ADVANCE_STR_NUL: + { + Con::printf("%i: OP_ADVANCE_STR_NUL", ip - 1); + break; + } + + case OP_REWIND_STR: + { + Con::printf("%i: OP_REWIND_STR", ip - 1); + break; + } + + case OP_TERMINATE_REWIND_STR: + { + Con::printf("%i: OP_TERMINATE_REWIND_STR", ip - 1); + break; + } + + case OP_COMPARE_STR: + { + Con::printf("%i: OP_COMPARE_STR", ip - 1); + break; + } + + case OP_PUSH: + { + Con::printf("%i: OP_PUSH", ip - 1); + break; + } + + case OP_PUSH_UINT: + { + Con::printf("%i: OP_PUSH_UINT", ip - 1); + break; + } + + case OP_PUSH_FLT: + { + Con::printf("%i: OP_PUSH_FLT", ip - 1); + break; + } + + case OP_PUSH_FRAME: + { + Con::printf("%i: OP_PUSH_FRAME count=%i", ip - 1, code[ip]); + ++ip; + break; + } + + case OP_ASSERT: + { + const char* message = (smInFunction ? functionStrings : globalStrings) + code[ip]; + Con::printf("%i: OP_ASSERT message=%s", ip - 1, message); + ++ip; + break; + } + + case OP_BREAK: + { + Con::printf("%i: OP_BREAK", ip - 1); + break; + } + + case OP_ITER_BEGIN: + { + StringTableEntry varName = CodeToSTE(code, ip); + U32 failIp = code[ip + 2]; + + Con::printf("%i: OP_ITER_BEGIN varName=%s failIp=%i", ip - 1, varName, failIp); + + ip += 3; + break; + } + + case OP_ITER_BEGIN_STR: + { + StringTableEntry varName = CodeToSTE(code, ip); + U32 failIp = code[ip + 2]; + + Con::printf("%i: OP_ITER_BEGIN varName=%s failIp=%i", ip - 1, varName, failIp); + + ip += 3; + break; + } + + case OP_ITER: + { + U32 breakIp = code[ip]; + + Con::printf("%i: OP_ITER breakIp=%i", ip - 1, breakIp); + + ++ip; + break; + } + + case OP_ITER_END: + { + Con::printf("%i: OP_ITER_END", ip - 1); + break; + } + + default: + Con::printf("%i: !!INVALID!!", ip - 1); + break; } } diff --git a/Engine/source/console/codeInterpreter.cpp b/Engine/source/console/codeInterpreter.cpp deleted file mode 100644 index 614eb8fec..000000000 --- a/Engine/source/console/codeInterpreter.cpp +++ /dev/null @@ -1,3018 +0,0 @@ -//----------------------------------------------------------------------------- -// 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" -#include "cinterface/cinterface.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. - if (subField == xyzw[0] || subField == rgba[0]) - dStrcpy(val, StringUnit::getUnit(prevVal, 0, " \t\n"), 128); - - else if (subField == xyzw[1] || subField == rgba[1]) - dStrcpy(val, StringUnit::getUnit(prevVal, 1, " \t\n"), 128); - - else if (subField == xyzw[2] || subField == rgba[2]) - dStrcpy(val, StringUnit::getUnit(prevVal, 2, " \t\n"), 128); - - else if (subField == xyzw[3] || subField == rgba[3]) - dStrcpy(val, StringUnit::getUnit(prevVal, 3, " \t\n"), 128); - - 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"), 128); - - else if (subField == xyzw[1] || subField == rgba[1]) - dStrcpy(val, StringUnit::setUnit(prevVal, 1, strValue, " \t\n"), 128); - - else if (subField == xyzw[2] || subField == rgba[2]) - dStrcpy(val, StringUnit::setUnit(prevVal, 2, strValue, " \t\n"), 128); - - else if (subField == xyzw[3] || subField == rgba[3]) - dStrcpy(val, StringUnit::setUnit(prevVal, 3, strValue, " \t\n"), 128); - - 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) -{ - dMemset(&mExec, 0, sizeof(mExec)); - dMemset(&mObjectCreationStack, 0, sizeof(mObjectCreationStack)); - dMemset(&mNSDocBlockClass, 0, sizeof(mNSDocBlockClass)); -} - -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) - break; - else if (ret == OPCodeReturn::breakContinue) - goto breakContinueLabel; - } - - if (telDebuggerOn && setFrame < 0) - TelDebugger->popStackFrame(); - - if (mPopFrame) - gEvalState.popFrame(); - - if (argv) - { - if (gEvalState.traceOn) - { - sTraceBuffer[0] = 0; - dStrcat(sTraceBuffer, "Leaving ", 1024); - - if (packageName) - { - dStrcat(sTraceBuffer, "[", 1024); - dStrcat(sTraceBuffer, packageName, 1024); - dStrcat(sTraceBuffer, "]", 1024); - } - if (thisNamespace && thisNamespace->mName) - { - dSprintf(sTraceBuffer + dStrlen(sTraceBuffer), (U32)(sizeof(sTraceBuffer) - dStrlen(sTraceBuffer)), - "%s::%s() - return %s", thisNamespace->mName, mThisFunctionName, STR.getStringValue()); - } - else - { - dSprintf(sTraceBuffer + dStrlen(sTraceBuffer), (U32)(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 ", 1024); - - if (mExec.packageName) - { - dStrcat(sTraceBuffer, "[", 1024); - dStrcat(sTraceBuffer, mExec.packageName, 1024); - dStrcat(sTraceBuffer, "]", 1024); - } - if (mExec.thisNamespace && mExec.thisNamespace->mName) - { - dSprintf(sTraceBuffer + dStrlen(sTraceBuffer), (U32)(sizeof(sTraceBuffer) - dStrlen(sTraceBuffer)), - "%s::%s(", mExec.thisNamespace->mName, mThisFunctionName); - } - else - { - dSprintf(sTraceBuffer + dStrlen(sTraceBuffer), (U32)(sizeof(sTraceBuffer) - dStrlen(sTraceBuffer)), - "%s(", mThisFunctionName); - } - for (S32 i = 0; i < wantedArgc; i++) - { - dStrcat(sTraceBuffer, mExec.argv[i + 1], 1024); - if (i != wantedArgc - 1) - dStrcat(sTraceBuffer, ", ", 1024); - } - dStrcat(sTraceBuffer, ")", 1024); - 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; iinsert(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(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(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(parent); - if (parent_db) - { - SimDataBlock* currentNewObject_db = dynamic_cast(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(parent); - if (parent_db) - { - SimDataBlock* currentNewObject_db = dynamic_cast(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(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(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(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(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, 256); - mCurField = CodeToSTE(mCodeBlock->code, ip); - curFieldArray[0] = 0; - ip += 2; - return OPCodeReturn::success; -} - -OPCodeReturn CodeInterpreter::op_setcurfield_array(U32 &ip) -{ - dStrcpy(curFieldArray, STR.getStringValue(), 256); - 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, 256); - 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 (!CInterface::GetCInterface().isMethod(fnNamespace, fnName) && !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 fnNamespace = CodeToSTE(mCodeBlock->code, ip + 2); - 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; - - bool cFunctionRes = false; - const char* cRetRes = NULL; - - if (callType == FuncCallExprNode::FunctionCall) - { - if (!mNSEntry) - mNSEntry = Namespace::global()->lookup(fnName); - - StringStackWrapper args(mCallArgc, mCallArgv); - cRetRes = CInterface::CallFunction(fnNamespace, fnName, args.argv + 1, args.argc - 1, &cFunctionRes); - } - 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(gEvalState.thisObject); - if (pComponent) - componentReturnValue = pComponent->callMethodArgList(mCallArgc, mCallArgv, false); - } - - ns = gEvalState.thisObject->getNamespace(); - if (ns) - mNSEntry = ns->lookup(fnName); - else - mNSEntry = NULL; - - StringStackWrapper args(mCallArgc, mCallArgv); - cRetRes = CInterface::CallMethod(gEvalState.thisObject, fnName, args.argv + 2, args.argc - 2, &cFunctionRes); - } - 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 (!cFunctionRes && (!mNSEntry || mExec.noCalls)) - { - if (!mExec.noCalls && !(routingId == MethodOnComponent)) - { - if (callType == FuncCallExprNode::MethodCall) - { - if (gEvalState.thisObject != NULL) - { - // Try to use the name instead of the id - StringTableEntry name = gEvalState.thisObject->getName() ? gEvalState.thisObject->getName() : gEvalState.thisObject->getIdString(); - Con::warnf(ConsoleLogEntry::General, "%s: Unknown method %s.%s Namespace List: %s", mCodeBlock->getFileLine(ip - 6), name, fnName, Con::getNamespaceList(ns)); - } - else - { - // NULL. - Con::warnf(ConsoleLogEntry::General, "%s: Unknown method NULL.%s", mCodeBlock->getFileLine(ip - 6), fnName); - } - } - else if (callType == FuncCallExprNode::ParentCall) - { - Con::warnf(ConsoleLogEntry::General, "%s: Unknown parent call %s.", mCodeBlock->getFileLine(ip - 6), fnName); - } - else - { - Con::warnf(ConsoleLogEntry::General, "%s: Unknown function %s.", mCodeBlock->getFileLine(ip - 6), fnName); - } - } - 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 (cFunctionRes || mNSEntry->mType == Namespace::Entry::ConsoleFunctionType) - { - ConsoleValue retVal; - ConsoleValueRef ret; - if (cFunctionRes) - { - retVal.init(); - ret.value = &retVal; - retVal.setStackStringValue(cRetRes); - } - else 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 function %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 = ""; - -#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 ? mThisObject->getNamespace() : NULL; - if (ns) - mNSEntry = ns->lookup(fnName); - else - mNSEntry = NULL; - - if (!mNSEntry || mExec.noCalls) - { - if (!mExec.noCalls) - { - if (mThisObject) - { - // Try to use the name instead of the id - StringTableEntry name = mThisObject->getName() ? mThisObject->getName() : mThisObject->getIdString(); - Con::warnf(ConsoleLogEntry::General, "%s: Unknown method %s.%s Namespace List: %s", mCodeBlock->getFileLine(ip - 6), name, fnName, Con::getNamespaceList(ns)); - } - else - { - // At least let the scripter know that they access the object. - Con::warnf(ConsoleLogEntry::General, "%s: Unknown method NULL.%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 = 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]; - - if (varName[0] == '$') - iter.mVariable = gEvalState.globalVars.add(varName); - else - 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; -} diff --git a/Engine/source/console/codeInterpreter.h b/Engine/source/console/codeInterpreter.h deleted file mode 100644 index 133222726..000000000 --- a/Engine/source/console/codeInterpreter.h +++ /dev/null @@ -1,262 +0,0 @@ -//----------------------------------------------------------------------------- -// 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 \ No newline at end of file diff --git a/Engine/source/console/compiledEval.cpp b/Engine/source/console/compiledEval.cpp index 47f5717ad..1d9ae968c 100644 --- a/Engine/source/console/compiledEval.cpp +++ b/Engine/source/console/compiledEval.cpp @@ -1,5 +1,7 @@ //----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC +// Copyright (c) 2013 GarageGames, LLC +// Copyright (c) 2015 Faust Logic, Inc. +// Copyright (c) 2021 TGEMIT Authors & Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to @@ -40,8 +42,8 @@ #include "util/messaging/message.h" #include "core/frameAllocator.h" -#include "console/codeInterpreter.h" #include "console/returnBuffer.h" +#include "console/consoleValueStack.h" #ifndef TORQUE_TGB_ONLY #include "materials/materialDefinition.h" @@ -50,13 +52,71 @@ using namespace Compiler; +enum EvalConstants +{ + MaxStackSize = 1024, + FieldBufferSizeString = 2048, + FieldBufferSizeNumeric = 128, + MethodOnComponent = -2 +}; + +/// 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. + const char* mString; + + /// Current parsing position. + U32 mIndex; + }; + union + { + ObjectPos mObj; + StringPos mStr; + } mData; +}; + +ConsoleValueStack<4096> gCallStack; + +StringStack STR; + +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]; + namespace Con { // Current script file name and root, these are registered as // console variables. extern StringTableEntry gCurrentFile; extern StringTableEntry gCurrentRoot; - extern S32 gObjectCopyFailures; } namespace Con @@ -79,6 +139,124 @@ namespace Con } } +// 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"), 128); + + else if (subField == xyzw[1] || subField == rgba[1]) + dStrcpy(val, StringUnit::getUnit(prevVal, 1, " \t\n"), 128); + + else if (subField == xyzw[2] || subField == rgba[2]) + dStrcpy(val, StringUnit::getUnit(prevVal, 2, " \t\n"), 128); + + else if (subField == xyzw[3] || subField == rgba[3]) + dStrcpy(val, StringUnit::getUnit(prevVal, 3, " \t\n"), 128); + + 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"), 128); + + else if (subField == xyzw[1] || subField == rgba[1]) + dStrcpy(val, StringUnit::setUnit(prevVal, 1, strValue, " \t\n"), 128); + + else if (subField == xyzw[2] || subField == rgba[2]) + dStrcpy(val, StringUnit::setUnit(prevVal, 2, strValue, " \t\n"), 128); + + else if (subField == xyzw[3] || subField == rgba[3]) + dStrcpy(val, StringUnit::setUnit(prevVal, 3, strValue, " \t\n"), 128); + + if (val[0] != 0) + { + // Update the field or variable. + if (object && field) + object->setDataField(field, 0, val); + else if (gEvalState.currentVariable) + gEvalState.setStringVariable(val); + } +} + //------------------------------------------------------------ F64 consoleStringToNumber(const char *str, StringTableEntry file, U32 line) @@ -239,38 +417,1717 @@ void ExprEvalState::setStringVariable(const char *val) currentVariable->setStringValue(val); } -void ExprEvalState::setStringStackPtrVariable(StringStackPtr str) -{ - AssertFatal(currentVariable != NULL, "Invalid evaluator state - trying to set null variable!"); - currentVariable->setStringStackPtrValue(str); -} +//----------------------------------------------------------------------------- -void ExprEvalState::setCopyVariable() +U32 gExecCount = 0; +void CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNamespace, U32 argc, ConsoleValue* argv, bool noCalls, StringTableEntry packageName, ConsoleValue& returnValue, S32 setFrame) { - if (copyVariable) +#ifdef TORQUE_DEBUG + U32 stackStart = STR.mStartStackSize; + gExecCount++; +#endif + + const dsize_t TRACE_BUFFER_SIZE = 1024; + static char traceBuffer[TRACE_BUFFER_SIZE]; + U32 i; + + U32 iterDepth = 0; + + incRefCount(); + F64* curFloatTable; + char* curStringTable; + S32 curStringTableLen = 0; //clint to ensure we dont overwrite it + STR.clearFunctionOffset(); + StringTableEntry thisFunctionName = NULL; + bool popFrame = false; + if (argv) { - switch (copyVariable->value.type) + // assume this points into a function decl: + U32 fnArgc = code[ip + 2 + 6]; + U32 regCount = code[ip + 2 + 7]; + thisFunctionName = CodeToSTE(code, ip); + S32 wantedArgc = getMin(argc - 1, fnArgc); // argv[0] is func name + if (gEvalState.traceOn) { - case ConsoleValue::TypeInternalInt: - currentVariable->setIntValue(copyVariable->getIntValue()); + traceBuffer[0] = 0; + dStrcat(traceBuffer, "Entering ", TRACE_BUFFER_SIZE); + if (packageName) + { + dStrcat(traceBuffer, "[", TRACE_BUFFER_SIZE); + dStrcat(traceBuffer, packageName, TRACE_BUFFER_SIZE); + dStrcat(traceBuffer, "]", TRACE_BUFFER_SIZE); + } + 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].getString(), TRACE_BUFFER_SIZE); + if (i != wantedArgc - 1) + dStrcat(traceBuffer, ", ", TRACE_BUFFER_SIZE); + } + dStrcat(traceBuffer, ")", TRACE_BUFFER_SIZE); + Con::printf("%s", traceBuffer); + } + gEvalState.pushFrame(thisFunctionName, thisNamespace, regCount); + popFrame = true; + for (i = 0; i < wantedArgc; i++) + { + S32 reg = code[ip + (2 + 6 + 1 + 1) + i]; + ConsoleValue& value = argv[i + 1]; + switch (value.getType()) + { + case ConsoleValueType::cvString: + gEvalState.setLocalStringVariable(reg, value.getString(), dStrlen(value.getString())); break; - case ConsoleValue::TypeInternalFloat: - currentVariable->setFloatValue(copyVariable->getFloatValue()); + case ConsoleValueType::cvInteger: + gEvalState.setLocalIntVariable(reg, value.getInt()); + break; + case ConsoleValueType::cvFloat: + gEvalState.setLocalFloatVariable(reg, value.getFloat()); + break; + case ConsoleValueType::cvSTEntry: + gEvalState.setLocalStringTableEntryVariable(reg, value.getString()); break; default: - currentVariable->setStringValue(copyVariable->getStringValue()); - break; + AssertFatal(false, avar("Invalid local variable type. Type was: %i", value.getType())); + } + } + ip = ip + fnArgc + (2 + 6 + 1 + 1); + curFloatTable = functionFloats; + curStringTable = functionStrings; + curStringTableLen = functionStringsMaxLen; + } + else + { + curFloatTable = globalFloats; + curStringTable = globalStrings; + curStringTableLen = globalStringsMaxLen; + + // Do we want this code to execute using a new stack frame? + if (setFrame < 0) + { + gEvalState.pushFrame(NULL, NULL, 0); + gCallStack.pushFrame(0); + popFrame = true; + } + else if (!gEvalState.stack.empty()) + { + // 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.stack.size() - setFrame - 1; + gEvalState.pushFrameRef(stackIndex); + popFrame = true; } } -} - -//------------------------------------------------------------ - - -ConsoleValueRef CodeBlock::exec(U32 ip, const char *functionName, Namespace *thisNamespace, U32 argc, ConsoleValueRef *argv, bool noCalls, StringTableEntry packageName, S32 setFrame) -{ - CodeInterpreter interpreter(this); - return interpreter.exec(ip, functionName, thisNamespace, argc, argv, noCalls, packageName, setFrame); + + // 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; + U32 failJump; + StringTableEntry fnName; + StringTableEntry fnNamespace, fnPackage; + + static const U32 objectCreationStackSize = 32; + U32 objectCreationStackIndex = 0; + struct { + SimObject* newObject; + U32 failJump; + } objectCreationStack[objectCreationStackSize]; + + SimObject* currentNewObject = 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]; + + S32 callArgc; + ConsoleValue* 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; + S32 reg; + + // 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 valBuffer(VAL_BUFFER_SIZE); + + for (;;) + { + U32 instruction = code[ip++]; + 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(); + if (fnNamespace == NULL && fnPackage == NULL) + ns = Namespace::global(); + else + ns = Namespace::find(fnNamespace, fnPackage); + ns->addFunction(fnName, this, hasBody ? ip : 0);// 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. + gCallStack.argvc(NULL, callArgc, &callArgv); + AssertFatal(callArgc - 3 >= 0, avar("Call Arg needs at least 3, only has %d", callArgc)); + const char* objectName = callArgv[2].getString(); + + // 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].getString())) + { + Con::errorf(ConsoleLogEntry::General, "Cannot re-declare data block %s with a different class.", objectName); + ip = failJump; + gCallStack.popFrame(); + break; + } + + // If there was one, set the currentNewObject and move on. + if (db) + currentNewObject = db; + } + else if (!isInternal) + { + 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; + gCallStack.popFrame(); + break; + } + + SimObject* obj = Sim::findObject((const char*)objectName); + if (obj) + { + if (isSingleton) + { + // Make sure we're not trying to change types + if (dStricmp(obj->getClassName(), callArgv[1].getString()) != 0) + { + Con::errorf(ConsoleLogEntry::General, "%s: Cannot re-declare object [%s] with a different class [%s] - was [%s].", + getFileLine(ip), objectName, callArgv[1].getString(), obj->getClassName()); + ip = failJump; + gCallStack.popFrame(); + break; + } + + // We're creating a singleton, so use the found object instead of creating a new object. + currentNewObject = obj; + Con::warnf("%s: Singleton Object was already created with name %s. Using existing object.", + getFileLine(ip), objectName); + } + } + } + + gCallStack.popFrame(); + + if (!currentNewObject) + { + // Well, looks like we have to create a new object. + ConsoleObject* object = ConsoleObject::create(callArgv[1].getString()); + + // Deal with failure! + if (!object) + { + Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-conobject class %s.", getFileLine(ip - 1), callArgv[1].getString()); + ip = failJump; + break; + } + + // Do special datablock init if appropros + if (isDataBlock) + { + SimDataBlock* dataBlock = dynamic_cast(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 - 1), callArgv[1].getString()); + + // Clean up... + delete object; + ip = failJump; + break; + } + } + + // Finally, set currentNewObject to point to the new one. + currentNewObject = dynamic_cast(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 - 1), callArgv[1].getString()); + delete object; + ip = failJump; + break; + } + + // Set the declaration line + currentNewObject->setDeclarationLine(lineNumber); + + // Set the file that this object was created in + currentNewObject->setFilename(this->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(parent); + if (parent_db) + { + SimDataBlock* currentNewObject_db = dynamic_cast(currentNewObject); + if (currentNewObject_db) + currentNewObject_db->copySubstitutionsFrom(parent_db); + } + } + else + { + Con::errorf(ConsoleLogEntry::General, "%s: Unable to find parent object %s for %s.", getFileLine(ip - 1), objParent, callArgv[1].getString()); + 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 ); + } + + // Do the constructor parameters. + if (!currentNewObject->processArguments(callArgc - 3, callArgv + 3)) + { + delete currentNewObject; + currentNewObject = NULL; + ip = failJump; + break; + } + + // 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(parent); + if (parent_db) + { + SimDataBlock* currentNewObject_db = dynamic_cast(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, callArgv[1].getString()); + } + } + } + + // 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()); + + // Make sure it wasn't already added, then add it. + if (currentNewObject == NULL) + { + break; + } + + bool isMessage = dynamic_cast(currentNewObject) != NULL; + + if (currentNewObject->isProperlyAdded() == false) + { + bool ret = false; + if (isMessage) + { + 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 - 2), currentNewObject->getName(), currentNewObject->getClassName()); + delete currentNewObject; + ip = failJump; + break; + } + } + + // Are we dealing with a datablock? + SimDataBlock* dataBlock = dynamic_cast(currentNewObject); + String errorStr; + + // If so, preload it. + if (dataBlock && !dataBlock->preload(true, errorStr)) + { + Con::errorf(ConsoleLogEntry::General, "%s: preload failed for %s: %s.", getFileLine(ip - 2), + currentNewObject->getName(), errorStr.c_str()); + dataBlock->deleteObject(); + ip = failJump; + break; + } + + // What group will we be added to, if any? + U32 groupAddId = (U32)intStack[_UINT]; + SimGroup* grp = NULL; + SimSet* set = 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() == NULL) + 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) + S32 id = currentNewObject->getId(); + if (placeAtRoot) + intStack[_UINT] = id; + else + intStack[++_UINT] = id; + + 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: + + if (iterDepth > 0) + { + // Clear iterator state. + while (iterDepth > 0) + { + iterStack[--_ITER].mIsStringIter = false; + --iterDepth; + } + + const char* retVal = STR.getStringValue(); + STR.rewind(); + + returnValue.setString(retVal, STR.mLen); + //STR.setStringValue(returnValue); // Not nice but works. + } + + goto execFinished; + + case OP_RETURN_FLT: + + if (iterDepth > 0) + { + // Clear iterator state. + while (iterDepth > 0) + { + iterStack[--_ITER].mIsStringIter = false; + --iterDepth; + } + + } + + returnValue.setFloat(floatStack[_FLT]); + _FLT--; + + goto execFinished; + + case OP_RETURN_UINT: + + if (iterDepth > 0) + { + // Clear iterator state. + while (iterDepth > 0) + { + iterStack[--_ITER].mIsStringIter = false; + --iterDepth; + } + } + + returnValue.setInt(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_INC: + reg = code[ip++]; + gEvalState.setLocalFloatVariable(reg, gEvalState.getLocalFloatVariable(reg) + 1.0); + 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_SAVEVAR_UINT: + gEvalState.setIntVariable((S32)intStack[_UINT]); + break; + + case OP_SAVEVAR_FLT: + gEvalState.setFloatVariable(floatStack[_FLT]); + break; + + case OP_SAVEVAR_STR: + gEvalState.setStringVariable(STR.getStringValue()); + break; + + case OP_LOAD_LOCAL_VAR_UINT: + reg = code[ip++]; + intStack[_UINT + 1] = gEvalState.getLocalIntVariable(reg); + _UINT++; + break; + + case OP_LOAD_LOCAL_VAR_FLT: + reg = code[ip++]; + floatStack[_FLT + 1] = gEvalState.getLocalFloatVariable(reg); + _FLT++; + break; + + case OP_LOAD_LOCAL_VAR_STR: + reg = code[ip++]; + val = gEvalState.getLocalStringVariable(reg); + STR.setStringValue(val); + break; + + case OP_SAVE_LOCAL_VAR_UINT: + reg = code[ip++]; + gEvalState.setLocalIntVariable(reg, (S32)intStack[_UINT]); + break; + + case OP_SAVE_LOCAL_VAR_FLT: + reg = code[ip++]; + gEvalState.setLocalFloatVariable(reg, floatStack[_FLT]); + break; + + case OP_SAVE_LOCAL_VAR_STR: + reg = code[ip++]; + gEvalState.setLocalStringVariable(reg, STR.getStringValue(), (S32)STR.mLen); + 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 wasnt found + if (curObject) + { + SimGroup* group = dynamic_cast(curObject); + if (group) + { + StringTableEntry intName = StringTable->insert(STR.getStringValue()); + bool recurse = code[ip - 1]; + SimObject* obj = group->findObjectByInternalName(intName, recurse); + intStack[_UINT + 1] = obj ? obj->getId() : 0; + _UINT++; + } + else + { + Con::errorf(ConsoleLogEntry::Script, "%s: Attempt to use -> on non-group %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, 256); + curField = CodeToSTE(code, ip); + curFieldArray[0] = 0; + ip += 2; + break; + + case OP_SETCURFIELD_ARRAY: + dStrcpy(curFieldArray, STR.getStringValue(), 256); + 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? + char buff[FieldBufferSizeNumeric]; + memset(buff, 0, sizeof(buff)); + getFieldComponent(prevObject, prevField, prevFieldArray, curField, buff); + intStack[_UINT + 1] = dAtoi(buff); + } + _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? + char buff[FieldBufferSizeNumeric]; + memset(buff, 0, sizeof(buff)); + getFieldComponent(prevObject, prevField, prevFieldArray, curField, buff); + floatStack[_FLT + 1] = dAtof(buff); + } + _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? + char buff[FieldBufferSizeString]; + memset(buff, 0, sizeof(buff)); + getFieldComponent(prevObject, prevField, prevFieldArray, curField, buff); + STR.setStringValue(buff); + } + + break; + + case OP_SAVEFIELD_UINT: + STR.setIntValue((U32)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] = (F64)intStack[_UINT]; + _UINT--; + _FLT++; + break; + + case OP_UINT_TO_STR: + STR.setIntValue((U32)intStack[_UINT]); + _UINT--; + break; + + case OP_UINT_TO_NONE: + _UINT--; + 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: + { + // 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); + fnNamespace = CodeToSTE(code, ip + 2); + U32 callType = code[ip + 4]; + + //if this is called from inside a function, append the ip and codeptr + if (!gEvalState.stack.empty()) + { + gEvalState.stack.last()->code = this; + gEvalState.stack.last()->ip = ip - 1; + } + + ip += 5; + gCallStack.argvc(fnName, callArgc, &callArgv); + + if (callType == FuncCallExprNode::FunctionCall) + { + // Note: This works even if the function was in a package. Reason being is when + // activatePackage() is called, it swaps the namespaceEntry into the global namespace + // (and reverts it when deactivatePackage is called). Method or Static related ones work + // as expected, as the namespace is resolved on the fly. + nsEntry = Namespace::global()->lookup(fnName); + if (!nsEntry) + { + Con::warnf(ConsoleLogEntry::General, + "%s: Unable to find function %s", + getFileLine(ip - 4), fnName); + //STR.popFrame(); + gCallStack.popFrame(); + break; + } + } + else if (callType == FuncCallExprNode::StaticCall) + { + // Try to look it up. + ns = Namespace::find(fnNamespace); + nsEntry = ns->lookup(fnName); + if (!nsEntry) + { + Con::warnf(ConsoleLogEntry::General, + "%s: Unable to find function %s%s%s", + getFileLine(ip - 4), fnNamespace ? fnNamespace : "", + fnNamespace ? "::" : "", fnName); + //STR.popFrame(); + gCallStack.popFrame(); + break; + } + } + else if (callType == FuncCallExprNode::MethodCall) + { + saveObject = gEvalState.thisObject; + + // Optimization: If we're an integer, we can lookup the value by SimObjectId + const ConsoleValue& simObjectLookupValue = callArgv[1]; + if (simObjectLookupValue.getType() == ConsoleValueType::cvInteger) + gEvalState.thisObject = Sim::findObject(static_cast(simObjectLookupValue.getInt())); + else + gEvalState.thisObject = Sim::findObject(simObjectLookupValue.getString()); + + if (gEvalState.thisObject == NULL) + { + Con::warnf( + ConsoleLogEntry::General, + "%s: Unable to find object: '%s' attempting to call function '%s'", + getFileLine(ip - 6), + simObjectLookupValue.getString(), + fnName + ); + //STR.popFrame(); + gCallStack.popFrame(); + STR.setStringValue(""); + break; + } + + 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; + } + } + + if (!nsEntry || noCalls) + { + if (!noCalls) + { + Con::warnf(ConsoleLogEntry::General, "%s: Unknown command %s.", getFileLine(ip - 4), 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)); + } + } + gCallStack.popFrame(); + STR.setStringValue(""); + STR.setStringValue(""); + break; + } + if (nsEntry->mType == Namespace::Entry::ConsoleFunctionType) + { + if (nsEntry->mFunctionOffset) + { + ConsoleValue ret; + nsEntry->mCode->exec(nsEntry->mFunctionOffset, fnName, nsEntry->mNamespace, callArgc, callArgv, false, nsEntry->mPackage, ret); + STR.setStringValue(ret.getString()); + } + else // no body + STR.setStringValue(""); + + gCallStack.popFrame(); + } + else + { + if ((nsEntry->mMinArgs && S32(callArgc) < nsEntry->mMinArgs) || (nsEntry->mMaxArgs && S32(callArgc) > nsEntry->mMaxArgs)) + { + const char* nsName = ns ? ns->mName : ""; + Con::warnf(ConsoleLogEntry::Script, "%s: %s::%s - wrong number of arguments.", getFileLine(ip - 4), nsName, fnName); + Con::warnf(ConsoleLogEntry::Script, "%s: usage: %s", getFileLine(ip - 4), nsEntry->mUsage); + gCallStack.popFrame(); + STR.setStringValue(""); + } + else + { + switch (nsEntry->mType) + { + case Namespace::Entry::StringCallbackType: + { + const char* ret = nsEntry->cb.mStringCallbackFunc(gEvalState.thisObject, callArgc, callArgv); + gCallStack.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); + gCallStack.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); + gCallStack.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::warnf(ConsoleLogEntry::General, "%s: Call to %s in %s uses result of void function call.", getFileLine(ip - 4), fnName, functionName); + gCallStack.popFrame(); + STR.setStringValue(""); + break; + } + case Namespace::Entry::BoolCallbackType: + { + bool result = nsEntry->cb.mBoolCallbackFunc(gEvalState.thisObject, callArgc, callArgv); + gCallStack.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: + gCallStack.pushString(STR.getStringValue(), STR.mLen); + break; + + case OP_PUSH_UINT: + gCallStack.pushInt((U32)intStack[_UINT--]); + break; + + case OP_PUSH_FLT: + gCallStack.pushFloat(floatStack[_FLT--]); + break; + + case OP_PUSH_FRAME: + gCallStack.pushFrame(code[ip++]); + 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.stack.empty(), "Empty eval stack on break!"); + gEvalState.stack.last()->code = this; + gEvalState.stack.last()->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.getStringValue(); + 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 = iter.mData.mStr.mString; + + 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(str)[endIndex] = '\0'; // We are on the string stack so this is okay. + iter.mVariable->setStringValue(&str[startIndex]); + const_cast(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: +#ifdef TORQUE_DEBUG + AssertFatal(returnValue.getType() == ConsoleValueType::cvNone, "returnValue was never set during script exec"); +#endif + + if (telDebuggerOn && setFrame < 0) + TelDebugger->popStackFrame(); + + if (popFrame) + { + gEvalState.popFrame(); + } + + if (argv) + { + if (gEvalState.traceOn) + { + traceBuffer[0] = 0; + dStrcat(traceBuffer, "Leaving ", TRACE_BUFFER_SIZE); + + if (packageName) + { + dStrcat(traceBuffer, "[", TRACE_BUFFER_SIZE); + dStrcat(traceBuffer, packageName, TRACE_BUFFER_SIZE); + dStrcat(traceBuffer, "]", TRACE_BUFFER_SIZE); + } + if (thisNamespace && thisNamespace->mName) + { + dSprintf(traceBuffer + dStrlen(traceBuffer), sizeof(traceBuffer) - dStrlen(traceBuffer), + "%s::%s() - return %s", thisNamespace->mName, thisFunctionName, returnValue.getString()); + } + else + { + dSprintf(traceBuffer + dStrlen(traceBuffer), sizeof(traceBuffer) - dStrlen(traceBuffer), + "%s() - return %s", thisFunctionName, returnValue.getString()); + } + Con::printf("%s", traceBuffer); + } + } + else + { + delete[] const_cast(globalStrings); + delete[] globalFloats; + globalStrings = NULL; + globalFloats = NULL; + } + smCurrentCodeBlock = saveCodeBlock; + if (saveCodeBlock && saveCodeBlock->name) + { + Con::gCurrentFile = saveCodeBlock->name; + Con::gCurrentRoot = saveCodeBlock->modPath; + } + + decRefCount(); + +#ifdef TORQUE_DEBUG + 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 } //------------------------------------------------------------ diff --git a/Engine/source/console/compiler.h b/Engine/source/console/compiler.h index 26dc93c13..c58fff3e6 100644 --- a/Engine/source/console/compiler.h +++ b/Engine/source/console/compiler.h @@ -93,26 +93,28 @@ namespace Compiler OP_MUL, 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, OP_LOADVAR_STR, - OP_LOADVAR_VAR, OP_SAVEVAR_UINT, OP_SAVEVAR_FLT, OP_SAVEVAR_STR, - OP_SAVEVAR_VAR, + + OP_LOAD_LOCAL_VAR_UINT, + OP_LOAD_LOCAL_VAR_FLT, + OP_LOAD_LOCAL_VAR_STR, + + OP_SAVE_LOCAL_VAR_UINT, + OP_SAVE_LOCAL_VAR_FLT, + OP_SAVE_LOCAL_VAR_STR, OP_SETCUROBJECT, OP_SETCUROBJECT_NEW, @@ -121,8 +123,6 @@ namespace Compiler OP_SETCURFIELD, OP_SETCURFIELD_ARRAY, // 50 OP_SETCURFIELD_TYPE, - OP_SETCURFIELD_ARRAY_VAR, - OP_SETCURFIELD_THIS, OP_LOADFIELD_UINT, OP_LOADFIELD_FLT, @@ -141,19 +141,15 @@ namespace Compiler OP_UINT_TO_FLT, OP_UINT_TO_STR, OP_UINT_TO_NONE, - OP_COPYVAR_TO_NONE, OP_LOADIMMED_UINT, OP_LOADIMMED_FLT, OP_TAG_TO_STR, OP_LOADIMMED_STR, // 70 - OP_DOCBLOCK_STR, + OP_DOCBLOCK_STR, // 76 OP_LOADIMMED_IDENT, - OP_CALLFUNC_RESOLVE, OP_CALLFUNC, - OP_CALLFUNC_POINTER, - OP_CALLFUNC_THIS, OP_ADVANCE_STR, OP_ADVANCE_STR_APPENDCHAR, @@ -166,8 +162,6 @@ namespace Compiler OP_PUSH, // String OP_PUSH_UINT, // Integer OP_PUSH_FLT, // Float - OP_PUSH_VAR, // Variable - OP_PUSH_THIS, // This pointer OP_PUSH_FRAME, // Frame OP_ASSERT, diff --git a/Engine/source/console/console.cpp b/Engine/source/console/console.cpp index 39d4b204d..50bdb5391 100644 --- a/Engine/source/console/console.cpp +++ b/Engine/source/console/console.cpp @@ -271,8 +271,6 @@ StringTableEntry gCurrentFile; StringTableEntry gCurrentRoot; /// @} -S32 gObjectCopyFailures = -1; - bool alwaysUseDebugOutput = true; bool useTimestamp = false; bool useRealTimestamp = false; @@ -327,6 +325,7 @@ void init() // Setup the console types. ConsoleBaseType::initialize(); + ConsoleValue::init(); // And finally, the ACR... AbstractClassRep::initialize(); @@ -344,10 +343,6 @@ void init() addVariable( "instantGroup", TypeRealString, &gInstantGroup, "The group that objects will be added to when they are created.\n" "@ingroup Console\n"); - addVariable("Con::objectCopyFailures", TypeS32, &gObjectCopyFailures, "If greater than zero then it counts the number of object creation " - "failures based on a missing copy object and does not report an error..\n" - "@ingroup Console\n"); - // Current script file name and root addVariable( "Con::File", TypeString, &gCurrentFile, "The currently executing script file.\n" "@ingroup FileSystem\n"); @@ -1590,11 +1585,9 @@ ConsoleValueRef _internalExecute(SimObject *object, S32 argc, ConsoleValueRef ar ICallMethod *com = dynamic_cast(object); if(com) { - STR.pushFrame(); - CSTK.pushFrame(); + gCallStack.pushFrame(0); com->callMethodArgList(argc, argv, false); - STR.popFrame(); - CSTK.popFrame(); + gCallStack.popFrame(); } } @@ -2523,70 +2516,20 @@ DefineEngineFunction( logWarning, void, ( const char* message ),, //------------------------------------------------------------------------------ -extern ConsoleValueStack CSTK; - -ConsoleValueRef::ConsoleValueRef(const ConsoleValueRef &ref) -{ - value = ref.value; -} - -ConsoleValueRef& ConsoleValueRef::operator=(const ConsoleValueRef &newValue) -{ - value = newValue.value; - return *this; -} - -ConsoleValueRef& ConsoleValueRef::operator=(const char *newValue) -{ - AssertFatal(value, "value should not be NULL"); - value->setStringValue(newValue); - return *this; -} - -ConsoleValueRef& ConsoleValueRef::operator=(S32 newValue) -{ - AssertFatal(value, "value should not be NULL"); - value->setIntValue(newValue); - return *this; -} - -ConsoleValueRef& ConsoleValueRef::operator=(U32 newValue) -{ - AssertFatal(value, "value should not be NULL"); - value->setIntValue(newValue); - return *this; -} - -ConsoleValueRef& ConsoleValueRef::operator=(F32 newValue) -{ - AssertFatal(value, "value should not be NULL"); - value->setFloatValue(newValue); - return *this; -} - -ConsoleValueRef& ConsoleValueRef::operator=(F64 newValue) -{ - AssertFatal(value, "value should not be NULL"); - value->setFloatValue(newValue); - return *this; -} - -//------------------------------------------------------------------------------ - -StringStackWrapper::StringStackWrapper(int targc, ConsoleValueRef targv[]) +ConsoleValueToStringArrayWrapper::ConsoleValueToStringArrayWrapper(int targc, ConsoleValue *targv) { argv = new const char*[targc]; argc = targc; - for (int i=0; i bufferLen) - sval = (char *) dRealloc(sval, newLen); - - dStrcpy(sval, internalValue, newLen); - bufferLen = newLen; - - return sval; - } -} - -StringStackPtr ConsoleValue::getStringStackPtr() -{ - if (type == TypeInternalStringStackPtr) - return (uintptr_t)sval; - else - return (uintptr_t)-1; -} - -bool ConsoleValue::getBoolValue() -{ - if(type == TypeInternalString || type == TypeInternalStackString || type == TypeInternalStringStackPtr) - return dAtob(getStringValue()); - if(type == TypeInternalFloat) - return fval > 0; - else if(type == TypeInternalInt) - return ival > 0; - else { - const char *value = Con::getData(type, dataPtr, 0, enumTable); - return dAtob(value); - } -} - -void ConsoleValue::setIntValue(S32 val) -{ - setFloatValue(val); -} - -void ConsoleValue::setIntValue(U32 val) -{ - if(type <= TypeInternalString) - { - fval = (F32)val; - ival = val; - if(bufferLen > 0) - { - dFree(sval); - bufferLen = 0; - } - - sval = typeValueEmpty; - type = TypeInternalInt; - } - else - { - const char *dptr = Con::getData(TypeS32, &val, 0); - Con::setData(type, dataPtr, 0, 1, &dptr, enumTable); - } -} - -void ConsoleValue::setBoolValue(bool val) -{ - return setIntValue(val ? 1 : 0); -} - -void ConsoleValue::setFloatValue(F32 val) -{ - if(type <= TypeInternalString) - { - fval = val; - ival = static_cast(val); - if(bufferLen > 0) - { - dFree(sval); - bufferLen = 0; - } - sval = typeValueEmpty; - type = TypeInternalFloat; - } - else - { - const char *dptr = Con::getData(TypeF32, &val, 0); - Con::setData(type, dataPtr, 0, 1, &dptr, enumTable); - } } //------------------------------------------------------------------------------ diff --git a/Engine/source/console/consoleInternal.cpp b/Engine/source/console/consoleInternal.cpp index 420d5a033..a498be154 100644 --- a/Engine/source/console/consoleInternal.cpp +++ b/Engine/source/console/consoleInternal.cpp @@ -183,13 +183,13 @@ void Dictionary::exportVariables(const char *varString, const char *fileName, bo for (s = sortList.begin(); s != sortList.end(); s++) { - switch ((*s)->value.type) + switch ((*s)->value.getType()) { - case ConsoleValue::TypeInternalInt: - dSprintf(buffer, sizeof(buffer), "%s = %d;%s", (*s)->name, (*s)->value.ival, cat); + case ConsoleValueType::cvInteger: + dSprintf(buffer, sizeof(buffer), "%s = %d;%s", (*s)->name, (*s)->value.getInt(), cat); break; - case ConsoleValue::TypeInternalFloat: - dSprintf(buffer, sizeof(buffer), "%s = %g;%s", (*s)->name, (*s)->value.fval, cat); + case ConsoleValueType::cvFloat: + dSprintf(buffer, sizeof(buffer), "%s = %g;%s", (*s)->name, (*s)->value.getFloat(), cat); break; default: expandEscape(expandBuffer, (*s)->getStringValue()); @@ -243,13 +243,11 @@ void Dictionary::exportVariables(const char *varString, Vector *names, V if (values) { - switch ((*s)->value.type) + switch ((*s)->value.getType()) { - case ConsoleValue::TypeInternalInt: - values->push_back(String::ToString((*s)->value.ival)); - break; - case ConsoleValue::TypeInternalFloat: - values->push_back(String::ToString((*s)->value.fval)); + case ConsoleValueType::cvInteger: + case ConsoleValueType::cvFloat: + values->push_back(String((*s)->value.getString())); break; default: expandEscape(expandBuffer, (*s)->getStringValue()); @@ -470,7 +468,6 @@ char *typeValueEmpty = ""; Dictionary::Entry::Entry(StringTableEntry in_name) { name = in_name; - value.type = ConsoleValue::TypeInternalString; notify = NULL; nextEntry = NULL; mUsage = NULL; @@ -508,150 +505,6 @@ const char *Dictionary::getVariable(StringTableEntry name, bool *entValid) return ""; } -void ConsoleValue::setStringValue(const char * value) -{ - if (value == NULL) value = typeValueEmpty; - - if (type <= ConsoleValue::TypeInternalString) - { - // Let's not remove empty-string-valued global vars from the dict. - // If we remove them, then they won't be exported, and sometimes - // it could be necessary to export such a global. There are very - // few empty-string global vars so there's no performance-related - // need to remove them from the dict. - /* - if(!value[0] && name[0] == '$') - { - gEvalState.globalVars.remove(this); - return; - } - */ - if (value == typeValueEmpty) - { - if (bufferLen > 0) - { - dFree(sval); - bufferLen = 0; - } - - sval = typeValueEmpty; - fval = 0.f; - ival = 0; - type = TypeInternalString; - return; - } - - U32 stringLen = dStrlen(value); - - // If it's longer than 256 bytes, it's certainly not a number. - // - // (This decision may come back to haunt you. Shame on you if it - // does.) - if (stringLen < 256) - { - fval = dAtof(value); - ival = dAtoi(value); - } - else - { - fval = 0.f; - ival = 0; - } - - // may as well pad to the next cache line - U32 newLen = ((stringLen + 1) + 15) & ~15; - - if (bufferLen == 0) - sval = (char *)dMalloc(newLen); - else if (newLen > bufferLen) - sval = (char *)dRealloc(sval, newLen); - - type = TypeInternalString; - - bufferLen = newLen; - dStrcpy(sval, value, newLen); - } - else - Con::setData(type, dataPtr, 0, 1, &value, enumTable); -} - - -void ConsoleValue::setStackStringValue(const char *value) -{ - if (value == NULL) value = typeValueEmpty; - - if (type <= ConsoleValue::TypeInternalString) - { - // sval might still be temporarily present so we need to check and free it - if (bufferLen > 0) - { - dFree(sval); - bufferLen = 0; - } - - if (value == typeValueEmpty) - { - sval = typeValueEmpty; - fval = 0.f; - ival = 0; - type = TypeInternalString; - return; - } - - U32 stringLen = dStrlen(value); - if (stringLen < 256) - { - fval = dAtof(value); - ival = dAtoi(value); - } - else - { - fval = 0.f; - ival = 0; - } - - type = TypeInternalStackString; - sval = (char*)value; - bufferLen = 0; - } - else - Con::setData(type, dataPtr, 0, 1, &value, enumTable); -} - -void ConsoleValue::setStringStackPtrValue(StringStackPtr ptrValue) -{ - if (type <= ConsoleValue::TypeInternalString) - { - const char *value = StringStackPtrRef(ptrValue).getPtr(&STR); - if (bufferLen > 0) - { - dFree(sval); - bufferLen = 0; - } - - U32 stringLen = dStrlen(value); - if (stringLen < 256) - { - fval = dAtof(value); - ival = dAtoi(value); - } - else - { - fval = 0.f; - ival = 0; - } - - type = TypeInternalStringStackPtr; - sval = (char*)(value - STR.mBuffer); - bufferLen = 0; - } - else - { - const char *value = StringStackPtrRef(ptrValue).getPtr(&STR); - Con::setData(type, dataPtr, 0, 1, &value, enumTable); - } -} - S32 Dictionary::getIntVariable(StringTableEntry name, bool *entValid) { Entry *ent = lookup(name); diff --git a/Engine/source/console/consoleInternal.h b/Engine/source/console/consoleInternal.h index 129da9dfb..151a75ac2 100644 --- a/Engine/source/console/consoleInternal.h +++ b/Engine/source/console/consoleInternal.h @@ -324,17 +324,17 @@ public: inline U32 getIntValue() { - return value.getIntValue(); + return value.getInt(); } inline F32 getFloatValue() { - return value.getFloatValue(); + return value.getFloat(); } inline const char *getStringValue() { - return value.getStringValue(); + return value.getString(); } void setIntValue(U32 val) @@ -345,7 +345,7 @@ public: return; } - value.setIntValue(val); + value.setInt(val); // Fire off the notification if we have one. if (notify) @@ -360,23 +360,7 @@ public: return; } - value.setFloatValue(val); - - // Fire off the notification if we have one. - if (notify) - notify->trigger(); - } - - void setStringStackPtrValue(StringStackPtr newValue) - { - if (mIsConstant) - { - Con::errorf("Cannot assign value to constant '%s'.", name); - return; - } - - value.setStringStackPtrValue(newValue); - + value.setFloat(val); // Fire off the notification if we have one. if (notify) @@ -391,8 +375,7 @@ public: return; } - value.setStringValue(newValue); - + value.setString(newValue, dStrlen(newValue)); // Fire off the notification if we have one. if (notify) @@ -471,6 +454,18 @@ public: void validate(); }; +struct ConsoleValueFrame +{ + ConsoleValue* values; + bool isReference; + + ConsoleValueFrame(ConsoleValue* vals, bool isRef) + { + values = vals; + isReference = isRef; + } +}; + class ExprEvalState { public: @@ -499,6 +494,9 @@ public: /// an interior pointer that will become invalid when the object changes address. Vector< Dictionary* > stack; + Vector< ConsoleValueFrame > localStack; + ConsoleValueFrame* currentRegisterArray; // contains array at to top of localStack + /// Dictionary globalVars; @@ -511,10 +509,43 @@ public: void setIntVariable(S32 val); void setFloatVariable(F64 val); void setStringVariable(const char *str); - void setStringStackPtrVariable(StringStackPtr str); - void setCopyVariable(); - void pushFrame(StringTableEntry frameName, Namespace *ns); + TORQUE_FORCEINLINE S32 getLocalIntVariable(S32 reg) + { + return currentRegisterArray->values[reg].getInt(); + } + + TORQUE_FORCEINLINE F64 getLocalFloatVariable(S32 reg) + { + return currentRegisterArray->values[reg].getFloat(); + } + + TORQUE_FORCEINLINE const char* getLocalStringVariable(S32 reg) + { + return currentRegisterArray->values[reg].getString(); + } + + TORQUE_FORCEINLINE void setLocalIntVariable(S32 reg, S64 val) + { + currentRegisterArray->values[reg].setInt(val); + } + + TORQUE_FORCEINLINE void setLocalFloatVariable(S32 reg, F64 val) + { + currentRegisterArray->values[reg].setFloat(val); + } + + TORQUE_FORCEINLINE void setLocalStringVariable(S32 reg, const char* val, S32 len) + { + currentRegisterArray->values[reg].setString(val, len); + } + + TORQUE_FORCEINLINE void setLocalStringTableEntryVariable(S32 reg, StringTableEntry val) + { + currentRegisterArray->values[reg].setStringTableEntry(val); + } + + void pushFrame(StringTableEntry frameName, Namespace *ns, S32 regCount); void popFrame(); /// Puts a reference to an existing stack frame diff --git a/Engine/source/console/consoleLogger.cpp b/Engine/source/console/consoleLogger.cpp index fc2095eae..d68cdb6c0 100644 --- a/Engine/source/console/consoleLogger.cpp +++ b/Engine/source/console/consoleLogger.cpp @@ -79,18 +79,18 @@ void ConsoleLogger::initPersistFields() //----------------------------------------------------------------------------- -bool ConsoleLogger::processArguments( S32 argc, ConsoleValueRef *argv ) +bool ConsoleLogger::processArguments( S32 argc, ConsoleValue *argv ) { if( argc == 0 ) return false; bool append = false; - if( argc == 2 ) - append = dAtob( argv[1] ); + if (argc == 2) + append = argv[1].getBool(); mAppend = append; - mFilename = StringTable->insert( argv[0] ); + mFilename = StringTable->insert( argv[0].getString() ); if( init() ) { diff --git a/Engine/source/console/consoleLogger.h b/Engine/source/console/consoleLogger.h index 901f45b17..e969f3ac1 100644 --- a/Engine/source/console/consoleLogger.h +++ b/Engine/source/console/consoleLogger.h @@ -81,7 +81,7 @@ class ConsoleLogger : public SimObject /// // Example script constructor usage. /// %obj = new ConsoleLogger( objName, logFileName, [append = false] ); /// @endcode - bool processArguments( S32 argc, ConsoleValueRef *argv ); + bool processArguments( S32 argc, ConsoleValue *argv ); /// Default constructor, make sure to initalize ConsoleLogger(); diff --git a/Engine/source/console/consoleValueStack.h b/Engine/source/console/consoleValueStack.h new file mode 100644 index 000000000..b88804dd5 --- /dev/null +++ b/Engine/source/console/consoleValueStack.h @@ -0,0 +1,121 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2013 GarageGames, LLC +// Copyright (c) 2021 TGEMIT Authors & Contributors +// +// 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 _CONSOLE_CONSOLE_VALUE_STACK_H_ +#define _CONSOLE_CONSOLE_VALUE_STACK_H_ + +template +class ConsoleValueStack +{ + constexpr static S32 allocatorSize = sizeof(ConsoleValue) * StackSize; + + struct Frame + { + ConsoleValue* values; + S32 count; + S32 internalCounter; + }; + + Vector stack; + char* memory; + S32 sp; + + TORQUE_FORCEINLINE Frame alloc(S32 count) + { + AssertFatal(sp + count * sizeof(ConsoleValue) < allocatorSize, "ConsoleValueStack overflow"); + + ConsoleValue* ret = reinterpret_cast(memory + sp); + sp += count * sizeof(ConsoleValue); + + return { ret, count, 1 }; + } + + TORQUE_FORCEINLINE void deAlloc(S32 count) + { + sp -= count * sizeof(ConsoleValue); + AssertFatal(sp >= 0, "Popped ConsoleValueStack too far, underflow"); + } + +public: + ConsoleValueStack() + { + memory = (char*)dMalloc(allocatorSize); + for (S32 i = 0; i < allocatorSize; i += sizeof(ConsoleValue)) + { + constructInPlace(reinterpret_cast(memory + i)); + } + sp = 0; + } + + ~ConsoleValueStack() + { + dFree(memory); + } + + TORQUE_FORCEINLINE void pushFrame(S32 count) + { + AssertISV(count >= 0, "Must be >= 0 when pushing stack frame"); + + // +1 for function name in argv[0] + const Frame& frame = alloc(count + 1); + stack.push_back(frame); + } + + TORQUE_FORCEINLINE void popFrame() + { + AssertISV(stack.size() > 0, "Stack Underflow"); + + deAlloc(stack.last().count); + stack.pop_back(); + } + + TORQUE_FORCEINLINE void pushInt(S64 value) + { + Frame& frame = stack.last(); + frame.values[frame.internalCounter++].setInt(value); + } + + TORQUE_FORCEINLINE void pushFloat(F64 value) + { + Frame& frame = stack.last(); + frame.values[frame.internalCounter++].setFloat(value); + } + + TORQUE_FORCEINLINE void pushString(const char* value, S32 len) + { + Frame& frame = stack.last(); + frame.values[frame.internalCounter++].setString(value, len); + } + + TORQUE_FORCEINLINE void argvc(StringTableEntry fn, S32& argc, ConsoleValue** argv) + { + Frame& frame = stack.last(); + argc = frame.count; + + // First param is always function name + frame.values[0].setStringTableEntry(fn); + *argv = frame.values; + } +}; + +#endif diff --git a/Engine/source/console/sim.h b/Engine/source/console/sim.h index d43c14b1e..61ff469e0 100644 --- a/Engine/source/console/sim.h +++ b/Engine/source/console/sim.h @@ -125,15 +125,12 @@ namespace Sim SimDataBlockGroup *getDataBlockGroup(); SimGroup* getRootGroup(); - SimObject* findObject(ConsoleValueRef&); SimObject* findObject(SimObjectId); + SimObject* findObject(const ConsoleValue&); + SimObject* findObject(ConsoleValue*); SimObject* findObject(const char* name); SimObject* findObject(const char* fileName, S32 declarationLine); - template inline bool findObject(ConsoleValueRef &ref,T*&t) - { - t = dynamic_cast(findObject(ref)); - return t != NULL; - } + template inline bool findObject(SimObjectId iD,T*&t) { t = dynamic_cast(findObject(iD)); diff --git a/Engine/source/console/simManager.cpp b/Engine/source/console/simManager.cpp index fc8a77edd..b874f752e 100644 --- a/Engine/source/console/simManager.cpp +++ b/Engine/source/console/simManager.cpp @@ -328,11 +328,6 @@ SimObject* findObject(const char* fileName, S32 declarationLine) return gRootGroup->findObjectByLineNumber(fileName, declarationLine, true); } -SimObject* findObject(ConsoleValueRef &ref) -{ - return findObject((const char*)ref); -} - SimObject* findObject(const char* name) { PROFILE_SCOPE(SimFindObject); @@ -391,6 +386,24 @@ SimObject* findObject(const char* name) return obj->findObject(name + len + 1); } +SimObject* findObject(const ConsoleValue &val) +{ + if (val.getType() == ConsoleValueType::cvNone) + return NULL; + if (val.getType() == ConsoleValueType::cvInteger) + return findObject((SimObjectId)val.getInt()); + return findObject(val.getString()); +} + +SimObject* findObject(ConsoleValue* val) +{ + if (val->getType() == ConsoleValueType::cvNone) + return NULL; + if (val->getType() == ConsoleValueType::cvInteger) + return findObject((SimObjectId)val->getInt()); + return findObject(val->getString()); +} + SimObject* findObject(SimObjectId id) { return gIdDictionary->find(id); diff --git a/Engine/source/console/simSet.cpp b/Engine/source/console/simSet.cpp index 06024c2c6..32f564ff5 100644 --- a/Engine/source/console/simSet.cpp +++ b/Engine/source/console/simSet.cpp @@ -229,11 +229,16 @@ void SimSet::scriptSort( const String &scriptCallbackFn ) //----------------------------------------------------------------------------- -void SimSet::callOnChildren( const String &method, S32 argc, ConsoleValueRef argv[], bool executeOnChildGroups ) +void SimSet::callOnChildren( const String &method, S32 argc, ConsoleValue argv[], bool executeOnChildGroups ) { + // TODO(JTH): Implement + AssertISV(false, "TODO Implement"); + return; + + /* // Prep the arguments for the console exec... // Make sure and leave args[1] empty. - ConsoleValueRef args[21] = { }; + ConsoleValue args[21] = { }; ConsoleValue name_method; name_method.setStackStringValue(method.c_str()); args[0] = ConsoleValueRef::fromValue(&name_method); @@ -255,6 +260,7 @@ void SimSet::callOnChildren( const String &method, S32 argc, ConsoleValueRef arg childSet->callOnChildren( method, argc, argv, executeOnChildGroups ); } } + */ } //----------------------------------------------------------------------------- @@ -838,7 +844,7 @@ SimGroup* SimGroup::deepClone() //----------------------------------------------------------------------------- -bool SimGroup::processArguments(S32, ConsoleValueRef *argv) +bool SimGroup::processArguments(S32, ConsoleValue *argv) { return true; } diff --git a/Engine/source/console/simSet.h b/Engine/source/console/simSet.h index 01f636662..b1f8c3f24 100644 --- a/Engine/source/console/simSet.h +++ b/Engine/source/console/simSet.h @@ -218,7 +218,7 @@ class SimSet : public SimObject, public TamlChildren /// @} - void callOnChildren( const String &method, S32 argc, ConsoleValueRef argv[], bool executeOnChildGroups = true ); + void callOnChildren( const String &method, S32 argc, ConsoleValue argv[], bool executeOnChildGroups = true ); /// Return the number of objects in this set as well as all sets that are contained /// in this set and its children. @@ -464,7 +464,7 @@ class SimGroup: public SimSet virtual SimObject* findObject(const char* name); virtual void onRemove(); - virtual bool processArguments( S32 argc, ConsoleValueRef *argv ); + virtual bool processArguments( S32 argc, ConsoleValue *argv ); virtual SimObject* getObject(const S32& index); diff --git a/Engine/source/console/stringStack.cpp b/Engine/source/console/stringStack.cpp index 96aef1c86..cfe2d83f5 100644 --- a/Engine/source/console/stringStack.cpp +++ b/Engine/source/console/stringStack.cpp @@ -207,228 +207,3 @@ void StringStack::clearFrames() mStartStackSize = 0; mFunctionOffset = 0; } - - -void ConsoleValueStack::getArgcArgv(StringTableEntry name, U32 *argc, ConsoleValueRef **in_argv, bool popStackFrame /* = false */) -{ - U32 startStack = mStackFrames[mFrame-1]; - U32 argCount = getMin(mStackPos - startStack, (U32)MaxArgs - 1); - - *in_argv = mArgv; - mArgv[0].value = CSTK.pushStackString(name); - - for(U32 i = 0; i < argCount; i++) { - ConsoleValueRef *ref = &mArgv[i+1]; - ref->value = &mStack[startStack + i]; - } - argCount++; - - *argc = argCount; - - if(popStackFrame) - popFrame(); -} - -ConsoleValueStack::ConsoleValueStack() : -mFrame(0), -mStackPos(0) -{ - for (int i=0; itype) - { - case ConsoleValue::TypeInternalInt: - mStack[mStackPos++].setIntValue((S32)variable->getIntValue()); - case ConsoleValue::TypeInternalFloat: - mStack[mStackPos++].setFloatValue((F32)variable->getFloatValue()); - default: - mStack[mStackPos++].setStackStringValue(variable->getStringValue()); - } -} - -void ConsoleValueStack::pushValue(ConsoleValue &variable) -{ - if (mStackPos == ConsoleValueStack::MaxStackDepth) { - AssertFatal(false, "Console Value Stack is empty"); - return; - } - - switch (variable.type) - { - case ConsoleValue::TypeInternalInt: - mStack[mStackPos++].setIntValue((S32)variable.getIntValue()); - case ConsoleValue::TypeInternalFloat: - mStack[mStackPos++].setFloatValue((F32)variable.getFloatValue()); - case ConsoleValue::TypeInternalStringStackPtr: - mStack[mStackPos++].setStringStackPtrValue(variable.getStringStackPtr()); - default: - mStack[mStackPos++].setStringValue(variable.getStringValue()); - } -} - -ConsoleValue* ConsoleValueStack::reserveValues(U32 count) -{ - U32 startPos = mStackPos; - if (startPos+count >= ConsoleValueStack::MaxStackDepth) { - AssertFatal(false, "Console Value Stack is empty"); - return NULL; - } - - //Con::printf("[%i]CSTK reserveValues %i", mStackPos, count); - mStackPos += count; - return &mStack[startPos]; -} - -bool ConsoleValueStack::reserveValues(U32 count, ConsoleValueRef *outValues) -{ - U32 startPos = mStackPos; - if (startPos+count >= ConsoleValueStack::MaxStackDepth) { - AssertFatal(false, "Console Value Stack is empty"); - return false; - } - - //Con::printf("[%i]CSTK reserveValues %i", mStackPos, count); - for (U32 i=0; imBuffer + mOffset; } diff --git a/Engine/source/console/test/ScriptTest.cpp b/Engine/source/console/test/ScriptTest.cpp index 994606783..b0674765b 100644 --- a/Engine/source/console/test/ScriptTest.cpp +++ b/Engine/source/console/test/ScriptTest.cpp @@ -20,6 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- +#ifdef 0 #ifdef TORQUE_TESTS_ENABLED #include "testing/unitTesting.h" #include "platform/platform.h" @@ -393,3 +394,4 @@ TEST(Script, Basic_Package) } #endif +#endif diff --git a/Engine/source/console/test/consoleTest.cpp b/Engine/source/console/test/consoleTest.cpp index adea797a2..d1ced9ec9 100644 --- a/Engine/source/console/test/consoleTest.cpp +++ b/Engine/source/console/test/consoleTest.cpp @@ -1,3 +1,5 @@ +#ifdef 0 + #ifdef TORQUE_TESTS_ENABLED #include "testing/unitTesting.h" #include "platform/platform.h" @@ -253,3 +255,4 @@ TEST(Con, execute) } #endif +#endif diff --git a/Engine/source/console/test/engineAPITest.cpp b/Engine/source/console/test/engineAPITest.cpp index 48e780531..32981e260 100644 --- a/Engine/source/console/test/engineAPITest.cpp +++ b/Engine/source/console/test/engineAPITest.cpp @@ -1,3 +1,4 @@ +#if 0 #ifdef TORQUE_TESTS_ENABLED #include "testing/unitTesting.h" #include "platform/platform.h" @@ -147,4 +148,5 @@ TEST(EngineAPI, _EngineConsoleExecCallbackHelper) "All values should be printed in the correct order"; } -#endif \ No newline at end of file +#endif +#endif diff --git a/Engine/source/core/strings/stringFunctions.h b/Engine/source/core/strings/stringFunctions.h index 918273423..d0c91b734 100644 --- a/Engine/source/core/strings/stringFunctions.h +++ b/Engine/source/core/strings/stringFunctions.h @@ -200,6 +200,11 @@ inline F64 dAtod(const char *str) return strtod(str, NULL); } +inline S64 dAtol(const char* str) +{ + return strtol(str, NULL, 10); +} + inline char dToupper(const char c) { return toupper( c ); diff --git a/Engine/source/environment/waterObject.cpp b/Engine/source/environment/waterObject.cpp index 1d3da4aeb..f03bf0636 100644 --- a/Engine/source/environment/waterObject.cpp +++ b/Engine/source/environment/waterObject.cpp @@ -411,7 +411,7 @@ void WaterObject::inspectPostApply() setMaskBits( UpdateMask | WaveMask | TextureMask | SoundMask ); } -bool WaterObject::processArguments( S32 argc, ConsoleValueRef *argv ) +bool WaterObject::processArguments( S32 argc, ConsoleValue *argv ) { if( typeid( *this ) == typeid( WaterObject ) ) { diff --git a/Engine/source/environment/waterObject.h b/Engine/source/environment/waterObject.h index 94862e4c6..15e7b0d40 100644 --- a/Engine/source/environment/waterObject.h +++ b/Engine/source/environment/waterObject.h @@ -156,7 +156,7 @@ public: virtual bool onAdd(); virtual void onRemove(); virtual void inspectPostApply(); - virtual bool processArguments(S32 argc, ConsoleValueRef *argv); + virtual bool processArguments(S32 argc, ConsoleValue *argv); // NetObject virtual U32 packUpdate( NetConnection * conn, U32 mask, BitStream *stream ); diff --git a/Engine/source/gui/core/guiControl.cpp b/Engine/source/gui/core/guiControl.cpp index 7e0f27791..2011aa68b 100644 --- a/Engine/source/gui/core/guiControl.cpp +++ b/Engine/source/gui/core/guiControl.cpp @@ -319,7 +319,7 @@ void GuiControl::initPersistFields() //----------------------------------------------------------------------------- -bool GuiControl::processArguments(S32 argc, ConsoleValueRef *argv) +bool GuiControl::processArguments(S32 argc, ConsoleValue *argv) { // argv[0] - The GuiGroup to add this control to when it's created. // this is an optional parameter that may be specified at diff --git a/Engine/source/gui/core/guiControl.h b/Engine/source/gui/core/guiControl.h index 997213f75..e0b3c0a76 100644 --- a/Engine/source/gui/core/guiControl.h +++ b/Engine/source/gui/core/guiControl.h @@ -341,7 +341,7 @@ class GuiControl : public SimGroup GuiControl(); virtual ~GuiControl(); - virtual bool processArguments(S32 argc, ConsoleValueRef *argv); + virtual bool processArguments(S32 argc, ConsoleValue *argv); static void initPersistFields(); static void consoleInit(); diff --git a/Engine/source/gui/worldEditor/worldEditor.cpp b/Engine/source/gui/worldEditor/worldEditor.cpp index 1e4a795ce..cb0dffc3c 100644 --- a/Engine/source/gui/worldEditor/worldEditor.cpp +++ b/Engine/source/gui/worldEditor/worldEditor.cpp @@ -2858,17 +2858,17 @@ void WorldEditor::initPersistFields() //------------------------------------------------------------------------------ // These methods are needed for the console interfaces. -void WorldEditor::ignoreObjClass( U32 argc, ConsoleValueRef *argv ) +void WorldEditor::ignoreObjClass( U32 argc, ConsoleValue *argv ) { for(S32 i = 2; i < argc; i++) { - ClassInfo::Entry * entry = getClassEntry(argv[i]); + ClassInfo::Entry * entry = getClassEntry(argv[i].getString()); if(entry) entry->mIgnoreCollision = true; else { entry = new ClassInfo::Entry; - entry->mName = StringTable->insert(argv[i]); + entry->mName = StringTable->insert(argv[i].getString()); entry->mIgnoreCollision = true; if(!addClassEntry(entry)) delete entry; diff --git a/Engine/source/gui/worldEditor/worldEditor.h b/Engine/source/gui/worldEditor/worldEditor.h index 01c7d396c..afcdb599a 100644 --- a/Engine/source/gui/worldEditor/worldEditor.h +++ b/Engine/source/gui/worldEditor/worldEditor.h @@ -76,7 +76,7 @@ class WorldEditor : public EditTSCtrl Point3F p2; }; - void ignoreObjClass(U32 argc, ConsoleValueRef* argv); + void ignoreObjClass(U32 argc, ConsoleValue* argv); void clearIgnoreList(); static bool setObjectsUseBoxCenter( void *object, const char *index, const char *data ) { static_cast(object)->setObjectsUseBoxCenter( dAtob( data ) ); return false; }; diff --git a/Engine/source/platformWin32/winMath.cpp b/Engine/source/platformWin32/winMath.cpp index 3b6e3ec15..b273d25f0 100644 --- a/Engine/source/platformWin32/winMath.cpp +++ b/Engine/source/platformWin32/winMath.cpp @@ -55,31 +55,36 @@ DefineEngineStringlyVariadicFunction( mathInit, void, 1, 10, "( ... )" } for (argc--, argv++; argc; argc--, argv++) { - if (dStricmp(*argv, "DETECT") == 0) { + const char* str = (*argv).getString(); + if (dStricmp(str, "DETECT") == 0) { Math::init(0); return; } - if (dStricmp(*argv, "C") == 0) { + if (dStricmp(str, "C") == 0) { properties |= CPU_PROP_C; continue; } - if (dStricmp(*argv, "FPU") == 0) { + if (dStricmp(str, "FPU") == 0) { properties |= CPU_PROP_FPU; continue; } - if (dStricmp(*argv, "MMX") == 0) { + if (dStricmp(str, "MMX") == 0) { properties |= CPU_PROP_MMX; continue; } - if (dStricmp(*argv, "3DNOW") == 0) { + if (dStricmp(str, "3DNOW") == 0) { properties |= CPU_PROP_3DNOW; continue; } - if (dStricmp(*argv, "SSE") == 0) { + if (dStricmp(str, "SSE") == 0) { properties |= CPU_PROP_SSE; continue; } - Con::printf("Error: MathInit(): ignoring unknown math extension '%s'", argv->getStringValue()); + if (dStricmp(str, "SSE2") == 0) { + properties |= CPU_PROP_SSE2; + continue; + } + Con::printf("Error: MathInit(): ignoring unknown math extension '%s'", str); } Math::init(properties); } diff --git a/Engine/source/sfx/sfxSource.cpp b/Engine/source/sfx/sfxSource.cpp index abc5b35e1..47cab9f15 100644 --- a/Engine/source/sfx/sfxSource.cpp +++ b/Engine/source/sfx/sfxSource.cpp @@ -316,7 +316,7 @@ void SFXSource::initPersistFields() //----------------------------------------------------------------------------- -bool SFXSource::processArguments( S32 argc, ConsoleValueRef *argv ) +bool SFXSource::processArguments( S32 argc, ConsoleValue *argv ) { // Don't allow subclasses of this to be created via script. Force // usage of the SFXSystem functions. diff --git a/Engine/source/sfx/sfxSource.h b/Engine/source/sfx/sfxSource.h index 16ab6fd14..8d6bb129f 100644 --- a/Engine/source/sfx/sfxSource.h +++ b/Engine/source/sfx/sfxSource.h @@ -382,7 +382,7 @@ class SFXSource : public SimGroup /// We overload this to disable creation of /// a source via script 'new'. - virtual bool processArguments( S32 argc, ConsoleValueRef *argv ); + virtual bool processArguments( S32 argc, ConsoleValue *argv ); // Console getters/setters. static bool _setDescription( void *obj, const char *index, const char *data ); diff --git a/Engine/source/sfx/sfxTrack.cpp b/Engine/source/sfx/sfxTrack.cpp index 067a202ca..987650c0b 100644 --- a/Engine/source/sfx/sfxTrack.cpp +++ b/Engine/source/sfx/sfxTrack.cpp @@ -95,7 +95,7 @@ void SFXTrack::initPersistFields() //----------------------------------------------------------------------------- -bool SFXTrack::processArguments( S32 argc, ConsoleValueRef *argv ) +bool SFXTrack::processArguments( S32 argc, ConsoleValue *argv ) { if( typeid( *this ) == typeid( SFXTrack ) ) { diff --git a/Engine/source/sfx/sfxTrack.h b/Engine/source/sfx/sfxTrack.h index e30acd007..2beb5e3e6 100644 --- a/Engine/source/sfx/sfxTrack.h +++ b/Engine/source/sfx/sfxTrack.h @@ -61,7 +61,7 @@ class SFXTrack : public SimDataBlock StringTableEntry mParameters[ MaxNumParameters ]; /// Overload this to disable direct instantiation of this class via script 'new'. - virtual bool processArguments( S32 argc, ConsoleValueRef *argv ); + virtual bool processArguments( S32 argc, ConsoleValue *argv ); public: diff --git a/Engine/source/shaderGen/GLSL/customFeatureGLSL.cpp b/Engine/source/shaderGen/GLSL/customFeatureGLSL.cpp index 3b0467062..99414d133 100644 --- a/Engine/source/shaderGen/GLSL/customFeatureGLSL.cpp +++ b/Engine/source/shaderGen/GLSL/customFeatureGLSL.cpp @@ -238,7 +238,7 @@ void CustomFeatureGLSL::addVertTexCoord(String name) mVars.push_back(newVarHolder); } -void CustomFeatureGLSL::writeLine(String format, S32 argc, ConsoleValueRef * argv) +void CustomFeatureGLSL::writeLine(String format, S32 argc, ConsoleValue * argv) { //do the var/arg fetching here Vector varList; @@ -246,7 +246,7 @@ void CustomFeatureGLSL::writeLine(String format, S32 argc, ConsoleValueRef * arg for (U32 i = 0; i < argc; i++) { - String varName = argv[i].getStringValue(); + String varName = argv[i].getString(); Var* newVar = (Var*)LangElement::find(varName.c_str()); if (!newVar) { @@ -304,7 +304,7 @@ void CustomFeatureGLSL::writeLine(String format, S32 argc, ConsoleValueRef * arg if (!newVar) { //couldn't find that variable, bail out - Con::errorf("CustomShaderFeature::writeLine: unable to find variable %s, meaning it was not declared before being used!", argv[i].getStringValue()); + Con::errorf("CustomShaderFeature::writeLine: unable to find variable %s, meaning it was not declared before being used!", argv[i].getString()); return; } } diff --git a/Engine/source/shaderGen/GLSL/customFeatureGLSL.h b/Engine/source/shaderGen/GLSL/customFeatureGLSL.h index c2d0191cc..b8358a835 100644 --- a/Engine/source/shaderGen/GLSL/customFeatureGLSL.h +++ b/Engine/source/shaderGen/GLSL/customFeatureGLSL.h @@ -128,5 +128,5 @@ public: void addTexture(String name, String type, String samplerState, U32 arraySize); void addConnector(String name, String type, String elementName); void addVertTexCoord(String name); - void writeLine(String format, S32 argc, ConsoleValueRef* argv); + void writeLine(String format, S32 argc, ConsoleValue* argv); }; diff --git a/Engine/source/shaderGen/HLSL/customFeatureHLSL.cpp b/Engine/source/shaderGen/HLSL/customFeatureHLSL.cpp index fa0a3934e..91e2329c4 100644 --- a/Engine/source/shaderGen/HLSL/customFeatureHLSL.cpp +++ b/Engine/source/shaderGen/HLSL/customFeatureHLSL.cpp @@ -385,7 +385,7 @@ void CustomFeatureHLSL::addVertTexCoord(String name) mVars.push_back(newVarHolder); } -void CustomFeatureHLSL::writeLine(String format, S32 argc, ConsoleValueRef * argv) +void CustomFeatureHLSL::writeLine(String format, S32 argc, ConsoleValue *argv) { //do the var/arg fetching here Vector varList; @@ -393,7 +393,7 @@ void CustomFeatureHLSL::writeLine(String format, S32 argc, ConsoleValueRef * arg for (U32 i = 0; i < argc; i++) { - String varName = argv[i].getStringValue(); + String varName = argv[i].getString(); Var* newVar = (Var*)LangElement::find(varName.c_str()); if (!newVar) { @@ -451,7 +451,7 @@ void CustomFeatureHLSL::writeLine(String format, S32 argc, ConsoleValueRef * arg if (!newVar) { //couldn't find that variable, bail out - Con::errorf("CustomShaderFeature::writeLine: unable to find variable %s, meaning it was not declared before being used!", argv[i].getStringValue()); + Con::errorf("CustomShaderFeature::writeLine: unable to find variable %s, meaning it was not declared before being used!", argv[i].getString()); return; } } diff --git a/Engine/source/shaderGen/HLSL/customFeatureHLSL.h b/Engine/source/shaderGen/HLSL/customFeatureHLSL.h index dd1ad0a09..be89aeb50 100644 --- a/Engine/source/shaderGen/HLSL/customFeatureHLSL.h +++ b/Engine/source/shaderGen/HLSL/customFeatureHLSL.h @@ -128,5 +128,5 @@ public: void addTexture(String name, String type, String samplerState, U32 arraySize); void addConnector(String name, String type, String elementName); void addVertTexCoord(String name); - void writeLine(String format, S32 argc, ConsoleValueRef* argv); + void writeLine(String format, S32 argc, ConsoleValue* argv); }; diff --git a/Engine/source/shaderGen/customShaderFeature.cpp b/Engine/source/shaderGen/customShaderFeature.cpp index e17cdc088..c184cb128 100644 --- a/Engine/source/shaderGen/customShaderFeature.cpp +++ b/Engine/source/shaderGen/customShaderFeature.cpp @@ -189,7 +189,7 @@ bool CustomShaderFeatureData::hasFeature(String name) return false; } -void CustomShaderFeatureData::writeLine(String format, S32 argc, ConsoleValueRef* argv) +void CustomShaderFeatureData::writeLine(String format, S32 argc, ConsoleValue* argv) { #ifdef TORQUE_D3D11 if (GFX->getAdapterType() == GFXAdapterType::Direct3D11) diff --git a/Engine/source/shaderGen/customShaderFeature.h b/Engine/source/shaderGen/customShaderFeature.h index 57d91e989..fd76380c4 100644 --- a/Engine/source/shaderGen/customShaderFeature.h +++ b/Engine/source/shaderGen/customShaderFeature.h @@ -77,7 +77,7 @@ public: void addVertTexCoord(String name); bool hasFeature(String name); - void writeLine(String format, S32 argc, ConsoleValueRef *argv); + void writeLine(String format, S32 argc, ConsoleValue *argv); }; #endif