2 * File: scriptcontext.cpp
4 * Author: Lukas Zeller (luz@plan44.ch)
7 * Environment to tokenize, prepare and run scripts
9 * Copyright (c) 2002-2011 by Synthesis AG + plan44.ch
11 * 2002-09-11 : luz : created
18 #ifndef SCRIPT_CONTEXT_H
19 #define SCRIPT_CONTEXT_H
25 #include "itemfield.h"
26 #include "multifielditem.h"
29 using namespace sysync;
35 * builtin function definitions
38 #define PARAM_TYPEMASK 0x1F
39 #define PARAM_OPT 0x20
40 #define PARAM_REF 0x40
41 #define PARAM_ARR 0x80
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)
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[];
56 // - Multi-Byte tokens:
58 // - t=token ID alphanum.
59 // - l=length of additional token data, 0x00..0xFF as one char
60 // - dddddd=additional token data
62 // highest Multibyte token
63 #define TK_MAX_MULTIBYTE 0x1F
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
82 // - type definition, d=TItemFieldTypes enum
83 #define TK_TYPEDEF 0x18
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
94 // - language elements, 0x80..0x9F
99 #define TK_CONTINUE 0x84
100 #define TK_RETURN 0x85
101 #define TK_WHILE 0x86
104 #define TK_EMPTY 0x90
105 #define TK_UNASSIGNED 0x91
107 #define TK_FALSE 0x93
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
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 %%%
128 #define TK_BITWISENOT 0x40
129 #define TK_LOGICALNOT 0x41
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
138 #define TK_MINUS 0x49
140 #define TK_SHIFTLEFT 0x4C
141 #define TK_SHIFTRIGHT 0x4D
143 #define TK_LESSTHAN 0x50
144 #define TK_GREATERTHAN 0x51
145 #define TK_LESSEQUAL 0x52
146 #define TK_GREATEREQUAL 0x53
148 #define TK_EQUAL 0x54
149 #define TK_NOTEQUAL 0x55
151 #define TK_BITWISEAND 0x58
153 #define TK_BITWISEXOR 0x5C
155 #define TK_BITWISEOR 0x60
157 #define TK_LOGICALAND 0x64
159 #define TK_LOGICALOR 0x68
161 // Special modifying operator
163 #define TK_ASSIGN 0x6C
166 // local script variable definition
170 TScriptVarDef(cAppCharP aName,uInt16 aIdx, TItemFieldTypes aType, bool aIsArray, bool aIsRef, bool aIsOpt);
172 uInt16 fIdx; // index (position in container).
173 string fVarName; // Variable name
174 TItemFieldTypes fVarType; // type of variable
176 bool fIsRef; // set if this is a local reference to an existing variable
177 bool fIsOpt; // set if this is a optional parameter
182 typedef std::vector<TScriptVarDef *> TVarDefs;
185 // user defined script function
186 class TUserScriptFunction
191 }; // TUserScriptFunction
193 typedef std::vector<TUserScriptFunction *> TUserScriptList;
195 // global script config (such as user-defined functions)
196 class TScriptConfig : public TConfigElement
198 typedef TConfigElement inherited;
200 TScriptConfig(TConfigElement *aParentElementP);
201 virtual ~TScriptConfig();
203 uInt32 fMaxLoopProcessingTime; // seconds
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
215 // check config elements
216 virtual bool localStartElement(const char *aElementName, const char **aAttributes, sInt32 aLine);
217 virtual void localResolve(bool aLastPass);
221 // script tokenizing error
222 class TTokenizeException : public TConfigParseException
224 typedef TConfigParseException inherited;
226 TTokenizeException(cAppCharP aScriptName, cAppCharP aMsg1,cAppCharP aScript, uInt16 aIndex, uInt16 aLine);
227 }; // TTokenizeException
230 // script resolving or execution error
231 class TScriptErrorException : public TConfigParseException
233 typedef TConfigParseException inherited;
235 TScriptErrorException(cAppCharP aMsg1, uInt16 aLine, cAppCharP aIdent=NULL);
236 }; // TScriptErrorException
239 // folder mapping table
240 typedef std::vector<string> TMacroArgsArray;
243 // script execution state stack
255 TScriptState state; // state
256 cUInt8P begin; // begin of that state in source
257 uInt16 line; // line number
260 // flow control stack depth
261 const sInt16 maxstackentries=40;
263 class TMultiFieldItem;
268 friend class TScriptVarKey;
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
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
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
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
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);
330 TDebugLogger *getDbgLogger(void);
331 uInt32 getDbgMask(void);
333 // Reset context (clear all variables and definitions)
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(
340 TFieldListConfig *aFieldListConfigP,
342 string *aFuncNameP=NULL,
343 bool aNoNewLocals=false // if set, declaration of new locals will be suppressed
345 // Prepare local variables (create local fields), according to definitions (re-)built with ResolveIdentifiers()
346 bool PrepareLocals(void);
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
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; };
377 sInt16 getNumParams(void) { return fNumParams; };
378 // - caller's context data pointer (opaque, for use by context functions)
379 void *getCallerContext(void) { return fCallerContext; };
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)
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)
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;
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
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
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()
415 // - flow control state stack
416 sInt16 fStackEntries;
417 TScriptStackEntry fScriptstack[maxstackentries];
418 // - context information
421 TMultiFieldItem *fTargetItemP;
422 bool fTargetWritable;
423 TMultiFieldItem *fReferenceItemP;
425 // Link to calling script context (for function contexts)
426 TScriptContext *fParentContextP;
429 const TFuncTable *fFuncTableP; // caller context's function table
430 void *fCallerContext; // free pointer possibly having a meaning for context functions
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);
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
444 void defineBuiltInVars(const TBuiltInFuncDef *aFuncDefP);
445 void executeBuiltIn(TItemField *&aTermP, const TBuiltInFuncDef *aFuncDefP);
447 void showVarDefs(cAppCharP aTxt);
452 #ifdef ENGINEINTERFACE_SUPPORT
455 // key for access to script context variables
456 class TScriptVarKey :
459 typedef TItemFieldKey inherited;
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
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);
474 // the script context
475 TScriptContext *fScriptContext;
482 #endif // ENGINEINTERFACE_SUPPORT
485 } // namespace sysync
487 #endif // SCRIPT_CONTEXT_H
489 #endif // SCRIPT_SUPPORT