473 lines
23 KiB
C++
473 lines
23 KiB
C++
#pragma once
|
|
|
|
#include "dtcore/inc/dttest.h"
|
|
#include "dtcore/inc/dtstream.h"
|
|
#include "dtcore/inc/dtscriptobject.h"
|
|
#include "dtcore/inc/dtscriptstate.h"
|
|
#include "dtcore/inc/dtscriptstatementexpressionparserinfo.h"
|
|
|
|
namespace dt
|
|
{
|
|
|
|
// Use this macro to register your script statement to the ScriptStatementFactory
|
|
#define DT_REGISTER_SCRIPT_STATEMENT(className) \
|
|
extern dt::ScriptStatementDescriptor dtScriptStatementDescriptor##className; \
|
|
dt::ScriptStatementFactory::RegisterScriptStatementDescriptor(&dtScriptStatementDescriptor##className);
|
|
|
|
// Use this macro to declare a script statement. The base class should be or derive from dt::ScriptStatement
|
|
// example: DT_DECLARE_SCRIPT_STATEMENT(yourstatementname, "do stuff") : public dt::ScriptStatementLeaf
|
|
#define DT_DECLARE_SCRIPT_STATEMENT(className, expression, ...) \
|
|
class className; \
|
|
static dt::ScriptStatementDescriptor dtScriptStatementDescriptor##className( \
|
|
#className, \
|
|
__FILE__, \
|
|
__LINE__, \
|
|
expression, \
|
|
&dt::ScriptStatementFactory::CreateScriptStatement<className>, \
|
|
&dt::ScriptStatementFactory::DestroyScriptStatement); \
|
|
class __VA_ARGS__ className
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
class ScriptParserState;
|
|
class ScriptStatementDescriptor;
|
|
class ScriptStatementImpl;
|
|
|
|
// Base class for a script step called a statement. The relation
|
|
// of this class is one to one with the script lines (one instance
|
|
// per script line). Normally your custom statement will not
|
|
// derive directly from this class but from one of these three:
|
|
//
|
|
// - ScriptStatementLeaf: simple, single line statement
|
|
// - ScriptStatementInSequence: compound statement with nested
|
|
// statements within a block surrounded by { }. All nested
|
|
// statements executes in sequence.
|
|
// - ScriptStatementInParallel: compound statement with nested
|
|
// statements within a block surrounded by { }. All nested
|
|
// statements executes in parallel.
|
|
class ScriptStatement
|
|
{
|
|
public:
|
|
// Default constructor, no work with side effect shall be
|
|
// performed here, only initialization.
|
|
DT_CORE_DLL_ENTRY ScriptStatement();
|
|
DT_CORE_DLL_ENTRY virtual ~ScriptStatement();
|
|
|
|
|
|
// The initialize function is where you can safely init object from the agent.
|
|
// This function is called repetitively until SetCompleted() is
|
|
// called. Override as needed.
|
|
DT_CORE_DLL_ENTRY virtual void Initialize() { SetCompleted(); }
|
|
// The run function is where the real work is done. This
|
|
// function is called repetitively until SetCompleted() is
|
|
// called. The function should not block unless the tests are
|
|
// run in background thread mode.
|
|
DT_CORE_DLL_ENTRY virtual void Run() { SetCompleted(); }
|
|
// The run function is where the cleanup work is done. This
|
|
// function is called repetitively until SetCompleted() is
|
|
// called. The function should not block unless the tests are
|
|
// run in background thread mode. The function is only called
|
|
// if Run() was called.
|
|
DT_CORE_DLL_ENTRY virtual void Cleanup() { SetCompleted(); }
|
|
// Override as needed. This function is called when the
|
|
// statement or test times out. You can insert a DT_FAIL macro
|
|
// in here to override the timeout failure message of the test
|
|
// to add contextual information. Per example, if this
|
|
// statement is performing a login, the timeout could be
|
|
// "timed out while login in"
|
|
DT_CORE_DLL_ENTRY virtual void OnTimeout() {}
|
|
|
|
// when called, the statement move on to the next state
|
|
DT_CORE_DLL_ENTRY virtual void SetCompleted() = 0;
|
|
// when called, the statement and its children, if applicable, will be skipped
|
|
DT_CORE_DLL_ENTRY virtual void Skip() = 0;
|
|
|
|
// Get the value of a variable of the specified name. Returns
|
|
// false if the variable does not exists.
|
|
DT_CORE_DLL_ENTRY bool TryGetVariable(const String& name, const ScriptObject** value);
|
|
// Get the value of a variable of the specified name. If the
|
|
// variable does not exists, the test fails and this function
|
|
// never returns.
|
|
DT_CORE_DLL_ENTRY const ScriptObject& GetVariable(const String& name) const;
|
|
// Create or update a variable of the specified name. If the
|
|
// variable does not exists, it is created in the current
|
|
// scope.
|
|
DT_CORE_DLL_ENTRY void SetVariable(const String& name, const ScriptObject& value);
|
|
// Create a variable of the specified name. if the variable
|
|
// already exists, the test fails and this function never
|
|
// returns.
|
|
DT_CORE_DLL_ENTRY void DeclareVariable(const String& name);
|
|
|
|
// Get the user ids for which this statement applies to. The
|
|
// statement will only run on agent where the user are
|
|
// associated. But in case of multiple users per agent, this
|
|
// function is used to know on which user it applies.
|
|
DT_CORE_DLL_ENTRY const Vector<UserId>& GetUserIds() const;
|
|
|
|
// Returns all optional zone names that where matches in the
|
|
// current script line.
|
|
DT_CORE_DLL_ENTRY const Set<String>& GetMatchedOptionalZoneNames() const;
|
|
// Returns true if the specified optional zone name was matches.
|
|
DT_CORE_DLL_ENTRY bool IsOptionalZoneMatched(const String& zoneName) const;
|
|
|
|
// Retrieve the statement descriptor that matched the statement.
|
|
DT_CORE_DLL_ENTRY const ScriptStatementDescriptor* GetDescriptor() const;
|
|
// Retrieve the script filename
|
|
DT_CORE_DLL_ENTRY const ScriptLine& GetScriptLine() const;
|
|
|
|
// Retrieve the timeout period of this statement. INVALID_VALUE
|
|
// means no timeout is applicable. Note that timeouts are
|
|
// handled internally. This information is exposed for information
|
|
// only.
|
|
DT_CORE_DLL_ENTRY Seconds GetTimeoutInSec() const;
|
|
|
|
// Get a unique id of this statement.
|
|
DT_CORE_DLL_ENTRY int GetId() const;
|
|
|
|
DT_CORE_DLL_ENTRY virtual bool InternalUpdate() = 0;
|
|
DT_CORE_DLL_ENTRY virtual void InternalTimeout() = 0;
|
|
|
|
// Returns true if this statement is a function
|
|
DT_CORE_DLL_ENTRY virtual bool IsFunction() const;
|
|
|
|
protected:
|
|
DT_CORE_DLL_ENTRY ScriptState* GetScriptState() const;
|
|
DT_CORE_DLL_ENTRY const Map<String, ScriptObject>& GetParameters() const;
|
|
DT_CORE_DLL_ENTRY bool HandleExecutionTimeout();
|
|
|
|
private:
|
|
friend class ScriptParserImpl;
|
|
friend class ScriptStatementCompound;
|
|
friend class ScriptStatementCompoundImpl;
|
|
friend class ScriptStatementLeafImpl;
|
|
friend class ServiceScript;
|
|
friend class ServiceScriptImpl;
|
|
friend class ScriptState;
|
|
friend class ScriptStatementFunctionCheckOptionalZone;
|
|
friend class StatementUtilsImpl;
|
|
|
|
const ScriptStatementCompound* GetParentStatement() const;
|
|
void SetParentStatement(const ScriptStatementCompound* parent);
|
|
void SetInformation(const ScriptStatementCompound* parent,
|
|
const ScriptLine& line,
|
|
const ScriptStatementDescriptor* descriptor,
|
|
const Map<String, ScriptObject>& parameters,
|
|
const Vector<UserId>& users,
|
|
const Set<String>& matchedOptionalZoneNames,
|
|
Seconds timeout);
|
|
|
|
DT_CORE_DLL_ENTRY virtual bool IsCompound() const;
|
|
bool IsInParallelBlock() const;
|
|
DT_CORE_DLL_ENTRY virtual bool IsRunningChildrenInParallel() const;
|
|
DT_CORE_DLL_ENTRY virtual void SetScriptState(ScriptState* state);
|
|
|
|
const ScriptStatement* GetFirstCommonStatementInHierarchy(const ScriptStatement* other);
|
|
|
|
void PushStack();
|
|
void PopStack();
|
|
void Synchronize();
|
|
bool IsSynchronized() const;
|
|
|
|
void SynchronizationEnable();
|
|
void SynchronizationDisable();
|
|
|
|
bool AppliesToCurrentAgentIndex() const;
|
|
|
|
ShowProgressionMode GetShowProgressionMode() const;
|
|
|
|
private:
|
|
ScriptStatementImpl* m_Impl;
|
|
};
|
|
|
|
typedef Vector<ScriptStatement*> ScriptStatements;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// This class is created by the DT_DECLARE_SCRIPT_STATEMENT macro and is
|
|
// used to store the statement declaration information.
|
|
class ScriptStatementDescriptor
|
|
{
|
|
public:
|
|
typedef ScriptStatement* (*CreateFunction)();
|
|
typedef void(*DestroyFunction)(ScriptStatement*);
|
|
|
|
DT_CORE_DLL_ENTRY ScriptStatementDescriptor(const char* className,
|
|
const char* file,
|
|
int line,
|
|
const char* expression,
|
|
CreateFunction createFunction,
|
|
DestroyFunction destroyFunction);
|
|
|
|
// returns the class name of the ScriptStatement
|
|
DT_CORE_DLL_ENTRY const char* GetName() const { return m_ClassName; }
|
|
// returns the filename where the script statement was declared
|
|
DT_CORE_DLL_ENTRY const char* GetFilename() const { return m_Filename; }
|
|
// returns the line where the script statement was declared
|
|
DT_CORE_DLL_ENTRY int GetLineNumber() const { return m_LineNumber; }
|
|
// returns the expression specified in DT_DECLARE_SCRIPT_STATEMENT
|
|
DT_CORE_DLL_ENTRY const char* GetExpression() const { return m_Expression; }
|
|
// returns a create function to create the Statement of this type
|
|
DT_CORE_DLL_ENTRY CreateFunction GetCreateFunction() const { return m_CreateFunction; }
|
|
// returns a destroy function to delete the Statement of this type
|
|
DT_CORE_DLL_ENTRY DestroyFunction GetDestroyFunction() const { return m_DestroyFunction; }
|
|
|
|
private:
|
|
const char* m_ClassName;
|
|
const char* m_Filename;
|
|
const char* m_Expression;
|
|
CreateFunction m_CreateFunction;
|
|
DestroyFunction m_DestroyFunction;
|
|
int m_LineNumber;
|
|
};
|
|
|
|
typedef Vector<ScriptStatementDescriptor*> ScriptStatementDescriptors;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
class ScriptStatementScannerImpl;
|
|
|
|
// This class is used by ScriptStatementExpressionParsers to parse
|
|
// the script lines and identify which ScriptStatement class to
|
|
// instantiate. This class is created internally and passed to the
|
|
// ScriptStatementExpressionParser::Parse() function.
|
|
class ScriptStatementScanner
|
|
{
|
|
public:
|
|
DT_CORE_DLL_ENTRY ScriptStatementScanner(ScriptParserState& parentState, const String& line);
|
|
DT_CORE_DLL_ENTRY ~ScriptStatementScanner();
|
|
|
|
DT_CORE_DLL_ENTRY const ScriptParserState& GetParentState() const;
|
|
DT_CORE_DLL_ENTRY ScriptParserState& GetParentState();
|
|
|
|
// returns the complete script line being parsed
|
|
DT_CORE_DLL_ENTRY const String& GetLine() const;
|
|
// returns the position offset on the line where the scanner is
|
|
DT_CORE_DLL_ENTRY SizeT GetPosition() const;
|
|
// returns the char at the current position of the scanner or '\0' if at end
|
|
DT_CORE_DLL_ENTRY char Peek() const;
|
|
// returns true if the scanner is at the end of the line
|
|
DT_CORE_DLL_ENTRY bool End() const;
|
|
|
|
// pre and post increment the current scanner position and
|
|
// return the next or current char
|
|
DT_CORE_DLL_ENTRY char operator++();
|
|
DT_CORE_DLL_ENTRY char operator++(int);
|
|
|
|
// util functions
|
|
DT_CORE_DLL_ENTRY static bool IsValidIntegerFirstChar(char c);
|
|
DT_CORE_DLL_ENTRY static bool IsValidIntegerChar(char c);
|
|
DT_CORE_DLL_ENTRY static bool IsValidIdentifierFirstChar(char c);
|
|
DT_CORE_DLL_ENTRY static bool IsValidIdentifierChar(char c);
|
|
DT_CORE_DLL_ENTRY static bool IsValidJsonFirstChar(char c);
|
|
DT_CORE_DLL_ENTRY static bool IsWhiteSpaceChar(char c);
|
|
|
|
// increment the scanner position until non white space is found
|
|
DT_CORE_DLL_ENTRY void SkipWhiteSpace();
|
|
// increment the scanner position by the number of char specified
|
|
DT_CORE_DLL_ENTRY void Skip(int count);
|
|
// increment the scanner position by the length of str if the line
|
|
// at the scanner position matches the str specified.
|
|
DT_CORE_DLL_ENTRY bool SkipLiteralIfEqual(const char* str);
|
|
// parse a variable reference, a identifier enclosed within parenthesis.
|
|
// returns a reference to a script object
|
|
// returns true if a reference was found
|
|
DT_CORE_DLL_ENTRY bool ParseReference(ScriptObject* out);
|
|
// parse a Json expression
|
|
// returns the JsonValue corresponding to the expression
|
|
// returns true if a Json expression was found and is valid
|
|
DT_CORE_DLL_ENTRY bool ParseJsonExpression(JsonValue* out);
|
|
// parse an identifier. An identifier starts with a letter and contains 0 or more
|
|
// letters, numbers or underscores.
|
|
// returns the identifier
|
|
// returns true if an identifier was found
|
|
DT_CORE_DLL_ENTRY bool ParseIdentifier(String* out);
|
|
// parse a 32 bit signed integer
|
|
// returns the integer
|
|
// returns true if a valid signed 32 bits integer was found
|
|
DT_CORE_DLL_ENTRY bool ParseInteger(S32* out);
|
|
// parse a 64 bit signed integer
|
|
// returns the integer
|
|
// returns true if a valid signed 64 bits integer was found
|
|
DT_CORE_DLL_ENTRY bool ParseInteger(S64* out);
|
|
// parse a 64 bit unsigned integer
|
|
// returns the unsigned integer
|
|
// returns true if a valid unsigned 64 bits integer was found
|
|
DT_CORE_DLL_ENTRY bool ParseInteger(U64* out);
|
|
// parse a 64 bit signed double
|
|
// returns the double
|
|
// returns true if a valid signed double was found
|
|
DT_CORE_DLL_ENTRY bool ParseDouble(double* out);
|
|
// parse a string enclosed in double quotes
|
|
// returns the string
|
|
// returns true if a valid string was found
|
|
DT_CORE_DLL_ENTRY bool ParseString(String* out);
|
|
// parse a bool
|
|
// returns the bool
|
|
// returns true if a valid bool was found
|
|
DT_CORE_DLL_ENTRY bool ParseBool(bool* out);
|
|
|
|
// returns the current longest matched position of the scanner
|
|
DT_CORE_DLL_ENTRY SizeT GetBestPosition() const;
|
|
// updates the longest matched position of the scanner
|
|
DT_CORE_DLL_ENTRY void UpdateBestPosition(SizeT possibleBestPosition);
|
|
// resets the longest matched position
|
|
DT_CORE_DLL_ENTRY void ResetBestPosition();
|
|
|
|
// save the current scanner position into a stack. Each push
|
|
// must be followed by one pop.
|
|
DT_CORE_DLL_ENTRY void PushPosition();
|
|
// pop the current position and if apply is true, restore the
|
|
// previously pushed position.
|
|
DT_CORE_DLL_ENTRY void PopPosition(bool apply = true);
|
|
// change the current scanner position
|
|
DT_CORE_DLL_ENTRY void SetPosition(SizeT newPosition);
|
|
|
|
private:
|
|
ScriptStatementScannerImpl* m_Impl;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Use this macro to register your script statement expression
|
|
// parser to the ScriptStatementFactory
|
|
#define DT_REGISTER_SCRIPT_STATEMENT_EXPRESSION_PARSER(className) \
|
|
extern dt::ScriptStatementExpressionParserDescriptor dtScriptStatementExpressionParserDescriptor##className; \
|
|
dt::ScriptStatementFactory::RegisterScriptStatementExpressionParserDescriptor(&dtScriptStatementExpressionParserDescriptor##className);
|
|
|
|
// Use this macro to declare a script statement expression
|
|
// parser. The base class should be or derive from
|
|
// dt::ScriptStatementExpressionParser.
|
|
// example: DT_DECLARE_SCRIPT_STATEMENT_EXPRESSION_PARSER(yourstatementexpressionparsername, "apple") : public dt::ScriptStatementExpressionParser
|
|
#define DT_DECLARE_SCRIPT_STATEMENT_EXPRESSION_PARSER(className, expression, ...) \
|
|
class className; \
|
|
static dt::ScriptStatementExpressionParserDescriptor dtScriptStatementExpressionParserDescriptor##className( \
|
|
#className, \
|
|
expression, \
|
|
&dt::ScriptStatementFactory::CreateScriptStatementExpressionParser<className>, \
|
|
&dt::ScriptStatementFactory::DestroyScriptStatementExpressionParser); \
|
|
class __VA_ARGS__ className
|
|
|
|
// Base class to implement new expression parsers. Expression
|
|
// parsers allow parsing part of a statement, retrieve some data
|
|
// and store it in native format to allow statement code to use
|
|
// it.
|
|
class ScriptStatementExpressionParser
|
|
{
|
|
public:
|
|
DT_CORE_DLL_ENTRY ScriptStatementExpressionParser();
|
|
DT_CORE_DLL_ENTRY virtual ~ScriptStatementExpressionParser() {};
|
|
|
|
// The parse method has to be overridden. The scanner contains
|
|
// the script line to be parsed and helper functions to do so.
|
|
// The parserInfo->GetContext() is the key to be used to store the
|
|
// corresponding parsed value in the outParameters map. Per example,
|
|
// if a class parses apple types, then the apple type would be
|
|
// stored in outParameters:
|
|
//
|
|
// outParameters->Insert(parserInfo->GetContext(), appleType);
|
|
//
|
|
// Returns true if the expression parses successfully matched,
|
|
// or otherwise return false. This class shall not generate
|
|
// any errors using DT_FAIL as the script parser tries all
|
|
// combinations on every line of script
|
|
DT_CORE_DLL_ENTRY virtual bool Parse(ScriptStatementScanner& scanner,
|
|
const ScriptStatementExpressionParserInfo& parserInfo,
|
|
Map<String, ScriptObject>* outParameters,
|
|
Set<String>* outOptionalZones) = 0;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// This class is created by the
|
|
// DT_REGISTER_SCRIPT_STATEMENT_EXPRESSION_PARSER macro and is
|
|
// used to store the statement expression parser declaration
|
|
// information.
|
|
class ScriptStatementExpressionParserDescriptor
|
|
{
|
|
public:
|
|
typedef ScriptStatementExpressionParser* (*CreateFunction)();
|
|
typedef void(*DestroyFunction)(ScriptStatementExpressionParser*);
|
|
|
|
DT_CORE_DLL_ENTRY ScriptStatementExpressionParserDescriptor(const char* className,
|
|
const char* expression,
|
|
CreateFunction createFunction,
|
|
DestroyFunction destroyFunction);
|
|
|
|
// returns the class name of the ScriptStatementExpressionParser
|
|
DT_CORE_DLL_ENTRY const char* GetName() const { return m_ClassName; }
|
|
// returns the expression of the parser, the second parameter
|
|
// of the DT_REGISTER_SCRIPT_STATEMENT_EXPRESSION_PARSER macro
|
|
DT_CORE_DLL_ENTRY const char* GetExpression() const { return m_Expression; }
|
|
// returns a create function to create the Statement of this type
|
|
DT_CORE_DLL_ENTRY CreateFunction GetCreateFunction() const { return m_CreateFunction; }
|
|
// returns a destroy function to delete the Statement of this type
|
|
DT_CORE_DLL_ENTRY DestroyFunction GetDestroyFunction() const { return m_DestroyFunction; }
|
|
|
|
private:
|
|
const char* m_ClassName;
|
|
const char* m_Expression;
|
|
CreateFunction m_CreateFunction;
|
|
DestroyFunction m_DestroyFunction;
|
|
};
|
|
|
|
typedef Vector<ScriptStatementExpressionParserDescriptor*> ScriptStatementExpressionParserDescriptors;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// This class is used by the following macros to register a
|
|
// statement or statement expression parser class to be created
|
|
// automatically by the script parser.
|
|
// - DT_REGISTER_SCRIPT_STATEMENT
|
|
// - DT_REGISTER_SCRIPT_STATEMENT_EXPRESSION_PARSER
|
|
class ScriptStatementFactory
|
|
{
|
|
public:
|
|
// Register a script statement descriptor
|
|
DT_CORE_DLL_ENTRY static void RegisterScriptStatementDescriptor(ScriptStatementDescriptor* stmDescriptor);
|
|
// Register all built in script statements
|
|
DT_CORE_DLL_ENTRY static void RegisterBuiltInStatements();
|
|
// Clear all registered script statements
|
|
DT_CORE_DLL_ENTRY static void ClearScriptStatementDescriptors();
|
|
// Helper function to create a script statement
|
|
template <typename T> static ScriptStatement* CreateScriptStatement();
|
|
// Destroy function for script statement
|
|
DT_CORE_DLL_ENTRY static void DestroyScriptStatement(ScriptStatement* stm);
|
|
// Returns the list of all known script statement descriptors
|
|
DT_CORE_DLL_ENTRY static void GetScriptStatementDescriptors(ScriptStatementDescriptors* out);
|
|
// Returns the script statement descriptor specified
|
|
DT_CORE_DLL_ENTRY static ScriptStatementDescriptor* GetScriptStatementDescriptor(const String& expression);
|
|
|
|
// Register a script statement descriptor expression parser
|
|
DT_CORE_DLL_ENTRY static void RegisterScriptStatementExpressionParserDescriptor(ScriptStatementExpressionParserDescriptor* parserDescriptor);
|
|
// Register all built in expression parsers
|
|
DT_CORE_DLL_ENTRY static void RegisterBuiltInExpressionParsers();
|
|
// Clear all registered script statement expression parsers
|
|
DT_CORE_DLL_ENTRY static void ClearScriptStatementExpressionParserDescriptors();
|
|
// Helper function to create a script statement expression parser
|
|
template <typename T> static ScriptStatementExpressionParser* CreateScriptStatementExpressionParser();
|
|
// Destroy function for script statement expression parser
|
|
DT_CORE_DLL_ENTRY static void DestroyScriptStatementExpressionParser(ScriptStatementExpressionParser* parser);
|
|
// Returns the list of all known script statement descriptors expression parser
|
|
DT_CORE_DLL_ENTRY static void GetScriptStatementExpressionParserDescriptors(ScriptStatementExpressionParserDescriptors* out);
|
|
// Returns the script statement descriptor expression parser specified
|
|
DT_CORE_DLL_ENTRY static ScriptStatementExpressionParserDescriptor* GetScriptStatementExpressionParserDescriptor(const String& expression);
|
|
|
|
public:
|
|
// This section is meant for INTERNAL USE only.
|
|
DT_CORE_DLL_ENTRY static void CreateFunctionScriptStatementDescriptors(const Map<String, ScriptDescriptor>& testFunctions);
|
|
DT_CORE_DLL_ENTRY static void GetFunctionScriptStatementDescriptors(ScriptStatementDescriptors* out);
|
|
DT_CORE_DLL_ENTRY static void DestroyFunctionScriptStatementDescriptors();
|
|
};
|
|
|
|
template <typename T> inline ScriptStatement* ScriptStatementFactory::CreateScriptStatement()
|
|
{
|
|
return DT_NEW(T)();
|
|
}
|
|
|
|
template <typename T> inline ScriptStatementExpressionParser* ScriptStatementFactory::CreateScriptStatementExpressionParser()
|
|
{
|
|
return DT_NEW(T)();
|
|
}
|
|
|
|
}
|
|
|