1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2019 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "nel/misc/smart_ptr.h"
31 /****************************************************************************/
32 /* Compiler classes */
33 /****************************************************************************/
34 //////////////////////////////////////////////////////////////////////////////
36 //////////////////////////////////////////////////////////////////////////////
38 /// A helper class seperating a string in substrings seperated by a pattern.
39 /** Be carefull, this objet keeps a reference to the string.
41 class CStringSeparator
44 CStringSeparator(std::string
const& str
, std::string
const& pattern
);
45 virtual ~CStringSeparator();
47 std::string
get() const;
50 void calcNext() const;
52 mutable size_t _Index
;
53 mutable size_t _NewIndex
;
54 mutable size_t _Delta
;
55 mutable size_t _StartIndex
;
56 std::string
const& _Str
;
57 std::string
const _Motif
;
60 /****************************************************************************/
61 /* Script Virtual Machine classes */
62 /****************************************************************************/
64 //////////////////////////////////////////////////////////////////////////////
65 // ByteCode interpretation //
66 //////////////////////////////////////////////////////////////////////////////
68 class CByteCode
: public NLMISC::CRefCount
71 CByteCode(std::string
const& sourceName
);
72 std::vector
<size_t> _opcodes
;
73 std::string
const _sourceName
;
76 class CByteCodeEntry
{
79 : _Index(std::numeric_limits
<size_t>::max())
82 CByteCodeEntry(NLMISC::CSmartPtr
<CByteCode
const> code
, size_t index
)
89 return _Index
!= std::numeric_limits
<size_t>::max();
91 NLMISC::CSmartPtr
<CByteCode
const>& code() { return _Code
; }
92 size_t& index() { return _Index
; }
93 NLMISC::CSmartPtr
<CByteCode
const> const& code() const { return _Code
; }
94 size_t const& index() const { return _Index
; }
96 NLMISC::CSmartPtr
<CByteCode
const> _Code
;
100 //////////////////////////////////////////////////////////////////////////////
102 class IScriptContext
;
107 enum TStackTypes
{ ENone
, EOther
, EString
, EFloat
, EContext
};
117 CStackEntry
& operator=(float const& f
);
118 CStackEntry
& operator=(int const& i
);
119 CStackEntry
& operator=(std::string
const& str
);
120 CStackEntry
& operator=(IScriptContext
* si
);
122 bool operator==(CStackEntry
const& other
) const;
123 bool operator!=(CStackEntry
const& other
) const;
124 bool operator<=(CStackEntry
const& other
) const;
125 bool operator>=(CStackEntry
const& other
) const;
126 bool operator<(CStackEntry
const& other
) const;
127 bool operator>(CStackEntry
const& other
) const;
131 operator std::string
&();
132 operator IScriptContext
*();
133 TStackTypes
type() const;
136 std::string
& getString();
137 std::string
const& getString() const;
138 IScriptContext
* getIScriptContext();
140 int const& getInt() const;
142 float const& getFloat() const;
153 void push(float const& val
);
154 void push(std::string
const& val
);
155 void push(IScriptContext
* val
);
158 CStackEntry
& top(); // is this an optimisation of the method below ?
159 CStackEntry
& top(int index
);
166 return _Stack
.size();
171 std::deque
<CStackEntry
> _Stack
;
174 //////////////////////////////////////////////////////////////////////////////
179 virtual std::string
getContextName() = 0;
180 virtual void interpretCodeOnChildren(CByteCodeEntry
const& codeScriptEntry
) = 0;
182 virtual float getLogicVar(NLMISC::TStringId varId
) = 0;
183 virtual void setLogicVar(NLMISC::TStringId varId
, float value
) = 0;
184 virtual std::string
getStrLogicVar(NLMISC::TStringId varId
) = 0;
185 virtual void setStrLogicVar(NLMISC::TStringId varId
, std::string
const& value
) = 0;
186 virtual IScriptContext
* getCtxLogicVar(NLMISC::TStringId varId
) = 0;
187 virtual void setCtxLogicVar(NLMISC::TStringId varId
, IScriptContext
* value
) = 0;
189 virtual IScriptContext
* findContext(NLMISC::TStringId
const strId
) = 0;
191 virtual void setScriptCallBack(NLMISC::TStringId
const& eventName
, CByteCodeEntry
const& codeScriptEntry
) = 0;
192 virtual CByteCodeEntry
const* getScriptCallBackPtr(NLMISC::TStringId
const& eventName
) const = 0;
193 virtual void callScriptCallBack(IScriptContext
* caller
, NLMISC::TStringId
const& funcName
, int mode
= 0, std::string
const& inParamsSig
= "", std::string
const& outParamsSig
= "", CScriptStack
* stack
= NULL
) = 0;
194 virtual void callNativeCallBack(IScriptContext
* caller
, std::string
const& funcName
, int mode
= 0, std::string
const& inParamsSig
= "", std::string
const& outParamsSig
= "", CScriptStack
* stack
= NULL
) = 0;
200 // Operations behave on stack elems.
203 /*00*/ INVALID_OPCODE
=0,
204 /*01*/ EOP
, // End Of Program
206 // Need: FuncName, NbParams, Params .. After: ReturnValue (1)
207 /*02*/ EQ
, // == StackBef: Value1,Value2 StackAft: Value1==Value2 (Boolean as float)
208 /*03*/ NEQ
, // != StackBef: Value1,Value2 StackAft: Value1!=Value2 (Boolean as float)
209 /*04*/ INF
, // < StackBef: Value1,Value2 StackAft: Value1<Value2 (Boolean as float)
210 /*05*/ INFEQ
, // <= StackBef: Value1,Value2 StackAft: Value1<=Value2 (Boolean as float)
211 /*06*/ SUP
, // > StackBef: Value1,Value2 StackAft: Value1>Value2 (Boolean as float)
212 /*07*/ SUPEQ
, // >= StackBef: Value1,Value2 StackAft: Value1>=Value2 (Boolean as float)
213 /*08*/ ADD
, // + StackBef: Value1,Value2 StackAft: Value1+Value2
214 /*09*/ SUB
, // - StackBef: Value1,Value2 StackAft: Value1-Value2
215 /*0a*/ MUL
, // * StackBef: Value1,Value2 StackAft: Value1/Value2
216 /*0b*/ DIV
, // / StackBef: Value1,Value2 StackAft: Value1/Value2 !Exception Gestion.
217 /*0c*/ AND
, // && StackBef: Value1,Value2 StackAft: Value1&&Value2
218 /*0d*/ OR
, // || StackBef: Value1,Value2 StackAft: Value1||Value2
219 /*0e*/ NOT
, // ! StackBef: Value StackAft: !Value
220 /*0f*/ PUSH_ON_STACK
, // Set a Value (Float,TStringId .. etc) StackBef: - StackAft: Value
221 /*10*/ POP
, // Pop StackBef: Value StackAft: -
222 /*11*/ SET_VAR_VAL
, // Set a value to a float variable. Code: VarName StackBef: VarValue StackAft: -
223 /*12*/ SET_STR_VAR_VAL
, // Set a value to a string variable. Code: VarName StackBef: VarValue StackAft: -
224 /*13*/ SET_CTX_VAR_VAL
, // Set a value to a context variable. Code: VarName StackBef: VarValue StackAft: -
225 /*14*/ PUSH_VAR_VAL
, // Push the value of a float variable. Code: VarName StackBef: - StackAft: VarValue
226 /*15*/ PUSH_STR_VAR_VAL
, // Push the value of a string variable. Code: VarName StackBef: - StackAft: VarValue
227 /*16*/ PUSH_CTX_VAR_VAL
, // Push the value of a context variable. Code: VarName StackBef: - StackAft: VarValue
228 /*17*/ // SET_OTHER_VAR_VAL, // Set a value to a float variable in another group. Code: GroupName,VarName StackBef: VarValue StackAft: -
229 /*18*/ // SET_OTHER_STR_VAR_VAL, // Set a value to a string variable in another group. Code: GroupName,VarName StackBef: VarValue StackAft: -
230 /*19*/ // SET_OTHER_CTX_VAR_VAL, // Set a value to a context variable in another group. Code: GroupName,VarName StackBef: VarValue StackAft: -
231 /*1a*/ // PUSH_OTHER_VAR_VAL, // Push the value of a float variable of another group. Code: GroupName,VarName StackBef: - StackAft: VarValue
232 /*1b*/ // PUSH_OTHER_STR_VAR_VAL, // Push the value of a string variable of another group. Code: GroupName,VarName StackBef: - StackAft: VarValue
233 /*1c*/ // PUSH_OTHER_CTX_VAR_VAL, // Push the value of a context variable of another group. Code: GroupName,VarName StackBef: - StackAft: VarValue
234 /*1d*/ SET_CONTEXT_VAR_VAL
, // Set a value to a float variable in another group. Code: VarName StackBef: VarValue,Group StackAft: -
235 /*1e*/ SET_CONTEXT_STR_VAR_VAL
, // Set a value to a float variable in another group. Code: VarName StackBef: VarValue,Group StackAft: -
236 /*1f*/ SET_CONTEXT_CTX_VAR_VAL
, // Set a value to a float variable in another group. Code: VarName StackBef: VarValue,Group StackAft: -
237 /*20*/ PUSH_CONTEXT_VAR_VAL
, // Push the value of a float variable of another group. Code: VarName StackBef: Group StackAft: VarValue
238 /*21*/ PUSH_CONTEXT_STR_VAR_VAL
, // Push the value of a float variable of another group. Code: VarName StackBef: Group StackAft: VarValue
239 /*22*/ PUSH_CONTEXT_CTX_VAR_VAL
, // Push the value of a float variable of another group. Code: VarName StackBef: Group StackAft: VarValue
240 /*23*/ JUMP
, // Jump + nb size_t to jump (relative). Code: JumpOffset StackBef: - StackAft: - //< May be innaccurate
241 /*24*/ JE
, // Jump if last stack value is FALSE(==0). Code: JumpOffset StackBef: Bool(float) StackAft: - //< May be innaccurate
242 /*25*/ JNE
, // Jump if last stack value is TRUE(==1). Code: JumpOffset StackBef: Bool(float) StackAft: - //< May be innaccurate
243 /*26*/ PUSH_PRINT_STRING
,
244 /*27*/ PUSH_PRINT_VAR
,
245 /*28*/ PUSH_PRINT_STR_VAR
,
253 /*30*/ ASSIGN_FUNC_FROM
,
257 /*34*/ RET
, // Get the value on the pile to retrieve the good IP (absolute).
268 IScriptContext
* thisContext
,
269 IScriptContext
* parentContext
,
270 IScriptContext
* callerContext
,
271 CByteCodeEntry
const& codeScriptEntry
);
272 static CScriptVM
* getInstance();
273 static void destroyInstance();
275 uint32
rand32(uint32 mod
)
277 if (mod
==0) return 0;
278 return ((((uint32
)_Random
.rand())<<16) + (uint32
)_Random
.rand()) % mod
;
280 static CScriptVM
* _Instance
;
281 NLMISC::CRandom _Random
;
284 //////////////////////////////////////////////////////////////////////////////
289 static CLibrary
& getInstance();
290 static void destroyInstance();
292 void addLib(std::string
const& name
, std::string
const& code
);
293 void addLib(std::string
const& name
, std::vector
<std::string
> const& code
);
294 void addLib(std::string
const& name
, NLMISC::CSmartPtr
<CByteCode
const> const& byteCode
);
295 NLMISC::CSmartPtr
<CByteCode
const> getLib(std::string
const& name
);
301 typedef std::map
<std::string
, NLMISC::CSmartPtr
<CByteCode
const> > TLibContainer
;
302 static CLibrary
* _instance
;
303 static TLibContainer _libs
;
306 /****************************************************************************/
307 /* Inlined functions */
308 /****************************************************************************/
311 CByteCode::CByteCode(std::string
const& sourceName
)
312 : _sourceName(sourceName
)
317 CLibrary
& CLibrary::getInstance()
320 _instance
= new CLibrary();
325 void CLibrary::destroyInstance()
335 CScriptStack::CStackEntry::CStackEntry()
341 CScriptStack::CStackEntry::~CStackEntry()
347 void CScriptStack::CStackEntry::clean()
354 CScriptStack::CStackEntry
& CScriptStack::CStackEntry::operator=(float const& f
)
362 CScriptStack::CStackEntry
& CScriptStack::CStackEntry::operator=(int const& i
)
370 CScriptStack::CStackEntry
& CScriptStack::CStackEntry::operator=(std::string
const& str
)
373 std::string
* const strPt
= new std::string(str
);
374 _valp
= *((uintptr_t*)&strPt
);
379 CScriptStack::CStackEntry
& CScriptStack::CStackEntry::operator=(IScriptContext
* sc
)
382 _valp
= *((uintptr_t*)&sc
);
388 bool CScriptStack::CStackEntry::operator==(CStackEntry
const& other
) const
390 nlassert(_type
==other
._type
);
394 return getString()==other
.getString();
396 return getFloat()==other
.getFloat();
398 return _valp
==other
._valp
;
401 return _vali
==other
._vali
;
406 bool CScriptStack::CStackEntry::operator!=(CStackEntry
const& other
) const
408 return !(*this == other
);
412 bool CScriptStack::CStackEntry::operator<=(CStackEntry
const& other
) const
414 return !(*this > other
);
418 bool CScriptStack::CStackEntry::operator>=(CStackEntry
const& other
) const
420 return !(*this < other
);
424 bool CScriptStack::CStackEntry::operator<(CStackEntry
const& other
) const
426 nlassert(_type
==other
._type
);
430 return getString()<other
.getString();
432 return getFloat()<other
.getFloat();
434 return _valp
<other
._valp
;
437 return _vali
<other
._vali
;
442 bool CScriptStack::CStackEntry::operator>(CStackEntry
const& other
) const
444 nlassert(_type
==other
._type
);
448 return getString()>other
.getString();
450 return getFloat()>other
.getFloat();
452 return _valp
>other
._valp
;
455 return _vali
>other
._vali
;
460 CScriptStack::CStackEntry::operator float&()
465 CScriptStack::CStackEntry::operator int&()
470 CScriptStack::CStackEntry::operator std::string
&()
475 CScriptStack::CStackEntry::operator IScriptContext
*()
477 return getIScriptContext();
481 CScriptStack::TStackTypes
CScriptStack::CStackEntry::type() const
487 std::string
& CScriptStack::CStackEntry::getString()
489 nlassert(_type
==EString
);
490 return *(*((std::string
**)&_valp
));
493 std::string
const& CScriptStack::CStackEntry::getString() const
495 nlassert(_type
==EString
);
496 return *(*((std::string
**)&_valp
));
499 IScriptContext
* CScriptStack::CStackEntry::getIScriptContext()
501 nlassert(_type
==EContext
);
502 return *((IScriptContext
**)&_valp
);
505 int& CScriptStack::CStackEntry::getInt()
507 nlassert(_type
==EOther
);
511 int const& CScriptStack::CStackEntry::getInt() const
513 nlassert(_type
==EOther
);
517 float& CScriptStack::CStackEntry::getFloat()
519 nlassert(_type
==EFloat
);
520 return *((float*)&_vali
);
523 float const& CScriptStack::CStackEntry::getFloat() const
525 nlassert(_type
==EFloat
);
526 return *((float const*)&_vali
);
530 void CScriptStack::push(float const& val
)
532 _Stack
.push_back(CStackEntry());
536 void CScriptStack::push(std::string
const& val
)
538 _Stack
.push_back(CStackEntry());
542 void CScriptStack::push(IScriptContext
* val
)
544 _Stack
.push_back(CStackEntry());
548 void CScriptStack::push(int val
)
550 _Stack
.push_back(CStackEntry());
555 CScriptStack::CStackEntry
& CScriptStack::top() // is this an optimisation of the method below ?
557 return _Stack
.back();
560 CScriptStack::CStackEntry
& CScriptStack::top(int index
)
562 return *(_Stack
.rbegin()+index
);
566 void CScriptStack::pop()
572 CStringSeparator::CStringSeparator(const std::string
&str
, const std::string
&motif
)
582 CStringSeparator::~CStringSeparator()
586 void CStringSeparator::reset() const
594 std::string
CStringSeparator::get() const
599 return _Str
.substr(_StartIndex
, _Delta
);
602 bool CStringSeparator::hasNext() const
608 void CStringSeparator::calcNext() const
611 while ( _Index
!=std::string::npos
614 _NewIndex
= _Str
.find_first_of(_Motif
, _Index
);
615 _StartIndex
= _Index
;
616 _Delta
= ((_NewIndex
==std::string::npos
)?_Str
.size():_NewIndex
)-_Index
;
617 if (_NewIndex
==std::string::npos
)
619 _Index
= std::string::npos
;
622 _Index
= _Str
.find_first_not_of(_Motif
, _NewIndex
);