Fix stack balancing problems by refactoring execution calls

- Con::executef now uses a template
- All public execution functions now restore the console stack upon return
- Fixed bad parameters on some callbacks
- Reverts get*Arg behavior
This commit is contained in:
James Urquhart 2015-02-07 22:41:54 +00:00
parent b1ad72692c
commit f44a3f27d6
43 changed files with 1781 additions and 358 deletions

View file

@ -181,6 +181,7 @@ public:
fval = 0;
sval = typeValueEmpty;
bufferLen = 0;
type = TypeInternalString;
}
void cleanup()
@ -203,9 +204,8 @@ class ConsoleValueRef
{
public:
ConsoleValue *value;
const char *stringStackValue;
ConsoleValueRef() : value(0), stringStackValue(0) { ; }
ConsoleValueRef() : value(0) { ; }
~ConsoleValueRef() { ; }
ConsoleValueRef(const ConsoleValueRef &ref);
@ -216,8 +216,9 @@ public:
ConsoleValueRef(F32 value);
ConsoleValueRef(F64 value);
static ConsoleValueRef fromValue(ConsoleValue *value) { ConsoleValueRef ref; ref.value = value; return ref; }
const char *getStringValue() { return value ? value->getStringValue() : ""; }
const char *getStringArgValue();
inline U32 getIntValue() { return value ? value->getIntValue() : 0; }
inline S32 getSignedIntValue() { return value ? value->getSignedIntValue() : 0; }
@ -229,6 +230,7 @@ public:
inline operator U32() { return getIntValue(); }
inline operator S32() { return getSignedIntValue(); }
inline operator F32() { return getFloatValue(); }
inline operator bool() { return getBoolValue(); }
inline bool isString() { return value ? value->type >= ConsoleValue::TypeInternalStackString : true; }
inline bool isInt() { return value ? value->type == ConsoleValue::TypeInternalInt : false; }
@ -281,6 +283,7 @@ public:
class StringStackConsoleWrapper
{
public:
ConsoleValue *argvValue;
ConsoleValueRef *argv;
int argc;
@ -753,23 +756,9 @@ namespace Con
/// char* argv[] = {"abs", "-9"};
/// char* result = execute(2, argv);
/// @endcode
const char *execute(S32 argc, const char* argv[]);
const char *execute(S32 argc, ConsoleValueRef argv[]);
/// @see execute(S32 argc, const char* argv[])
// Note: this can't be ConsoleValueRef& since the compiler will confuse it with SimObject*
#define ARG ConsoleValueRef
const char *executef( ARG);
const char *executef( ARG, ARG);
const char *executef( ARG, ARG, ARG);
const char *executef( ARG, ARG, ARG, ARG);
const char *executef( ARG, ARG, ARG, ARG, ARG);
const char *executef( ARG, ARG, ARG, ARG, ARG, ARG);
const char *executef( ARG, ARG, ARG, ARG, ARG, ARG, ARG);
const char *executef( ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
const char *executef( ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
const char *executef( ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
#undef ARG
/// NOTE: this function restores the console stack on return.
ConsoleValueRef execute(S32 argc, const char* argv[]);
ConsoleValueRef execute(S32 argc, ConsoleValueRef argv[]);
/// Call a Torque Script member function of a SimObject from C/C++ code.
/// @param object Object on which to execute the method call.
@ -783,35 +772,23 @@ namespace Con
/// char* argv[] = {"setMode", "", "2"};
/// char* result = execute(mysimobject, 3, argv);
/// @endcode
const char *execute(SimObject *object, S32 argc, const char *argv[], bool thisCallOnly = false);
const char *execute(SimObject *object, S32 argc, ConsoleValueRef argv[], bool thisCallOnly = false);
/// @see execute(SimObject *, S32 argc, ConsoleValueRef argv[])
#define ARG ConsoleValueRef
const char *executef(SimObject *, ARG);
const char *executef(SimObject *, ARG, ARG);
const char *executef(SimObject *, ARG, ARG, ARG);
const char *executef(SimObject *, ARG, ARG, ARG, ARG);
const char *executef(SimObject *, ARG, ARG, ARG, ARG, ARG);
const char *executef(SimObject *, ARG, ARG, ARG, ARG, ARG, ARG);
const char *executef(SimObject *, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
const char *executef(SimObject *, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
const char *executef(SimObject *, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
const char *executef(SimObject *, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
const char *executef(SimObject *, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
#undef ARG
/// NOTE: this function restores the console stack on return.
ConsoleValueRef execute(SimObject *object, S32 argc, const char* argv[], bool thisCallOnly = false);
ConsoleValueRef execute(SimObject *object, S32 argc, ConsoleValueRef argv[], bool thisCallOnly = false);
/// Evaluate an arbitrary chunk of code.
///
/// @param string Buffer containing code to execute.
/// @param echo Should we echo the string to the console?
/// @param fileName Indicate what file this code is coming from; used in error reporting and such.
const char *evaluate(const char* string, bool echo = false, const char *fileName = NULL);
/// NOTE: This function restores the console stack on return.
ConsoleValueRef evaluate(const char* string, bool echo = false, const char *fileName = NULL);
/// Evaluate an arbitrary line of script.
///
/// This wraps dVsprintf(), so you can substitute parameters into the code being executed.
const char *evaluatef(const char* string, ...);
/// NOTE: This function restores the console stack on return.
ConsoleValueRef evaluatef(const char* string, ...);
/// @}
@ -831,14 +808,12 @@ namespace Con
char* getReturnBuffer( const StringBuilder& str );
char* getArgBuffer(U32 bufferSize);
ConsoleValueRef getFloatArg(F64 arg);
ConsoleValueRef getIntArg (S32 arg);
char* getStringArg( const char *arg );
char* getFloatArg(F64 arg);
char* getIntArg (S32 arg);
char* getStringArg( const char* arg );
char* getStringArg( const String& arg );
/// @}
void resetStackFrame();
/// @name Namespaces
/// @{
@ -872,21 +847,47 @@ namespace Con
/// @name Dynamic Type System
/// @{
///
/* void registerType( const char *typeName, S32 type, S32 size, GetDataFunction gdf, SetDataFunction sdf, bool isDatablockType = false );
void registerType( const char* typeName, S32 type, S32 size, bool isDatablockType = false );
void registerTypeGet( S32 type, GetDataFunction gdf );
void registerTypeSet( S32 type, SetDataFunction sdf );
const char *getTypeName(S32 type);
bool isDatablockType( S32 type ); */
void setData(S32 type, void *dptr, S32 index, S32 argc, const char **argv, const EnumTable *tbl = NULL, BitSet32 flag = 0);
const char *getData(S32 type, void *dptr, S32 index, const EnumTable *tbl = NULL, BitSet32 flag = 0);
const char *getFormattedData(S32 type, const char *data, const EnumTable *tbl = NULL, BitSet32 flag = 0);
/// @}
};
struct _EngineConsoleCallbackHelper;
template<typename P1> struct _EngineConsoleExecCallbackHelper;
namespace Con
{
/// @name Console Execution - executef
/// {
///
/// Implements a script function thunk which automatically converts parameters to relevant console types.
/// Can be used as follows:
/// - Con::executef("functionName", ...);
/// - Con::executef(mySimObject, "functionName", ...);
///
/// NOTE: if you get a rather cryptic template error coming through here, most likely you are trying to
/// convert a parameter which EngineMarshallType does not have a specialization for.
/// Another problem can occur if you do not include "console/simBase.h" and "console/engineAPI.h"
/// since _EngineConsoleExecCallbackHelper and SimConsoleThreadExecCallback are required.
///
/// @see _EngineConsoleExecCallbackHelper
///
template<typename A> ConsoleValueRef executef(A a) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(); }
template<typename A, typename B> ConsoleValueRef executef(A a, B b) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b); }
template<typename A, typename B, typename C> ConsoleValueRef executef(A a, B b, C c) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c); }
template<typename A, typename B, typename C, typename D> ConsoleValueRef executef(A a, B b, C c, D d) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c, d); }
template<typename A, typename B, typename C, typename D, typename E> ConsoleValueRef executef(A a, B b, C c, D d, E e) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c, d, e); }
template<typename A, typename B, typename C, typename D, typename E, typename F> ConsoleValueRef executef(A a, B b, C c, D d, E e, F f) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c, d, e, f); }
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G> ConsoleValueRef executef(A a, B b, C c, D d, E e, F f, G g) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c, d, e, f, g); }
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H> ConsoleValueRef executef(A a, B b, C c, D d, E e, F f, G g, H h) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c, d, e, f, g, h); }
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I> ConsoleValueRef executef(A a, B b, C c, D d, E e, F f, G g, H h, I i) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c, d, e, f, g, h, i); }
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J> ConsoleValueRef executef(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c, d, e, f, g, h, i, j); }
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K> ConsoleValueRef executef(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c, d, e, f, g, h, i, j, k); }
/// }
};
extern void expandEscape(char *dest, const char *src);
extern bool collapseEscape(char *buf);
extern U32 HashPointer(StringTableEntry ptr);
@ -1103,6 +1104,28 @@ struct ConsoleDocFragment
};
/// Utility class to save and restore the current console stack frame
///
class ConsoleStackFrameSaver
{
public:
bool mSaved;
ConsoleStackFrameSaver() : mSaved(false)
{
}
~ConsoleStackFrameSaver()
{
restore();
}
void save();
void restore();
};
/// @name Global Console Definition Macros
///
/// @note If TORQUE_DEBUG is defined, then we gather documentation information, and