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