2 * File: scriptcontext.cpp
4 * Author: Lukas Zeller (luz@synthesis.ch)
7 * Environment to tokenize, prepare and run scripts
9 * Copyright (c) 2002-2009 by Synthesis AG (www.synthesis.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)
51 // - Multi-Byte tokens:
53 // - t=token ID alphanum.
54 // - l=length of additional token data, 0x00..0xFF as one char
55 // - dddddd=additional token data
57 // highest Multibyte token
58 #define TK_MAX_MULTIBYTE 0x1F
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
77 // - type definition, d=TItemFieldTypes enum
78 #define TK_TYPEDEF 0x18
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
89 // - language elements, 0x80..0x9F
94 #define TK_CONTINUE 0x84
95 #define TK_RETURN 0x85
100 #define TK_UNASSIGNED 0x91
102 #define TK_FALSE 0x93
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
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 %%%
123 #define TK_BITWISENOT 0x40
124 #define TK_LOGICALNOT 0x41
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
133 #define TK_MINUS 0x49
135 #define TK_SHIFTLEFT 0x4C
136 #define TK_SHIFTRIGHT 0x4D
138 #define TK_LESSTHAN 0x50
139 #define TK_GREATERTHAN 0x51
140 #define TK_LESSEQUAL 0x52
141 #define TK_GREATEREQUAL 0x53
143 #define TK_EQUAL 0x54
144 #define TK_NOTEQUAL 0x55
146 #define TK_BITWISEAND 0x58
148 #define TK_BITWISEXOR 0x5C
150 #define TK_BITWISEOR 0x60
152 #define TK_LOGICALAND 0x64
154 #define TK_LOGICALOR 0x68
156 // Special modifying operator
158 #define TK_ASSIGN 0x6C
161 // local script variable definition
165 TScriptVarDef(cAppCharP aName,uInt16 aIdx, TItemFieldTypes aType, bool aIsArray, bool aIsRef, bool aIsOpt);
167 uInt16 fIdx; // index (position in container).
168 string fVarName; // Variable name
169 TItemFieldTypes fVarType; // type of variable
171 bool fIsRef; // set if this is a local reference to an existing variable
172 bool fIsOpt; // set if this is a optional parameter
177 typedef std::vector<TScriptVarDef *> TVarDefs;
180 // user defined script function
181 class TUserScriptFunction
186 }; // TUserScriptFunction
188 typedef std::vector<TUserScriptFunction *> TUserScriptList;
190 // global script config (such as user-defined functions)
191 class TScriptConfig : public TConfigElement
193 typedef TConfigElement inherited;
195 TScriptConfig(TConfigElement *aParentElementP);
196 virtual ~TScriptConfig();
198 uInt32 fMaxLoopProcessingTime; // seconds
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
210 // check config elements
211 virtual bool localStartElement(const char *aElementName, const char **aAttributes, sInt32 aLine);
212 virtual void localResolve(bool aLastPass);
216 // script tokenizing error
217 class TTokenizeException : public TConfigParseException
219 typedef TConfigParseException inherited;
221 TTokenizeException(cAppCharP aScriptName, cAppCharP aMsg1,cAppCharP aScript, uInt16 aIndex, uInt16 aLine);
222 }; // TTokenizeException
225 // script resolving or execution error
226 class TScriptErrorException : public TConfigParseException
228 typedef TConfigParseException inherited;
230 TScriptErrorException(cAppCharP aMsg1, uInt16 aLine, cAppCharP aIdent=NULL);
231 }; // TScriptErrorException
234 // folder mapping table
235 typedef std::vector<string> TMacroArgsArray;
238 // script execution state stack
250 TScriptState state; // state
251 cUInt8P begin; // begin of that state in source
252 uInt16 line; // line number
255 // flow control stack depth
256 const sInt16 maxstackentries=40;
258 class TMultiFieldItem;
263 friend class TScriptVarKey;
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
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
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
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
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);
325 TDebugLogger *getDbgLogger(void);
326 uInt32 getDbgMask(void);
328 // Reset context (clear all variables and definitions)
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(
335 TFieldListConfig *aFieldListConfigP,
337 string *aFuncNameP=NULL,
338 bool aNoNewLocals=false // if set, declaration of new locals will be suppressed
340 // Prepare local variables (create local fields), according to definitions (re-)built with ResolveIdentifiers()
341 bool PrepareLocals(void);
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
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; };
372 sInt16 getNumParams(void) { return fNumParams; };
373 // - caller's context data pointer (opaque, for use by context functions)
374 void *getCallerContext(void) { return fCallerContext; };
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)
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)
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;
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
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
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()
410 // - flow control state stack
411 sInt16 fStackEntries;
412 TScriptStackEntry fScriptstack[maxstackentries];
413 // - context information
416 TMultiFieldItem *fTargetItemP;
417 bool fTargetWritable;
418 TMultiFieldItem *fReferenceItemP;
420 // Link to calling script context (for function contexts)
421 TScriptContext *fParentContextP;
424 const TFuncTable *fFuncTableP; // caller context's function table
425 void *fCallerContext; // free pointer eventually having a meaning for context functions
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);
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
439 void defineBuiltInVars(const TBuiltInFuncDef *aFuncDefP);
440 void executeBuiltIn(TItemField *&aTermP, const TBuiltInFuncDef *aFuncDefP);
442 void showVarDefs(cAppCharP aTxt);
447 #ifdef ENGINEINTERFACE_SUPPORT
450 // key for access to script context variables
451 class TScriptVarKey :
454 typedef TItemFieldKey inherited;
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
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);
469 // the script context
470 TScriptContext *fScriptContext;
477 #endif // ENGINEINTERFACE_SUPPORT
480 } // namespace sysync
482 #endif // SCRIPT_CONTEXT_H
484 #endif // SCRIPT_SUPPORT