| 1 | /* |
| 2 | * LegacyClonk |
| 3 | * |
| 4 | * Copyright (c) RedWolf Design |
| 5 | * Copyright (c) 2001, Sven2 |
| 6 | * Copyright (c) 2017-2022, The LegacyClonk Team and contributors |
| 7 | * |
| 8 | * Distributed under the terms of the ISC license; see accompanying file |
| 9 | * "COPYING" for details. |
| 10 | * |
| 11 | * "Clonk" is a registered trademark of Matthes Bender, used with permission. |
| 12 | * See accompanying file "TRADEMARK" for details. |
| 13 | * |
| 14 | * To redistribute this file separately, substitute the full license texts |
| 15 | * for the above references. |
| 16 | */ |
| 17 | |
| 18 | // C4Aul script engine CP conversion |
| 19 | // (cut C4Aul of classes/structs and put everything in namespace C4Aul instead?) |
| 20 | // drop uncompiled scripts when not in developer mode |
| 21 | // -> build string table |
| 22 | // -> clear the string table in UnLink? ReLink won't happen to be called in player mode anyway |
| 23 | |
| 24 | #pragma once |
| 25 | |
| 26 | #include <C4AulScriptStrict.h> |
| 27 | #include <C4ValueList.h> |
| 28 | #include <C4ValueMap.h> |
| 29 | #include <C4Id.h> |
| 30 | #include "C4Log.h" |
| 31 | #include <C4Script.h> |
| 32 | #include <C4StringTable.h> |
| 33 | |
| 34 | #include <cstdint> |
| 35 | #include <list> |
| 36 | #include <vector> |
| 37 | |
| 38 | // class predefs |
| 39 | class C4AulError; |
| 40 | class C4AulFunc; |
| 41 | class C4AulScriptFunc; |
| 42 | class C4AulScript; |
| 43 | class C4AulScriptEngine; |
| 44 | |
| 45 | struct C4AulContext; |
| 46 | struct C4AulBCC; |
| 47 | |
| 48 | class C4Def; |
| 49 | class C4DefList; |
| 50 | |
| 51 | // consts |
| 52 | #define C4AUL_MAX_String 1024 // max string length |
| 53 | #define C4AUL_MAX_Identifier 100 // max length of function identifiers |
| 54 | #define C4AUL_MAX_Par 10 // max number of parameters |
| 55 | |
| 56 | #define C4AUL_ControlMethod_None 0 |
| 57 | #define C4AUL_ControlMethod_Classic 1 |
| 58 | #define C4AUL_ControlMethod_JumpAndRun 2 |
| 59 | #define C4AUL_ControlMethod_All 3 |
| 60 | |
| 61 | // generic C4Aul error class |
| 62 | class C4AulError |
| 63 | { |
| 64 | protected: |
| 65 | std::string message; |
| 66 | bool isWarning{false}; |
| 67 | |
| 68 | public: |
| 69 | C4AulError(); |
| 70 | C4AulError(const C4AulError &Error) : message{Error.message}, isWarning{Error.isWarning} {} |
| 71 | virtual ~C4AulError() {} |
| 72 | virtual void show() const; // present error message |
| 73 | }; |
| 74 | |
| 75 | // parse error |
| 76 | class C4AulParseError : public C4AulError |
| 77 | { |
| 78 | C4AulParseError(std::string_view message, const char *identifier, bool warn); |
| 79 | |
| 80 | public: |
| 81 | C4AulParseError(C4AulScript *pScript, std::string_view msg, const char *pIdtf = nullptr, bool Warn = false); |
| 82 | C4AulParseError(class C4AulParseState *state, std::string_view msg, const char *pIdtf = nullptr, bool Warn = false); |
| 83 | }; |
| 84 | |
| 85 | // execution error |
| 86 | class C4AulExecError : public C4AulError |
| 87 | { |
| 88 | C4Object *cObj; |
| 89 | |
| 90 | public: |
| 91 | C4AulExecError(C4Object *pObj, std::string_view error); |
| 92 | virtual void show() const override; // present error message |
| 93 | }; |
| 94 | |
| 95 | // function access |
| 96 | enum C4AulAccess |
| 97 | { |
| 98 | AA_PRIVATE, |
| 99 | AA_PROTECTED, |
| 100 | AA_PUBLIC, |
| 101 | AA_GLOBAL |
| 102 | }; |
| 103 | |
| 104 | struct C4AulParSet |
| 105 | { |
| 106 | C4Value Par[C4AUL_MAX_Par]; |
| 107 | |
| 108 | C4AulParSet() {} |
| 109 | C4AulParSet(const C4Value &par0, const C4Value &par1 = C4Value(), const C4Value &par2 = C4Value(), const C4Value &par3 = C4Value(), const C4Value &par4 = C4Value(), |
| 110 | const C4Value &par5 = C4Value(), const C4Value &par6 = C4Value(), const C4Value &par7 = C4Value(), const C4Value &par8 = C4Value(), const C4Value &par9 = C4Value()) |
| 111 | { |
| 112 | Par[0].Set(par0); Par[1].Set(par1); Par[2].Set(par2); Par[3].Set(par3); Par[4].Set(par4); |
| 113 | Par[5].Set(par5); Par[6].Set(par6); Par[7].Set(par7); Par[8].Set(par8); Par[9].Set(par9); |
| 114 | } |
| 115 | |
| 116 | C4Value &operator[](int iIdx) { return Par[iIdx]; } |
| 117 | const C4Value &operator[](int iIdx) const { return Par[iIdx]; } |
| 118 | }; |
| 119 | |
| 120 | #define Copy2ParSet8(Pars, Vars) Pars[0].Set(Vars##0); Pars[1].Set(Vars##1); Pars[2].Set(Vars##2); Pars[3].Set(Vars##3); Pars[4].Set(Vars##4); Pars[5].Set(Vars##5); Pars[6].Set(Vars##6); Pars[7].Set(Vars##7); |
| 121 | #define Copy2ParSet9(Pars, Vars) Pars[0].Set(Vars##0); Pars[1].Set(Vars##1); Pars[2].Set(Vars##2); Pars[3].Set(Vars##3); Pars[4].Set(Vars##4); Pars[5].Set(Vars##5); Pars[6].Set(Vars##6); Pars[7].Set(Vars##7); Pars[8].Set(Vars##8); |
| 122 | |
| 123 | // byte code chunk type |
| 124 | // some special script functions defined hard-coded to reduce the exec context |
| 125 | enum C4AulBCCType |
| 126 | { |
| 127 | AB_DEREF, // deref the current value |
| 128 | AB_MAPA_R, // map access via . |
| 129 | AB_MAPA_V, // not creating a reference |
| 130 | AB_ARRAYA_R, // array access |
| 131 | AB_ARRAYA_V, // not creating a reference |
| 132 | AB_ARRAY_APPEND, // always as a reference |
| 133 | AB_VARN_R, // a named var |
| 134 | AB_VARN_V, |
| 135 | AB_PARN_R, // a named parameter |
| 136 | AB_PARN_V, |
| 137 | AB_LOCALN_R, // a named local |
| 138 | AB_LOCALN_V, |
| 139 | AB_GLOBALN_R, // a named global |
| 140 | AB_GLOBALN_V, |
| 141 | AB_VAR_R, // Var statement |
| 142 | AB_VAR_V, |
| 143 | AB_PAR_R, // Par statement |
| 144 | AB_PAR_V, |
| 145 | AB_FUNC, // function |
| 146 | |
| 147 | // prefix |
| 148 | AB_Inc1, // ++ |
| 149 | AB_Dec1, // -- |
| 150 | AB_BitNot, // ~ |
| 151 | AB_Not, // ! |
| 152 | AB_Neg, // - |
| 153 | |
| 154 | // postfix (whithout second statement) |
| 155 | AB_Inc1_Postfix, // ++ |
| 156 | AB_Dec1_Postfix, // -- |
| 157 | |
| 158 | // postfix |
| 159 | AB_Pow, // ** |
| 160 | AB_Div, // / |
| 161 | AB_Mul, // * |
| 162 | AB_Mod, // % |
| 163 | AB_Sub, // - |
| 164 | AB_Sum, // + |
| 165 | AB_LeftShift, // << |
| 166 | AB_RightShift, // >> |
| 167 | AB_LessThan, // < |
| 168 | AB_LessThanEqual, // <= |
| 169 | AB_GreaterThan, // > |
| 170 | AB_GreaterThanEqual, // >= |
| 171 | AB_Concat, // .. |
| 172 | AB_EqualIdent, // old == |
| 173 | AB_Equal, // new == |
| 174 | AB_NotEqualIdent, // old != |
| 175 | AB_NotEqual, // new != |
| 176 | AB_SEqual, // S=, eq |
| 177 | AB_SNEqual, // ne |
| 178 | AB_BitAnd, // & |
| 179 | AB_BitXOr, // ^ |
| 180 | AB_BitOr, // | |
| 181 | AB_And, // && |
| 182 | AB_Or, // || |
| 183 | AB_NilCoalescing, // ?? |
| 184 | AB_PowIt, // **= |
| 185 | AB_MulIt, // *= |
| 186 | AB_DivIt, // /= |
| 187 | AB_ModIt, // %= |
| 188 | AB_Inc, // += |
| 189 | AB_Dec, // -= |
| 190 | AB_LeftShiftIt, // <<= |
| 191 | AB_RightShiftIt, // >>= |
| 192 | AB_ConcatIt, // ..= |
| 193 | AB_AndIt, // &= |
| 194 | AB_OrIt, // |= |
| 195 | AB_XOrIt, // ^= |
| 196 | AB_NilCoalescingIt, // ??= only the jumping part |
| 197 | AB_Set, // = |
| 198 | |
| 199 | AB_CALLGLOBAL, // global context call |
| 200 | AB_CALL, // direct object call |
| 201 | AB_CALLFS, // failsafe direct call |
| 202 | AB_CALLNS, // direct object call: namespace operator |
| 203 | AB_STACK, // push nulls / pop |
| 204 | AB_NIL, // constant: nil |
| 205 | AB_INT, // constant: int |
| 206 | AB_BOOL, // constant: bool |
| 207 | AB_STRING, // constant: string |
| 208 | AB_C4ID, // constant: C4ID |
| 209 | AB_ARRAY, // semi-constant: array |
| 210 | AB_MAP, // semi-constant: map |
| 211 | AB_IVARN, // initialization of named var |
| 212 | AB_JUMP, // jump |
| 213 | AB_JUMPAND, // jump if zero, else pop the stack |
| 214 | AB_JUMPOR, // jump if not zero, else pop the stack |
| 215 | AB_JUMPNIL, // jump if nil, otherwise just continue |
| 216 | AB_JUMPNOTNIL, // jump if not nil, otherwise just continue |
| 217 | AB_CONDN, // conditional jump (negated, pops stack) |
| 218 | AB_FOREACH_NEXT, // foreach: next element in array |
| 219 | AB_FOREACH_MAP_NEXT, // foreach: next key-value pair in map |
| 220 | AB_RETURN, // return statement |
| 221 | AB_ERR, // parse error at this position |
| 222 | AB_EOFN, // end of function |
| 223 | AB_EOF, // end of file |
| 224 | }; |
| 225 | |
| 226 | // ** a definition of an operator |
| 227 | // there are two classes of operators, the postfix-operators (+,-,&,...) and the |
| 228 | // prefix-operators (mainly !,~,...). |
| 229 | struct C4ScriptOpDef |
| 230 | { |
| 231 | unsigned short Priority; |
| 232 | const char *Identifier; |
| 233 | C4AulBCCType Code; |
| 234 | bool Postfix; |
| 235 | bool RightAssociative; // right or left-associative? |
| 236 | bool NoSecondStatement; // no second statement expected (++/-- postfix) |
| 237 | C4V_Type RetType; // type returned. ignored by C4V |
| 238 | C4V_Type Type1; |
| 239 | C4V_Type Type2; |
| 240 | }; |
| 241 | extern C4ScriptOpDef C4ScriptOpMap[]; |
| 242 | |
| 243 | // byte code chunk |
| 244 | struct C4AulBCC |
| 245 | { |
| 246 | C4AulBCCType bccType; // chunk type |
| 247 | std::intptr_t bccX; |
| 248 | const char *SPos; |
| 249 | }; |
| 250 | |
| 251 | // call context |
| 252 | struct C4AulContext |
| 253 | { |
| 254 | C4Object *Obj; |
| 255 | C4Def *Def; |
| 256 | struct C4AulScriptContext *Caller; |
| 257 | |
| 258 | bool CalledWithStrictNil() const noexcept; |
| 259 | }; |
| 260 | |
| 261 | // execution context |
| 262 | struct C4AulScriptContext : public C4AulContext |
| 263 | { |
| 264 | C4Value *Return; |
| 265 | C4Value *Pars; |
| 266 | C4Value *Vars; |
| 267 | C4AulScriptFunc *Func; |
| 268 | bool TemporaryScript; |
| 269 | C4ValueList NumVars; |
| 270 | C4AulBCC *CPos; |
| 271 | time_t tTime; // initialized only by profiler if active |
| 272 | |
| 273 | size_t ParCnt() const { return Vars - Pars; } |
| 274 | void dump(std::string Dump = "" ); |
| 275 | }; |
| 276 | |
| 277 | // base function class |
| 278 | class C4AulFunc |
| 279 | { |
| 280 | friend class C4AulScript; |
| 281 | friend class C4AulScriptEngine; |
| 282 | friend class C4AulFuncMap; |
| 283 | friend class C4AulParseState; |
| 284 | |
| 285 | public: |
| 286 | C4AulFunc(C4AulScript *pOwner, const char *pName, bool bAtEnd = true); |
| 287 | virtual ~C4AulFunc(); |
| 288 | |
| 289 | C4AulScript *Owner; // owner |
| 290 | char Name[C4AUL_MAX_Identifier]; // function name |
| 291 | |
| 292 | protected: |
| 293 | C4AulFunc *Prev, *Next; // linked list members |
| 294 | C4AulFunc *MapNext; // map member |
| 295 | C4AulFunc *LinkedTo; // points to next linked function; destructor will destroy linked func, too |
| 296 | |
| 297 | public: |
| 298 | C4AulFunc *OverloadedBy; // function by which this one is overloaded |
| 299 | C4AulFunc *NextSNFunc; // next script func using the same name (list build in AfterLink) |
| 300 | |
| 301 | virtual C4AulScriptFunc *SFunc() { return nullptr; } // type check func... |
| 302 | |
| 303 | // Wether this function should be visible to players |
| 304 | virtual bool GetPublic() { return false; } |
| 305 | virtual int GetParCount() { return C4AUL_MAX_Par; } |
| 306 | virtual const C4V_Type *GetParType() { return nullptr; } |
| 307 | virtual C4V_Type GetRetType() { return C4V_Any; } |
| 308 | virtual C4Value Exec(C4AulContext *pCallerCtx, const C4Value pPars[], bool fPassErrors = false) { return C4Value(); } // execute func (script call) |
| 309 | virtual C4Value Exec(C4Object *pObj = nullptr, const C4AulParSet &pPars = C4AulParSet{}, bool fPassErrors = false, bool nonStrict3WarnConversionOnly = false, bool convertNilToIntBool = true); // execute func (engine call) |
| 310 | virtual void UnLink() { OverloadedBy = NextSNFunc = nullptr; } |
| 311 | |
| 312 | C4AulFunc *GetLocalSFunc(const char *szIdtf); // find script function in own scope |
| 313 | |
| 314 | C4AulFunc *FindSameNameFunc(C4Def *pScope); // Find a function of the same name for given scope |
| 315 | |
| 316 | protected: |
| 317 | void DestroyLinked(); // destroys linked functions |
| 318 | }; |
| 319 | |
| 320 | // script function class |
| 321 | class C4AulScriptFunc : public C4AulFunc |
| 322 | { |
| 323 | public: |
| 324 | C4AulFunc *OwnerOverloaded; // overloaded owner function; if present |
| 325 | C4AulScriptFunc *SFunc() override { return this; } // type check func... |
| 326 | |
| 327 | protected: |
| 328 | void ParseDesc(); // evaluate desc (i.e. get idImage and Condition |
| 329 | |
| 330 | public: |
| 331 | C4AulAccess Access; |
| 332 | StdStrBuf Desc; // full function description block, including image and condition |
| 333 | StdStrBuf DescText; // short function description text (name of menu entry) |
| 334 | StdStrBuf DescLong; // secondary function description |
| 335 | C4ID idImage; // associated image |
| 336 | int32_t iImagePhase; // Image phase |
| 337 | C4AulFunc *Condition; // func condition |
| 338 | int32_t ControlMethod; // 0 = all, 1 = Classic, 2 = Jump+Run |
| 339 | const char *Script; // script pos |
| 340 | C4AulBCC *Code; // code pos |
| 341 | C4ValueMapNames VarNamed; // list of named vars in this function |
| 342 | C4ValueMapNames ParNamed; // list of named pars in this function |
| 343 | C4V_Type ParType[C4AUL_MAX_Par]; // parameter types |
| 344 | bool bNewFormat; // new func format? [ func xyz(par abc) { ... } ] |
| 345 | bool bReturnRef; // return reference |
| 346 | C4AulScript *pOrgScript; // the original script (!= Owner if included or appended) |
| 347 | |
| 348 | C4AulScriptFunc(C4AulScript *pOwner, const char *pName, bool bAtEnd = true) : C4AulFunc(pOwner, pName, bAtEnd), |
| 349 | idImage(C4ID_None), iImagePhase(0), Condition(nullptr), ControlMethod(C4AUL_ControlMethod_All), OwnerOverloaded(nullptr), |
| 350 | bReturnRef(false), tProfileTime(0) |
| 351 | { |
| 352 | for (int i = 0; i < C4AUL_MAX_Par; i++) ParType[i] = C4V_Any; |
| 353 | } |
| 354 | |
| 355 | virtual void UnLink() override; |
| 356 | |
| 357 | virtual bool GetPublic() override { return true; } |
| 358 | virtual const C4V_Type *GetParType() override { return ParType; } |
| 359 | virtual C4V_Type GetRetType() override { return bReturnRef ? C4V_pC4Value : C4V_Any; } |
| 360 | virtual C4Value Exec(C4AulContext *pCallerCtx, const C4Value pPars[], bool fPassErrors = false) override; // execute func (script call, should not happen) |
| 361 | virtual C4Value Exec(C4Object *pObj = nullptr, const C4AulParSet &pPars = C4AulParSet{}, bool fPassErrors = false, bool nonStrict3WarnConversionOnly = false, bool convertNilToIntBool = true) override; // execute func (engine call) |
| 362 | |
| 363 | void CopyBody(C4AulScriptFunc &FromFunc); // copy script/code, etc from given func |
| 364 | |
| 365 | std::string GetFullName(); // get a fully classified name (C4ID::Name) for debug output |
| 366 | |
| 367 | time_t tProfileTime; // internally set by profiler |
| 368 | |
| 369 | bool HasStrictNil() const noexcept; |
| 370 | |
| 371 | friend class C4AulScript; |
| 372 | }; |
| 373 | |
| 374 | class C4AulFuncMap |
| 375 | { |
| 376 | public: |
| 377 | C4AulFuncMap(); |
| 378 | ~C4AulFuncMap(); |
| 379 | C4AulFunc *GetFunc(const char *Name, const C4AulScript *Owner, const C4AulFunc *After); |
| 380 | C4AulFunc *GetFirstFunc(const char *Name); |
| 381 | C4AulFunc *GetNextSNFunc(const C4AulFunc *After); |
| 382 | |
| 383 | private: |
| 384 | C4AulFunc **Funcs; |
| 385 | int FuncCnt; |
| 386 | int Capacity; |
| 387 | static unsigned int Hash(const char *Name); |
| 388 | |
| 389 | protected: |
| 390 | void Add(C4AulFunc *func, bool bAtEnd = true); |
| 391 | void Remove(C4AulFunc *func); |
| 392 | |
| 393 | friend class C4AulFunc; |
| 394 | }; |
| 395 | |
| 396 | // aul script state |
| 397 | enum C4AulScriptState |
| 398 | { |
| 399 | ASS_ERROR, // erroneous script |
| 400 | ASS_NONE, // nothing |
| 401 | ASS_PREPARSED, // function list built; CodeSize set |
| 402 | ASS_LINKED, // includes and appends resolved |
| 403 | ASS_PARSED // byte code generated |
| 404 | }; |
| 405 | |
| 406 | // script profiler entry |
| 407 | class C4AulProfiler |
| 408 | { |
| 409 | private: |
| 410 | // map entry |
| 411 | struct Entry |
| 412 | { |
| 413 | C4AulScriptFunc *pFunc; |
| 414 | time_t tProfileTime; |
| 415 | |
| 416 | bool operator<(const Entry &e2) const { return tProfileTime < e2.tProfileTime; } |
| 417 | }; |
| 418 | |
| 419 | // items |
| 420 | std::vector<Entry> Times; |
| 421 | std::shared_ptr<spdlog::logger> logger; |
| 422 | |
| 423 | public: |
| 424 | C4AulProfiler(std::shared_ptr<spdlog::logger> logger) : logger{std::move(logger)} {} |
| 425 | |
| 426 | void CollectEntry(C4AulScriptFunc *pFunc, time_t tProfileTime); |
| 427 | void Show(); |
| 428 | |
| 429 | static void Abort(); |
| 430 | static void StartProfiling(C4AulScript *pScript); |
| 431 | static void StopProfiling(); |
| 432 | }; |
| 433 | |
| 434 | C4LOGGERCONFIG_NAME_TYPE(C4AulProfiler); |
| 435 | |
| 436 | template<> |
| 437 | struct C4LoggerConfig::Defaults<C4AulProfiler> |
| 438 | { |
| 439 | static constexpr spdlog::level::level_enum GuiLogLevel{spdlog::level::info}; |
| 440 | static constexpr bool ShowLoggerNameInGui{false}; |
| 441 | }; |
| 442 | |
| 443 | // script class |
| 444 | class C4AulScript |
| 445 | { |
| 446 | public: |
| 447 | C4AulScript(); |
| 448 | virtual ~C4AulScript(); |
| 449 | void Default(); // init |
| 450 | void Clear(); // remove script, byte code and children |
| 451 | void Reg2List(C4AulScriptEngine *pEngine, C4AulScript *pOwner); // reg to linked list |
| 452 | void Unreg(); // remove from list |
| 453 | virtual bool Delete() { return true; } // allow deletion on pure class |
| 454 | |
| 455 | protected: |
| 456 | struct Append |
| 457 | { |
| 458 | const C4ID id; |
| 459 | const bool nowarn; |
| 460 | |
| 461 | bool operator==(C4ID other) const { return id == other; } |
| 462 | }; |
| 463 | |
| 464 | C4AulFunc *Func0, *FuncL; // owned functions |
| 465 | C4AulScriptEngine *Engine; // owning engine |
| 466 | C4AulScript *Owner, *Prev, *Next, *Child0, *ChildL; // tree structure |
| 467 | |
| 468 | StdStrBuf Script; // script |
| 469 | C4AulBCC *Code, *CPos; // compiled script (/pos) |
| 470 | C4AulScriptState State; // script state |
| 471 | int CodeSize; // current number of byte code chunks in Code |
| 472 | int CodeBufSize; // size of Code buffer |
| 473 | bool Preparsing; // set while preparse |
| 474 | bool Resolving; // set while include-resolving, to catch circular includes |
| 475 | |
| 476 | std::list<C4ID> Includes; // include list |
| 477 | std::list<Append> Appends; // append list |
| 478 | |
| 479 | // internal function used to find overloaded functions |
| 480 | C4AulFunc *GetOverloadedFunc(C4AulFunc *ByFunc); |
| 481 | C4AulFunc *GetFunc(const char *pIdtf); // get local function by name |
| 482 | |
| 483 | void AddBCC(C4AulBCCType eType, std::intptr_t = 0, const char *SPos = nullptr); // add byte code chunk and advance |
| 484 | bool Preparse(); // preparse script; return if successful |
| 485 | void ParseFn(C4AulScriptFunc *Fn, bool fExprOnly = false); // parse single script function |
| 486 | |
| 487 | bool Parse(); // parse preparsed script; return if successful |
| 488 | void ParseDescs(); // parse function descs |
| 489 | |
| 490 | bool ResolveIncludes(C4DefList *rDefs); // resolve includes |
| 491 | bool ResolveAppends(C4DefList *rDefs); // resolve appends |
| 492 | bool IncludesResolved; |
| 493 | void AppendTo(C4AulScript &Scr, bool bHighPrio); // append to given script |
| 494 | void UnLink(); // reset to unlinked state |
| 495 | virtual void AfterLink(); // called after linking is completed; presearch common funcs here & search same-named funcs |
| 496 | virtual bool ReloadScript(const char *szPath); // reload given script |
| 497 | |
| 498 | C4AulScript *FindFirstNonStrictScript(); // find first script that is not #strict |
| 499 | |
| 500 | size_t GetCodePos() const { return CPos - Code; } |
| 501 | C4AulBCC *GetCodeByPos(size_t iPos) { return Code + iPos; } |
| 502 | |
| 503 | public: |
| 504 | std::string ScriptName; // script name |
| 505 | C4Def *Def; // owning def file |
| 506 | C4ValueMapNames LocalNamed; |
| 507 | C4ID idDef; // script id (to resolve includes) |
| 508 | C4AulScriptStrict Strict; // new or even newer syntax? |
| 509 | bool Temporary; // set for DirectExec-scripts; do not parse those |
| 510 | |
| 511 | C4AulScriptEngine *GetEngine() { return Engine; } |
| 512 | const char *GetScript() const { return Script.getData(); } |
| 513 | |
| 514 | C4AulFunc *GetFuncRecursive(const char *pIdtf); // search function by identifier, including global funcs |
| 515 | C4AulScriptFunc *GetSFunc(const char *pIdtf, C4AulAccess AccNeeded, bool fFailSafe = false); // get local sfunc, check access, check '~'-safety |
| 516 | C4AulScriptFunc *GetSFunc(const char *pIdtf); // get local script function by name |
| 517 | C4AulScriptFunc *GetSFunc(int iIndex, const char *szPattern = nullptr, C4AulAccess AccNeeded = AA_PRIVATE); // get local script function by index |
| 518 | C4AulScriptFunc *GetSFuncWarn(const char *pIdtf, C4AulAccess AccNeeded, const char *WarnStr); // get function; return nullptr and warn if not existent |
| 519 | C4AulAccess GetAllowedAccess(C4AulFunc *func, C4AulScript *caller); |
| 520 | |
| 521 | public: |
| 522 | C4Value DirectExec(C4Object *pObj, const char *szScript, const char *szContext, bool fPassErrors = false, C4AulScriptStrict Strict = C4AulScriptStrict::MAXSTRICT); // directly parse uncompiled script (WARG! CYCLES!) |
| 523 | void ResetProfilerTimes(); // zero all profiler times of owned functions |
| 524 | void CollectProfilerTimes(class C4AulProfiler &rProfiler); |
| 525 | |
| 526 | bool IsReady() { return State == ASS_PARSED; } // whether script calls may be done |
| 527 | |
| 528 | // helper functions |
| 529 | void Warn(std::string_view msg, const char *pIdtf); |
| 530 | |
| 531 | friend class C4AulParseError; |
| 532 | friend class C4AulFunc; |
| 533 | friend class C4AulScriptFunc; |
| 534 | friend class C4AulScriptEngine; |
| 535 | friend class C4AulParseState; |
| 536 | }; |
| 537 | |
| 538 | // holds all C4AulScripts |
| 539 | class C4AulScriptEngine : public C4AulScript |
| 540 | { |
| 541 | protected: |
| 542 | C4AulFuncMap FuncLookUp; |
| 543 | |
| 544 | public: |
| 545 | int warnCnt, errCnt; // number of warnings/errors |
| 546 | int nonStrictCnt; // number of non-strict scripts |
| 547 | int lineCnt; // line count parsed |
| 548 | |
| 549 | C4ValueList Global; |
| 550 | C4ValueMapNames GlobalNamedNames; |
| 551 | C4ValueMapData GlobalNamed; |
| 552 | |
| 553 | C4StringTable Strings; |
| 554 | |
| 555 | // global constants (such as "static const C4D_Structure = 2;") |
| 556 | // cannot share var lists, because it's so closely tied to the data lists |
| 557 | // constants are used by the Parser only, anyway, so it's not |
| 558 | // necessary to pollute the global var list here |
| 559 | C4ValueMapNames GlobalConstNames; |
| 560 | C4ValueMapData GlobalConsts; |
| 561 | |
| 562 | C4AulScriptEngine(); |
| 563 | ~C4AulScriptEngine(); |
| 564 | void Clear(); // clear data |
| 565 | void Link(C4DefList *rDefs); // link and parse all scripts |
| 566 | void ReLink(C4DefList *rDefs); // unlink + relink and parse all scripts |
| 567 | bool ReloadScript(const char *szScript, C4DefList *pDefs); // search script and reload + relink, if found |
| 568 | |
| 569 | C4AulFunc *GetFirstFunc(const char *Name) |
| 570 | { |
| 571 | return FuncLookUp.GetFirstFunc(Name); |
| 572 | } |
| 573 | |
| 574 | C4AulFunc *GetFunc(const char *Name, const C4AulScript *Owner, const C4AulFunc *After) |
| 575 | { |
| 576 | return FuncLookUp.GetFunc(Name, Owner, After); |
| 577 | } |
| 578 | |
| 579 | C4AulFunc *GetNextSNFunc(const C4AulFunc *After) |
| 580 | { |
| 581 | return FuncLookUp.GetNextSNFunc(After); |
| 582 | } |
| 583 | |
| 584 | // For the list of functions in the PropertyDlg |
| 585 | C4AulFunc *GetFirstFunc() { return Func0; } |
| 586 | C4AulFunc *GetNextFunc(C4AulFunc *pFunc) { return pFunc->Next; } |
| 587 | |
| 588 | void RegisterGlobalConstant(const char *szName, const C4Value &rValue); // creates a new constants or overwrites an old one |
| 589 | bool GetGlobalConstant(const char *szName, C4Value *pTargetValue); // check if a constant exists; assign value to pTargetValue if not nullptr |
| 590 | |
| 591 | bool DenumerateVariablePointers(); |
| 592 | void UnLink(); // called when a script is being reloaded (clears string table) |
| 593 | // Compile scenario script data (without strings and constants) |
| 594 | void CompileFunc(StdCompiler *pComp); |
| 595 | |
| 596 | friend class C4AulFunc; |
| 597 | friend class C4AulParseState; |
| 598 | }; |
| 599 | |
| 600 | class C4AulExec; |
| 601 | |
| 602 | C4LOGGERCONFIG_NAME_TYPE(C4AulExec); |
| 603 | |
| 604 | template<> |
| 605 | struct C4LoggerConfig::Defaults<C4AulExec> |
| 606 | { |
| 607 | static constexpr auto GuiLogLevel = spdlog::level::info; |
| 608 | static constexpr bool ShowLoggerNameInGui{false}; |
| 609 | }; |
| 610 | |