// Ryzom - MMORPG Framework
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
#ifndef CL_INTERFACE_EXPR_H
#define CL_INTERFACE_EXPR_H
#include "nel/misc/ucstring.h"
#include "nel/misc/rgba.h"
class ICDBNode;
struct CInterfaceExprUserType;
class CInterfaceExprNode;
/** a value that can be returned by a CInterfaceExpr instance
* It supports basic type;
* It can be extended by user defined types
*/
class CInterfaceExprValue
{
public:
enum TType { Boolean = 0, Integer, Double, String, RGBA, UserType, NoType };
public:
// default ctor
CInterfaceExprValue() : _Type(NoType) {}
// copy ctor
CInterfaceExprValue(const CInterfaceExprValue &other);
// assignment operator
CInterfaceExprValue &operator = (const CInterfaceExprValue &other);
// dtor
~CInterfaceExprValue() { clean(); }
TType getType() const { return _Type; }
// get. Should be used only if the type is valid
bool getBool() const;
sint64 getInteger() const;
double getDouble() const;
std::string getString() const;
NLMISC::CRGBA getRGBA() const;
const ucstring &getUCString() const;
CInterfaceExprUserType *getUserType() const;
// set
void setBool(bool value) { clean(); _Type = Boolean; _BoolValue = value; }
void setInteger(sint64 value) { clean(); _Type = Integer; _IntegerValue = value; }
void setDouble(double value) { clean(); _Type = Double; _DoubleValue = value; }
void setString(const std::string &value) { clean(); _Type = String; _StringValue = value; }
void setUCString(const ucstring &value) { clean(); _Type = String; _StringValue = value; }
void setRGBA(NLMISC::CRGBA value) { clean(); _Type = RGBA; _RGBAValue = (uint32)(value.R+(value.G<<8)+(value.B<<16)+(value.A<<24)); }
void setUserType(CInterfaceExprUserType *value);
// reset this object to initial state (no type)
void clean();
// conversions. They return true if success
bool toBool();
bool toInteger();
bool toDouble();
bool toString();
bool toType(TType type);
bool toRGBA();
// test if the value if a bool, double, or integer
bool isNumerical() const;
/** evaluate a from a string
* \param expr : where to start the evaluation
* \return the position following the token, or NULL if the parsing failed
*/
const char *initFromString(const char *expr);
/////////////////////////////////////////////////////////////////////////////////////////////
private:
TType _Type;
union
{
bool _BoolValue;
sint64 _IntegerValue;
double _DoubleValue;
CInterfaceExprUserType *_UserTypeValue;
uint32 _RGBAValue;
};
ucstring _StringValue; // well, can't fit in union, unless we do some horrible hack..
private:
const char *evalBoolean(const char *expr);
const char *evalNumber(const char *expr);
const char *evalString(const char *expr);
};
/**
* Base class for user defined types that are use by the 'CInterfaceExprValue' class
* Derivers should include the 'clone' method
*
* CInterfaceExprValue instances have ownership of this object.
*
* \author Nicolas Vizerie
* \author Nevrax France
* \date 2003
*/
struct CInterfaceExprUserType
{
// cloning method
virtual CInterfaceExprUserType *clone() const = 0;
// dtor
virtual ~CInterfaceExprUserType() {}
};
/** Evaluate expressions used in interface.
* It can retrieve values from the database.
* It can also build a list of database values it depends of.
*
* An expression can be :
*
* - a string : 'toto', 'abcd', 'a\nbcd', 'a\\t', the escape sequences are the one of C
* - a integer 1, 2, 3
* - a double 1.1, 2.2
* - a database entry : @ui:interface:toto:truc. If the address is a leaf, it returns the leaf value and put an observer on it. If not a leaf, it returns 0, but put an observer on it.
* - a database indirection @db:value[db:index] is replaced by @db:value0 if db:index == 0 for example
* - a user function call : fct(expr0, epxr1, ...).
*
* NB : The lua language has been integrated since then (2005), and should be more suited
* for most of the tasks.
*
*
* \author Nicolas Vizerie
* \author Nevrax France
* \date 2002
*/
class CInterfaceExpr
{
public:
// list of argument for a function
typedef std::vector TArgList;
/** prototype of a user callable function
* It should return true if the result is meaningful. If not, the rest of the evaluation is stopped
*/
typedef bool (* TUserFct) (TArgList &args, CInterfaceExprValue &result);
public:
// release memory
static void release();
/** This try to eval the provided expression.
* - This returns a result
* - This eventually fill a vector with a set of database entries it has dependencies on
* \param expr The expression to evaluate
* \param result The result value
* \param nodes If not NULL, will be filled with the database nodes this expression depends on
* Node will only be inserted once, so we end up with a set of node (not ordered)
* \param noFctCalls when set to true, the terminal function calls will not be made, so the evaluation is only used to see which database entries the expression depends on.
*/
static bool eval(const std::string &expr, CInterfaceExprValue &result, std::vector *nodes = NULL, bool noFctCalls = false);
/** Build a tree from the given expression so that it can be evaluated quickly.
* This is useful for a fixed expression that must be evaluated often
*/
static CInterfaceExprNode *buildExprTree(const std::string &expr);
/** Register a function that can have several arguments
* // NB : this is case sensitive
*/
static void registerUserFct(const char *name, TUserFct fct);
// Simple evaluations
static bool evalAsInt(const std::string &expr, sint64 &dest);
static bool evalAsDouble(const std::string &expr, double &dest);
static bool evalAsBool(const std::string &expr, bool &dest);
static bool evalAsString(const std::string &expr, std::string &dest);
/////////////////////////////////////////////////////////////////////////////////////////////
private:
// map of user functions
typedef std::map TUserFctMap;
private:
static TUserFctMap *_UserFct;
private:
/** eval the value of a single expression
* \return position to the next valid character
*/
static const char *evalExpr(const char *expr, CInterfaceExprValue &result, std::vector *nodes, bool noFctCalls);
static const char *evalFct(const char *expr,CInterfaceExprValue &result,std::vector *nodes, bool noFctCalls);
static const char *evalDBEntry(const char *expr,CInterfaceExprValue &result,std::vector *nodes);
public:
static const char *unpackDBentry(const char *expr, std::vector *nodes, std::string &dest, bool *hasIndirections = NULL);
/** Build tree of a single expression
* \return position to the next valid character
*/
private:
static const char *buildExprTree(const char *expr, CInterfaceExprNode *&result);
static const char *buildFctNode(const char *expr, CInterfaceExprNode *&result);
static const char *buildDBEntryNode(const char *expr,CInterfaceExprNode *&result);
};
// helper macro to register user functions at startup
#define REGISTER_INTERFACE_USER_FCT(name, fct) \
const struct __InterUserFctRegister__##fct\
{\
__InterUserFctRegister__##fct() { CInterfaceExpr::registerUserFct(name, fct); }\
} __InterUserFctRegisterInstance__##fct;
// helper macro to declare a user function
// the code must follow
// arguments are available in 'args', result should be put in 'result'
#define DECLARE_INTERFACE_USER_FCT(name) \
bool name(CInterfaceExpr::TArgList &args, CInterfaceExprValue &result)
// helper macro to declare a C constant mirroring
#define DECLARE_INTERFACE_CONSTANT(_name, _cconst) \
static DECLARE_INTERFACE_USER_FCT(_name) \
{ \
result.setInteger(_cconst); \
return true; \
} \
REGISTER_INTERFACE_USER_FCT(#_name, _name)
#endif