d866477a18db633a8e70ffb9ce904ca70c8defa9
[platform/upstream/syncevolution.git] / src / synthesis / src / sysync / scriptcontext.h
1 /*
2  *  File:         scriptcontext.cpp
3  *
4  *  Author:                       Lukas Zeller (luz@synthesis.ch)
5  *
6  *  TScriptContext
7  *    Environment to tokenize, prepare and run scripts
8  *
9  *  Copyright (c) 2002-2009 by Synthesis AG (www.synthesis.ch)
10  *
11  *  2002-09-11 : luz : created
12  *
13  *
14  */
15
16 #ifdef SCRIPT_SUPPORT
17
18 #ifndef SCRIPT_CONTEXT_H
19 #define SCRIPT_CONTEXT_H
20
21 // includes
22 #include "sysync.h"
23
24
25 #include "itemfield.h"
26 #include "multifielditem.h"
27
28
29 using namespace sysync;
30
31 namespace sysync {
32
33
34 /*
35  * builtin function definitions
36  */
37
38 #define PARAM_TYPEMASK 0x1F
39 #define PARAM_OPT      0x20
40 #define PARAM_REF      0x40
41 #define PARAM_ARR      0x80
42
43 #define VAL(x)    ( (uInt8)x)
44 #define OPTVAL(x) (((uInt8)x)+PARAM_OPT)
45 #define REF(x)    (((uInt8)x)+PARAM_REF)
46 #define REFARR(x) (((uInt8)x)+PARAM_REF+PARAM_ARR)
47
48
49 // Token definitions
50
51 // - Multi-Byte tokens:
52 //   tldddddddddddddd
53 //   - t=token ID alphanum.
54 //   - l=length of additional token data, 0x00..0xFF as one char
55 //   - dddddd=additional token data
56
57 // highest Multibyte token
58 #define TK_MAX_MULTIBYTE 0x1F
59
60 // - literals, dddd=literal string
61 #define TK_NUMERIC_LITERAL 0x10
62 #define TK_STRING_LITERAL 0x11
63 // - variable identifiers, dddd = idddddd
64 //   where i=room for field index, dddd=identifier
65 #define TK_IDENTIFIER 0x12
66 // - script line token, dd = line number 16bit, followed by source text (NUL terminated) if script debug on
67 #define TK_SOURCELINE 0x13
68 // - object specifier, d=single object index byte
69 #define TK_OBJECT 0x14
70 // - builtin function identifier, d=function index
71 #define TK_FUNCTION 0x15
72 // - user defined function identifier, idddddd i=room for function index, ddd=function name
73 #define TK_USERFUNCTION 0x16
74 // - built-in context-dependent function
75 #define TK_CONTEXTFUNCTION 0x17
76
77 // - type definition, d=TItemFieldTypes enum
78 #define TK_TYPEDEF 0x18
79
80
81 // object indices
82 #define OBJ_AUTO 0 // not specified, is local or target field
83 #define OBJ_LOCAL 1 // local variable
84 #define OBJ_TARGET 2 // target field
85 #define OBJ_REFERENCE 3 // reference field
86
87
88
89 // - language elements, 0x80..0x9F
90 #define TK_IF 0x80
91 #define TK_ELSE 0x81
92 #define TK_LOOP 0x82
93 #define TK_BREAK 0x83
94 #define TK_CONTINUE 0x84
95 #define TK_RETURN 0x85
96 #define TK_WHILE 0x86
97
98 // - constants
99 #define TK_EMPTY 0x90
100 #define TK_UNASSIGNED 0x91
101 #define TK_TRUE 0x92
102 #define TK_FALSE 0x93
103
104 // - grouping, in the 0x20..0x3F area
105 #define TK_DOMAINSEP '.'
106 #define TK_OPEN_PARANTHESIS '('
107 #define TK_CLOSE_PARANTHESIS ')'
108 #define TK_LIST_SEPARATOR ','
109 #define TK_BEGIN_BLOCK 0x30
110 #define TK_END_BLOCK 0x31
111 #define TK_END_STATEMENT ';'
112 #define TK_OPEN_ARRAY 0x32
113 #define TK_CLOSE_ARRAY 0x33
114
115 // - operators, in the 0x40..0x7F range
116 //   in order of precedence (upper 6 bits = precedence)
117 #define TK_OP_PRECEDENCE_MASK 0xFC
118 #define TK_BINOP_MIN 0x44
119 #define TK_BINOP_MAX 0x68 // excluding assignment %%%
120
121 //   Pure unaries
122 //   - negation
123 #define TK_BITWISENOT 0x40
124 #define TK_LOGICALNOT 0x41
125
126 //   Binaries (some of them also used as unaries, like MINUS)
127 //   - multiply, divide
128 #define TK_MULTIPLY 0x44
129 #define TK_DIVIDE 0x45
130 #define TK_MODULUS 0x46
131 //   - add, subtract
132 #define TK_PLUS 0x48
133 #define TK_MINUS 0x49
134 //   - shift
135 #define TK_SHIFTLEFT 0x4C
136 #define TK_SHIFTRIGHT 0x4D
137 //   - comparison
138 #define TK_LESSTHAN 0x50
139 #define TK_GREATERTHAN 0x51
140 #define TK_LESSEQUAL 0x52
141 #define TK_GREATEREQUAL 0x53
142 //   - equality
143 #define TK_EQUAL 0x54
144 #define TK_NOTEQUAL 0x55
145 //   - bitwise AND
146 #define TK_BITWISEAND 0x58
147 //   - bitwise XOR
148 #define TK_BITWISEXOR 0x5C
149 //   - bitwise OR
150 #define TK_BITWISEOR 0x60
151 //   - logical AND
152 #define TK_LOGICALAND 0x64
153 //   - logical OR
154 #define TK_LOGICALOR 0x68
155
156 //   Special modifying operator
157 //   - assignment
158 #define TK_ASSIGN 0x6C
159
160
161 // local script variable definition
162 class TScriptVarDef
163 {
164 public:
165   TScriptVarDef(cAppCharP aName,uInt16 aIdx, TItemFieldTypes aType, bool aIsArray, bool aIsRef, bool aIsOpt);
166   ~TScriptVarDef();
167   uInt16 fIdx; // index (position in container).
168   string fVarName;  // Variable name
169   TItemFieldTypes fVarType; // type of variable
170   bool fIsArray;
171   bool fIsRef; // set if this is a local reference to an existing variable
172   bool fIsOpt; // set if this is a optional parameter
173 }; // TScriptVarDef
174
175
176 // script variables
177 typedef std::vector<TScriptVarDef *> TVarDefs;
178
179
180 // user defined script function
181 class TUserScriptFunction
182 {
183 public:
184   string fFuncName;
185   string fFuncDef;
186 }; // TUserScriptFunction
187
188 typedef std::vector<TUserScriptFunction *> TUserScriptList;
189
190 // global script config (such as user-defined functions)
191 class TScriptConfig : public TConfigElement
192 {
193   typedef TConfigElement inherited;
194 public:
195   TScriptConfig(TConfigElement *aParentElementP);
196   virtual ~TScriptConfig();
197   // properties
198   uInt32 fMaxLoopProcessingTime; // seconds
199   // special scripts
200   // user-defined functions
201   TUserScriptList fFunctionScripts;
202   // macros (pure texts used while parsing)
203   TStringToStringMap fScriptMacros;
204   // accessing user defined functions
205   string *getFunctionScript(sInt16 aFuncIndex);
206   sInt16 getFunctionIndex(cAppCharP aName, size_t aLen);
207   virtual void clear();
208   void clearmacros() { fScriptMacros.clear(); }; // called when config is read, as then templates are no longer needed
209 protected:
210   // check config elements
211   virtual bool localStartElement(const char *aElementName, const char **aAttributes, sInt32 aLine);
212   virtual void localResolve(bool aLastPass);
213 }; // TScriptConfig
214
215
216 // script tokenizing error
217 class TTokenizeException : public TConfigParseException
218 {
219   typedef TConfigParseException inherited;
220 public:
221   TTokenizeException(cAppCharP aScriptName, cAppCharP aMsg1,cAppCharP aScript, uInt16 aIndex, uInt16 aLine);
222 }; // TTokenizeException
223
224
225 // script resolving or execution error
226 class TScriptErrorException : public TConfigParseException
227 {
228   typedef TConfigParseException inherited;
229 public:
230   TScriptErrorException(cAppCharP aMsg1, uInt16 aLine, cAppCharP aIdent=NULL);
231 }; // TScriptErrorException
232
233
234 // folder mapping table
235 typedef std::vector<string> TMacroArgsArray;
236
237
238 // script execution state stack
239 typedef enum {
240   ssta_statement,
241   ssta_block,
242   ssta_if,
243   ssta_else,
244   ssta_chainif,
245   ssta_loop,
246   ssta_while,
247 } TScriptState;
248
249 typedef struct {
250   TScriptState state; // state
251   cUInt8P begin; // begin of that state in source
252   uInt16 line; // line number
253 } TScriptStackEntry;
254
255 // flow control stack depth
256 const sInt16 maxstackentries=40;
257
258 class TMultiFieldItem;
259
260 // script context
261 class TScriptContext
262 {
263   friend class TScriptVarKey;
264 public:
265   TScriptContext(TSyncAppBase *aAppBaseP, TSyncSession *aSessionP);
266   virtual ~TScriptContext();
267   // Tokenizing is available without context
268   static void Tokenize(TSyncAppBase *aAppBaseP, cAppCharP aScriptName, sInt32 aLine, cAppCharP aScriptText, string &aTScript, const TFuncTable *aContextFuncs, bool aFuncHeader=false, bool aNoDeclarations=false, TMacroArgsArray *aMacroArgsP=NULL);
269   static void TokenizeAndResolveFunction(TSyncAppBase *aAppBaseP, sInt32 aLine, cAppCharP aScriptText, TUserScriptFunction &aFuncDef);
270   // resolve identifiers in a script, if there is a context passed at all
271   static void resolveScript(TSyncAppBase *aAppBaseP, string &aTScript,TScriptContext *&aCtxP, TFieldListConfig *aFieldListConfigP);
272   // rebuild a script context for a script, if the script is not empty
273   // - Script must already be resolved with ResolveIdentifiers
274   // - If context already exists, adds new locals to existing ones
275   // - If aBuildVars is set, buildVars() will be called after rebuilding variable definitions
276   static void rebuildContext(TSyncAppBase *aAppBaseP, string &aTScript,TScriptContext *&aCtxP, TSyncSession *aSessionP=NULL, bool aBuildVars=false);
277   // - link a script into a contect with already instantiated variables. This is e.g. for activating remoterule scripts
278   static void linkIntoContext(string &aTScript,TScriptContext *aCtxP, TSyncSession *aSessionP);
279   // Build the local variables according to definitions (clears existing vars first)
280   static void buildVars(TScriptContext *&aCtxP);
281   // execute a script if there is a context for it
282   bool static execute(
283     TScriptContext *aCtxP,
284     const string &aTScript,
285     const TFuncTable *aFuncTableP, // context's function table, NULL if none
286     void *aCallerContext, // free pointer eventually having a meaning for context functions
287     TMultiFieldItem *aTargetItemP=NULL, // target (or "loosing") item
288     bool aTargetWritable=true, // if set, target item may be modified
289     TMultiFieldItem *aReferenceItemP=NULL, // reference for source (or "old" or "winning") item
290     bool aRefWritable=false, // if set, reference item may also be written
291     bool aNoDebug=false // if set, debug output is suppressed even if DBG_SCRIPTS is generally on
292   );
293   // execute a script returning a boolean if there is a context for it
294   bool static executeTest(
295     bool aDefaultAnswer, // result if no script is there or script returns no value
296     TScriptContext *aCtxP,
297     const string &aTScript,
298     const TFuncTable *aFuncTableP, // context's function table, NULL if none
299     void *aCallerContext, // free pointer eventually having a meaning for context functions
300     TMultiFieldItem *aTargetItemP=NULL, // target (or "loosing") item
301     bool aTargetWritable=true, // if set, target item may be modified
302     TMultiFieldItem *aReferenceItemP=NULL, // reference for source (or "old" or "winning") item
303     bool aRefWritable=false // if set, reference item may also be written
304   );
305   // execute a script returning a result if there is a context for it
306   bool static executeWithResult(
307     TItemField *&aResultField, // can be default result or NULL, will contain result or NULL if no result
308     TScriptContext *aCtxP,
309     const string &aTScript,
310     const TFuncTable *aFuncTableP, // context's function table, NULL if none
311     void *aCallerContext, // free pointer eventually having a meaning for context functions
312     TMultiFieldItem *aTargetItemP, // target (or "loosing") item
313     bool aTargetWritable, // if set, target item may be modified
314     TMultiFieldItem *aReferenceItemP, // reference for source (or "old" or "winning") item
315     bool aRefWritable, // if set, reference item may also be written
316     bool aNoDebug=false // if set, debug output is suppressed even if DBG_SCRIPTS is generally on
317   );
318   // get info
319   uInt16 getScriptLine(void) { return line; };
320   // get context pointers
321   TSyncSession *getSession(void) { return fSessionP; };
322   TSyncAppBase *getSyncAppBase(void) { return fAppBaseP; };
323   GZones *getSessionZones(void);
324   #ifdef SYDEBUG
325   TDebugLogger *getDbgLogger(void);
326   uInt32 getDbgMask(void);
327   #endif
328   // Reset context (clear all variables and definitions)
329   void clear(void);
330   // clear all fields (local variables), but not their definitions
331   void clearFields(void);
332   // Resolve local variable declarations, references and field references
333   void ResolveIdentifiers(
334     string &aTScript,
335     TFieldListConfig *aFieldListConfigP,
336     bool aRebuild=false,
337     string *aFuncNameP=NULL,
338     bool aNoNewLocals=false // if set, declaration of new locals will be suppressed
339   );
340   // Prepare local variables (create local fields), according to definitions (re-)built with ResolveIdentifiers()
341   bool PrepareLocals(void);
342   // Execute script
343   bool ExecuteScript(
344     const string &aTScript,
345     TItemField **aResultPP, // if not NULL, a result field will be returned here (must be deleted by caller)
346     bool aAsFunction, // if set, this is a function call
347     const TFuncTable *aFuncTableP, // context's function table, NULL if none
348     void *aCallerContext, // free pointer eventually having a meaning for context functions
349     TMultiFieldItem *aTargetItemP, // target (or "loosing") item
350     bool aTargetWritable, // if set, target item may be modified
351     TMultiFieldItem *aReferenceItemP, // reference for source (or "old" or "winning") item
352     bool aRefWritable, // if set, reference item may also be written
353     bool aNoDebug=false // if set, debug output is suppressed even if DBG_SCRIPTS is generally on
354   );
355   // context variable access
356   // - get variable definition, NULL if none defined yet
357   TScriptVarDef *getVarDef(cAppCharP aVarName,size_t len=0);
358   TScriptVarDef *getVarDef(sInt16 aLocalVarIdx);
359   // - get identifier index (>=0: field index, <0: local var)
360   //   returns VARIDX_UNDEFINED for unknown identifier
361   sInt16 getIdentifierIndex(sInt16 aObjIndex, TFieldListConfig *aFieldListConfigP, cAppCharP aIdentifier,size_t aLen=0);
362   // - get field by fid, can also be field of aItem, also resolves arrays
363   TItemField *getFieldOrVar(TMultiFieldItem *aItemP, sInt16 aFid, sInt16 aArrIdx);
364   // - get field by fid, can also be field of aItem
365   TItemField *getFieldOrVar(TMultiFieldItem *aItemP, sInt16 aFid);
366   // - get local var by local index
367   TItemField *getLocalVar(sInt16 aVarIdx);
368   // - set local var by local index (used for passing references)
369   void setLocalVar(sInt16 aVarIdx, TItemField *aFieldP);
370   sInt16 getNumLocals(void) { return fNumVars; };
371   // - parameters
372   sInt16 getNumParams(void) { return fNumParams; };
373   // - caller's context data pointer (opaque, for use by context functions)
374   void *getCallerContext(void) { return fCallerContext; };
375 private:
376   // syncappbase link, must always exist
377   TSyncAppBase *fAppBaseP;
378   // session link, can be NULL
379   TSyncSession *fSessionP;
380   // local variable definitions (used in resolve phase)
381   TVarDefs fVarDefs;
382   // actually instantiated local variable fields (size of fFieldsP array, used at execution)
383   // Note: might differ from fVarDefs when new vars have been defined, but not instantiated yet)
384   uInt16 fNumVars;
385   // function properties (if context is a function context)
386   uInt16 fNumParams; // this determines the number of parameter locals
387   TItemFieldTypes fFuncType; // return type of function
388   // The local variables and field references
389   TItemField **fFieldsP;
390   // script parsing
391   // - variables
392   sInt16 skipping; // skipping
393   uInt16 line,nextline; // line numbers
394   cUInt8P bp; // start of script
395   cUInt8P ep; // end of script
396   cUInt8P p; // cursor, start at beginning
397   cUInt8P np; // next token
398   #ifdef SYDEBUG
399   const char *scriptname; // name of script
400   const char *linesource; // start of embedded source for current line
401   bool executing; // set if executing (not resolving)
402   bool debugon; // set if debug enabled
403   bool inComment; // for colorizer
404   #endif
405   // - helpers
406   void initParse(const string &aTScript, bool aExecuting=false); // init parsing variables
407   uInt8 gettoken(void); // get next token
408   void reusetoken(void); // re-use last token fetched with gettoken()
409   // script execution
410   // - flow control state stack
411   sInt16 fStackEntries;
412   TScriptStackEntry fScriptstack[maxstackentries];
413   // - context information
414 public:
415   //   Items
416   TMultiFieldItem *fTargetItemP;
417   bool fTargetWritable;
418   TMultiFieldItem *fReferenceItemP;
419   bool fRefWritable;
420   //   Link to calling script context (for function contexts)
421   TScriptContext *fParentContextP;
422 private:
423   //   Function table
424   const TFuncTable *fFuncTableP; // caller context's function table
425   void *fCallerContext; // free pointer eventually having a meaning for context functions
426   // - helpers
427   void pushState(TScriptState aNewState, cUInt8P aBegin=NULL, uInt16 aLine=0);
428   void popState(TScriptState aCurrentStateExpected);
429   bool getVarField(TItemField *&aItemFieldP);
430   void evalParams(TScriptContext *aFuncContextP);
431   TItemField *evalTerm(TItemFieldTypes aResultType);
432   void evalExpression(
433     TItemField *&aResultFieldP, // result (created new if passed NULL, modified and casted if passed a field)
434     bool aShowResult=true, // if set, this is the main expression (and we want to see the result in DBG)
435     TItemField *aLeftTermP=NULL, // if not NULL, chain-evaluate rest of expression according to aBinaryOp and aPreviousOp. WILL BE CONSUMED
436     uInt8 *aBinaryOpP=NULL, // operator to be applied between term passed in aLeftTermP and next term, will receive next operator that has same or lower precedence than aPreviousOp
437     uInt8 aPreviousOp=0 // if an operator of same or lower precedence than this is found, expression evaluation ends
438   );
439   void defineBuiltInVars(const TBuiltInFuncDef *aFuncDefP);
440   void executeBuiltIn(TItemField *&aTermP, const TBuiltInFuncDef *aFuncDefP);
441   #ifdef SYDEBUG
442   void showVarDefs(cAppCharP aTxt);
443   #endif
444 }; // TScriptContext
445
446
447 #ifdef ENGINEINTERFACE_SUPPORT
448
449
450 // key for access to script context variables
451 class TScriptVarKey :
452   public TItemFieldKey
453 {
454   typedef TItemFieldKey inherited;
455 public:
456   TScriptVarKey(TEngineInterface *aEngineInterfaceP, TScriptContext *aScriptContext) :
457     inherited(aEngineInterfaceP),
458     fScriptContext(aScriptContext), // may be NULL, no vars will be accessible then but no crash occurs
459     fIterator(0)
460   {};
461
462 protected:
463
464   // methods to actually access a TItemField
465   virtual sInt16 getFidFor(cAppCharP aName, stringSize aNameSz);
466   virtual TItemField *getBaseFieldFromFid(sInt16 aFid);
467   virtual bool getFieldNameFromFid(sInt16 aFid, string &aFieldName);
468
469   // the script context
470   TScriptContext *fScriptContext;
471   // value iterator
472   sInt16 fIterator;
473
474 }; // TScriptVarKey
475
476
477 #endif // ENGINEINTERFACE_SUPPORT
478
479
480 } // namespace sysync
481
482 #endif // SCRIPT_CONTEXT_H
483
484 #endif // SCRIPT_SUPPORT
485
486 /* eof */