Torque3D/Engine/source/console/consoleInternal.h

530 lines
16 KiB
C
Raw Normal View History

2012-09-19 15:15:01 +00:00
//-----------------------------------------------------------------------------
// 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 _CONSOLEINTERNAL_H_
#define _CONSOLEINTERNAL_H_
#ifndef _STRINGFUNCTIONS_H_
2017-11-06 04:33:32 +00:00
#include "core/strings/stringFunctions.h"
2012-09-19 15:15:01 +00:00
#endif
#ifndef _STRINGTABLE_H_
2017-11-06 04:33:32 +00:00
#include "core/stringTable.h"
2012-09-19 15:15:01 +00:00
#endif
#ifndef _CONSOLETYPES_H
2017-11-06 04:33:32 +00:00
#include "console/consoleTypes.h"
2012-09-19 15:15:01 +00:00
#endif
#ifndef _CONSOLEOBJECT_H_
2017-11-06 04:33:32 +00:00
#include "console/simObject.h"
2012-09-19 15:15:01 +00:00
#endif
#ifndef _DATACHUNKER_H_
2017-11-06 04:33:32 +00:00
#include "core/dataChunker.h"
2012-09-19 15:15:01 +00:00
#endif
2023-04-23 08:39:54 +00:00
#include "module.h"
2012-09-19 15:15:01 +00:00
/// @ingroup console_system Console System
/// @{
struct FunctionDecl;
class CodeBlock;
class AbstractClassRep;
/// A dictionary of function entries.
///
/// Namespaces are used for dispatching calls in the console system.
class Namespace
{
2017-11-06 04:33:32 +00:00
enum {
MaxActivePackages = 512,
};
static U32 mNumActivePackages;
static U32 mOldNumActivePackages;
static StringTableEntry mActivePackages[MaxActivePackages];
public:
StringTableEntry mName;
StringTableEntry mPackage;
Namespace *mParent;
Namespace *mNext;
AbstractClassRep *mClassRep;
U32 mRefCountToParent;
const char* mUsage;
/// Script defined usage strings need to be cleaned up. This
/// field indicates whether or not the usage was set from script.
bool mCleanUpUsage;
/// A function entry in the namespace.
struct Entry
{
enum
{
ScriptCallbackType = -3,
GroupMarker = -2,
InvalidFunctionType = -1,
ConsoleFunctionType,
StringCallbackType,
IntCallbackType,
FloatCallbackType,
VoidCallbackType,
BoolCallbackType
2012-09-19 15:15:01 +00:00
};
2017-11-06 04:33:32 +00:00
/// Link back to the namespace to which the entry belongs.
Namespace* mNamespace;
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
/// Next function entry in the hashtable link chain of the namespace.
Entry* mNext;
/// Name of this function.
StringTableEntry mFunctionName;
///
S32 mType;
/// Min number of arguments expected by this function.
S32 mMinArgs;
/// Max number of arguments expected by this function. If zero,
/// function takes an arbitrary number of arguments.
S32 mMaxArgs;
/// Name of the package to which this function belongs.
2012-09-19 15:15:01 +00:00
StringTableEntry mPackage;
2017-11-06 04:33:32 +00:00
/// Whether this function is included only in TORQUE_TOOLS builds.
bool mToolOnly;
/// Usage string for documentation.
2012-09-19 15:15:01 +00:00
const char* mUsage;
2017-11-06 04:33:32 +00:00
/// Extended console function information.
ConsoleFunctionHeader* mHeader;
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
/// The compiled script code if this is a script function.
2023-04-23 08:39:54 +00:00
Con::Module* mModule;
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
/// The offset in the compiled script code at which this function begins.
U32 mFunctionOffset;
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
/// If it's a script function, this is the line of the declaration in code.
/// @note 0 for functions read from legacy DSOs that have no line number information.
U32 mFunctionLineNumber;
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
union CallbackUnion {
StringCallback mStringCallbackFunc;
IntCallback mIntCallbackFunc;
VoidCallback mVoidCallbackFunc;
FloatCallback mFloatCallbackFunc;
BoolCallback mBoolCallbackFunc;
const char *mGroupName;
const char *mCallbackName;
} cb;
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
Entry();
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
///
void clear();
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
///
2023-04-23 08:39:54 +00:00
ConsoleValue execute(S32 argc, ConsoleValue* argv, SimObject* thisObj);
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
/// Return a one-line documentation text string for the function.
String getBriefDescription(String* outRemainingDocText = NULL) const;
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
/// Get the auto-doc string for this function. This string does not included prototype information.
String getDocString() const;
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
/// Return a string describing the arguments the function takes including default argument values.
String getArgumentsString() const;
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
/// Return a full prototype string for the function including return type, function name,
/// and arguments.
String getPrototypeString() const;
/// Return a minimalized prototype string for the function including return type, function name,
/// and arguments.
String getPrototypeSig() const;
2017-11-06 04:33:32 +00:00
};
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
Entry* mEntryList;
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
Entry** mHashTable;
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
U32 mHashSize;
U32 mHashSequence; ///< @note The hash sequence is used by the autodoc console facility
/// as a means of testing reference state.
Namespace();
~Namespace();
2023-04-23 08:39:54 +00:00
void addFunction(StringTableEntry name, Con::Module* cb, U32 functionOffset, const char* usage = NULL, U32 lineNumber = 0);
2017-11-06 04:33:32 +00:00
void addCommand(StringTableEntry name, StringCallback, const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL);
void addCommand(StringTableEntry name, IntCallback, const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL);
void addCommand(StringTableEntry name, FloatCallback, const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL);
void addCommand(StringTableEntry name, VoidCallback, const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL);
void addCommand(StringTableEntry name, BoolCallback, const char *usage, S32 minArgs, S32 maxArgs, bool toolOnly = false, ConsoleFunctionHeader* header = NULL);
void addScriptCallback(const char *funcName, const char *usage, ConsoleFunctionHeader* header = NULL);
void markGroup(const char* name, const char* usage);
char * lastUsage;
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
/// Returns true if this namespace represents an engine defined
/// class and is not just a script defined class namespace.
bool isClass() const { return mClassRep && mClassRep->getNameSpace() == this; }
void getEntryList(VectorPtr<Entry *> *);
/// Return the name of this namespace.
StringTableEntry getName() const { return mName; }
/// Return the superordinate namespace to this namespace. Symbols are inherited from
/// this namespace.
Namespace* getParent() const { return mParent; }
/// Return the topmost package in the parent hierarchy of this namespace
/// that still refers to the same namespace. If packages are active and
/// adding to this namespace, then they will be linked in-between the namespace
/// they are adding to and its real parent namespace.
Namespace* getPackageRoot()
{
Namespace* walk = this;
while (walk->mParent && walk->mParent->mName == mName)
walk = walk->mParent;
return walk;
}
/// Return the package in which this namespace is defined.
StringTableEntry getPackage() const { return mPackage; }
/// Increase the count on the reference that this namespace
/// holds to its parent.
/// @note Must not be called on namespaces coming from packages.
void incRefCountToParent()
{
AssertFatal(mPackage == NULL, "Namespace::incRefCountToParent - Must not be called on a namespace coming from a package!");
mRefCountToParent++;
}
/// Decrease the count on the reference that this namespace
/// holds to its parent.
/// @note Must not be called on namespaces coming from packages.
void decRefCountToParent()
{
unlinkClass(NULL);
}
Entry *lookup(StringTableEntry name);
Entry *lookupRecursive(StringTableEntry name);
Entry *createLocalEntry(StringTableEntry name);
void buildHashTable();
void clearEntries();
bool classLinkTo(Namespace *parent);
bool unlinkClass(Namespace *parent);
void getUniqueEntryLists(Namespace *other, VectorPtr<Entry *> *outThisList, VectorPtr<Entry *> *outOtherList);
const char *tabComplete(const char *prevText, S32 baseLen, bool fForward);
static U32 mCacheSequence;
static DataChunker mCacheAllocator;
static DataChunker mAllocator;
static void trashCache();
static Namespace *mNamespaceList;
static Namespace *mGlobalNamespace;
static void init();
static void shutdown();
static Namespace *global();
static Namespace *find(StringTableEntry name, StringTableEntry package = NULL);
static void activatePackage(StringTableEntry name);
static void deactivatePackage(StringTableEntry name);
static void deactivatePackageStack(StringTableEntry name);
static void dumpClasses(bool dumpScript = true, bool dumpEngine = true);
static void dumpFunctions(bool dumpScript = true, bool dumpEngine = true);
static void printNamespaceEntries(Namespace * g, bool dumpScript = true, bool dumpEngine = true);
static void unlinkPackages();
static void relinkPackages();
static bool isPackage(StringTableEntry name);
static U32 getActivePackagesCount();
static StringTableEntry getActivePackage(U32 index);
2012-09-19 15:15:01 +00:00
};
typedef VectorPtr<Namespace::Entry *>::iterator NamespaceEntryListIterator;
class Dictionary
{
public:
struct Entry
{
2021-04-13 01:26:26 +00:00
friend class Dictionary;
2012-09-19 15:15:01 +00:00
StringTableEntry name;
Entry *nextEntry;
typedef Signal<void()> NotifySignal;
/// The optional notification signal called when
/// a value is assigned to this variable.
NotifySignal *notify;
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
/// Usage doc string.
const char* mUsage;
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
/// Whether this is a constant that cannot be assigned to.
bool mIsConstant;
ConsoleValue value;
2021-04-13 01:26:26 +00:00
2012-09-19 15:15:01 +00:00
public:
Entry() {
name = NULL;
notify = NULL;
nextEntry = NULL;
mUsage = NULL;
mIsConstant = false;
2020-05-11 19:40:31 +00:00
mNext = NULL;
}
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
Entry(StringTableEntry name);
~Entry();
2017-11-06 04:33:32 +00:00
Entry *mNext;
2017-11-06 04:33:32 +00:00
2021-04-13 01:26:26 +00:00
void reset();
2012-09-19 15:15:01 +00:00
2025-05-08 19:40:17 +00:00
inline ConsoleValue getValue() { return (value); }
inline U32 getIntValue()
2012-09-19 15:15:01 +00:00
{
return value.getInt();
2012-09-19 15:15:01 +00:00
}
inline F32 getFloatValue()
2012-09-19 15:15:01 +00:00
{
return value.getFloat();
2012-09-19 15:15:01 +00:00
}
inline const char *getStringValue()
2012-09-19 15:15:01 +00:00
{
return value.getString();
2012-09-19 15:15:01 +00:00
}
void setIntValue(U32 val)
{
2017-11-06 04:33:32 +00:00
if (mIsConstant)
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
Con::errorf("Cannot assign value to constant '%s'.", name);
2012-09-19 15:15:01 +00:00
return;
}
2017-11-06 04:33:32 +00:00
if (value.isConsoleType())
2021-04-13 01:26:26 +00:00
{
const char* dptr = Con::getData(TypeS32, &val, 0);
2025-05-11 21:57:56 +00:00
Con::setData(value.type, value.dataPtr, 0, 1, &dptr, value.enumTable);
2021-04-13 01:26:26 +00:00
}
else
{
value.setInt(val);
2021-04-13 01:26:26 +00:00
}
2012-09-19 15:15:01 +00:00
// Fire off the notification if we have one.
2017-11-06 04:33:32 +00:00
if (notify)
2012-09-19 15:15:01 +00:00
notify->trigger();
}
void setFloatValue(F32 val)
{
2017-11-06 04:33:32 +00:00
if (mIsConstant)
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
Con::errorf("Cannot assign value to constant '%s'.", name);
2012-09-19 15:15:01 +00:00
return;
}
2017-11-06 04:33:32 +00:00
if (value.isConsoleType())
2012-09-19 15:15:01 +00:00
{
const char* dptr = Con::getData(TypeF32, &val, 0);
2025-05-11 21:57:56 +00:00
Con::setData(value.type, value.dataPtr, 0, 1, &dptr, value.enumTable);
2021-04-13 01:26:26 +00:00
}
else
{
value.setFloat(val);
2012-09-19 15:15:01 +00:00
}
2017-11-06 04:33:32 +00:00
2012-09-19 15:15:01 +00:00
// Fire off the notification if we have one.
2017-11-06 04:33:32 +00:00
if (notify)
2012-09-19 15:15:01 +00:00
notify->trigger();
}
2021-04-13 01:26:26 +00:00
void setStringValue(const char* val)
{
if (mIsConstant)
{
Con::errorf("Cannot assign value to constant '%s'.", name);
return;
}
if (value.isConsoleType())
{
2025-05-11 21:57:56 +00:00
Con::setData(value.type, value.dataPtr, 0, 1, &val, value.enumTable);
}
else
{
value.setString(val);
}
// Fire off the notification if we have one.
if (notify)
notify->trigger();
}
2012-09-19 15:15:01 +00:00
};
struct HashTableData
{
Dictionary* owner;
S32 size;
S32 count;
Entry **data;
FreeListChunker< Entry > mChunker;
2017-11-06 04:33:32 +00:00
HashTableData(Dictionary* owner)
: owner(owner), size(0), count(0), data(NULL) {}
};
HashTableData* hashTable;
HashTableData ownHashTable;
StringTableEntry scopeName;
Namespace *scopeNamespace;
2023-04-23 08:39:54 +00:00
Con::Module *module;
U32 ip;
Dictionary();
~Dictionary();
Entry *lookup(StringTableEntry name);
Entry *add(StringTableEntry name);
2023-04-23 08:39:54 +00:00
void setState(Dictionary* ref = NULL);
void remove(Entry *);
void reset();
2017-11-06 04:33:32 +00:00
void exportVariables(const char *varString, const char *fileName, bool append);
void exportVariables(const char *varString, Vector<String> *names, Vector<String> *values);
void deleteVariables(const char *varString);
void setVariable(StringTableEntry name, const char *value);
const char *getVariable(StringTableEntry name, bool *valid = NULL);
S32 getIntVariable(StringTableEntry name, bool *valid = NULL);
F32 getFloatVariable(StringTableEntry name, bool *entValid = NULL);
U32 getCount() const
{
2012-09-19 15:15:01 +00:00
return hashTable->count;
}
bool isOwner() const
{
2012-09-19 15:15:01 +00:00
return hashTable->owner;
}
/// @see Con::addVariable
2017-11-06 04:33:32 +00:00
Entry* addVariable(const char *name,
S32 type,
void *dataPtr,
const char* usage);
2012-09-19 15:15:01 +00:00
/// @see Con::removeVariable
bool removeVariable(StringTableEntry name);
2012-09-19 15:15:01 +00:00
/// @see Con::addVariableNotify
2017-11-06 04:33:32 +00:00
void addVariableNotify(const char *name, const Con::NotifyDelegate &callback);
2012-09-19 15:15:01 +00:00
/// @see Con::removeVariableNotify
2017-11-06 04:33:32 +00:00
void removeVariableNotify(const char *name, const Con::NotifyDelegate &callback);
2012-09-19 15:15:01 +00:00
/// Return the best tab completion for prevText, with the length
/// of the pre-tab string in baseLen.
const char *tabComplete(const char *prevText, S32 baseLen, bool);
2012-09-19 15:15:01 +00:00
/// Run integrity checks for debugging.
void validate();
2012-09-19 15:15:01 +00:00
};
2021-03-30 23:33:19 +00:00
struct ConsoleValueFrame
{
ConsoleValue* values;
bool isReference;
2021-04-02 04:57:49 +00:00
ConsoleValueFrame() : values(NULL), isReference(false)
{}
2021-03-30 23:33:19 +00:00
ConsoleValueFrame(ConsoleValue* vals, bool isRef)
{
values = vals;
isReference = isRef;
}
};
2023-04-23 08:39:54 +00:00
namespace Con
2012-09-19 15:15:01 +00:00
{
2023-04-23 08:39:54 +00:00
/// The current $instantGroup setting.
extern String gInstantGroup;
2021-03-30 23:33:19 +00:00
2023-04-23 08:39:54 +00:00
/// Global variable storage
inline Dictionary gGlobalVars;
2021-03-30 23:33:19 +00:00
2023-04-23 08:39:54 +00:00
typedef Dictionary ConsoleFrame;
typedef Vector<ConsoleFrame*> ConsoleStack;
2021-04-30 04:24:03 +00:00
2023-04-23 08:39:54 +00:00
inline ConsoleStack gFrameStack;
2023-04-23 08:39:54 +00:00
inline ConsoleStack getFrameStack() { return gFrameStack; }
inline void pushStackFrame(ConsoleFrame* frame) { gFrameStack.push_back(frame); }
inline ConsoleFrame* popStackFrame() { ConsoleFrame* last = gFrameStack.last(); gFrameStack.pop_back(); return last; }
inline ConsoleFrame* getCurrentStackFrame() { return getFrameStack().empty() ? NULL : gFrameStack.last(); }
inline ConsoleFrame* getStackFrame(S32 idx) { return gFrameStack[idx]; }
2017-11-06 04:33:32 +00:00
2023-04-23 08:39:54 +00:00
inline Vector<Con::Module*> gScriptModules;
2021-08-20 02:05:43 +00:00
2023-04-23 08:39:54 +00:00
inline Vector<Con::Module*> getAllScriptModules() { return gScriptModules; }
Con::Module* findScriptModuleForFile(const char* fileName);
// Convenience functions for getting the execution context
inline const char* getCurrentScriptModulePath() { return getCurrentStackFrame() && getCurrentStackFrame()->module ? getCurrentStackFrame()->module->getPath() : NULL; }
inline const char* getCurrentScriptModuleName() { return getCurrentStackFrame() && getCurrentStackFrame()->module ? getCurrentStackFrame()->module->getName() : NULL; }
inline Con::Module* getCurrentScriptModule() { return getCurrentStackFrame() ? getCurrentStackFrame()->module : NULL; }
2017-11-06 04:33:32 +00:00
2023-04-23 08:39:54 +00:00
inline bool gTraceOn;
2012-09-19 15:15:01 +00:00
}
/// @}
#endif