"Fossies" - the Fresh Open Source Software Archive

Member "AutoHotkey_L-1.1.33.09/source/script_object_bif.cpp" (8 May 2021, 15146 Bytes) of package /windows/misc/AutoHotkey_L-1.1.33.09.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "script_object_bif.cpp" see the Fossies "Dox" file reference documentation.

    1 #include "stdafx.h" // pre-compiled headers
    2 #include "defines.h"
    3 #include "globaldata.h"
    4 #include "script.h"
    5 
    6 #include "script_object.h"
    7 
    8 
    9 //
   10 // BIF_ObjCreate - Object()
   11 //
   12 
   13 BIF_DECL(BIF_ObjCreate)
   14 {
   15     IObject *obj = NULL;
   16 
   17     if (aParamCount == 1) // L33: POTENTIALLY UNSAFE - Cast IObject address to object reference.
   18     {
   19         if (obj = TokenToObject(*aParam[0]))
   20         {   // Allow &obj == Object(obj), but AddRef() for equivalence with ComObjActive(comobj).
   21             obj->AddRef();
   22             aResultToken.value_int64 = (__int64)obj;
   23             return; // symbol is already SYM_INTEGER.
   24         }
   25         obj = (IObject *)TokenToInt64(*aParam[0]);
   26         if (obj < (IObject *)1024) // Prevent some obvious errors.
   27             obj = NULL;
   28         else
   29             obj->AddRef();
   30     }
   31     else
   32         obj = Object::Create(aParam, aParamCount);
   33 
   34     if (obj)
   35     {
   36         aResultToken.symbol = SYM_OBJECT;
   37         aResultToken.object = obj;
   38         // DO NOT ADDREF: after we return, the only reference will be in aResultToken.
   39     }
   40     else
   41     {
   42         aResultToken.symbol = SYM_STRING;
   43         aResultToken.marker = _T("");
   44     }
   45 }
   46 
   47 
   48 //
   49 // BIF_ObjArray - Array(items*)
   50 //
   51 
   52 BIF_DECL(BIF_ObjArray)
   53 {
   54     if (aResultToken.object = Object::CreateArray(aParam, aParamCount))
   55     {
   56         aResultToken.symbol = SYM_OBJECT;
   57         return;
   58     }
   59     aResultToken.symbol = SYM_STRING;
   60     aResultToken.marker = _T("");
   61 }
   62     
   63 
   64 //
   65 // BIF_IsObject - IsObject(obj)
   66 //
   67 
   68 BIF_DECL(BIF_IsObject)
   69 {
   70     int i;
   71     for (i = 0; i < aParamCount && TokenToObject(*aParam[i]); ++i);
   72     aResultToken.value_int64 = (__int64)(i == aParamCount); // TRUE if all are objects.
   73 }
   74     
   75 
   76 //
   77 // BIF_ObjInvoke - Handles ObjGet/Set/Call() and get/set/call syntax.
   78 //
   79 
   80 BIF_DECL(BIF_ObjInvoke)
   81 {
   82     int invoke_type;
   83     IObject *obj;
   84     ExprTokenType *obj_param;
   85 
   86     // Since ObjGet/ObjSet/ObjCall are not publicly accessible as functions, Func::mName
   87     // (passed via aResultToken.marker) contains the actual flag rather than a name.
   88     invoke_type = (int)(INT_PTR)aResultToken.marker;
   89 
   90     // Set default return value; ONLY AFTER THE ABOVE.
   91     aResultToken.symbol = SYM_STRING;
   92     aResultToken.marker = _T("");
   93     
   94     obj_param = *aParam; // aParam[0].  Load-time validation has ensured at least one parameter was specified.
   95     ++aParam;
   96     --aParamCount;
   97 
   98     // The following is used in place of TokenToObject to bypass #Warn UseUnset:
   99     if (obj_param->symbol == SYM_OBJECT)
  100         obj = obj_param->object;
  101     else if (obj_param->symbol == SYM_VAR && obj_param->var->HasObject())
  102         obj = obj_param->var->Object();
  103     else
  104         obj = NULL;
  105     
  106     if (obj)
  107     {
  108         bool param_is_var = obj_param->symbol == SYM_VAR;
  109         if (param_is_var)
  110             // Since the variable may be cleared as a side-effect of the invocation, call AddRef to ensure the object does not expire prematurely.
  111             // This is not necessary for SYM_OBJECT since that reference is already counted and cannot be released before we return.  Each object
  112             // could take care not to delete itself prematurely, but it seems more proper, more reliable and more maintainable to handle it here.
  113             obj->AddRef();
  114         aResult = obj->Invoke(aResultToken, *obj_param, invoke_type, aParam, aParamCount);
  115         if (param_is_var)
  116             obj->Release();
  117     }
  118     // Invoke meta-functions of g_MetaObject.
  119     else if (INVOKE_NOT_HANDLED == (aResult = g_MetaObject.Invoke(aResultToken, *obj_param, invoke_type | IF_META, aParam, aParamCount)))
  120     {
  121         // Since above did not handle it, check for attempts to access .base of non-object value (g_MetaObject itself).
  122         if (   invoke_type != IT_CALL // Exclude things like "".base().
  123             && aParamCount > (invoke_type == IT_SET ? 2 : 0) // SET is supported only when an index is specified: "".base[x]:=y
  124             && !_tcsicmp(TokenToString(*aParam[0]), _T("base"))   )
  125         {
  126             if (aParamCount > 1)    // "".base[x] or similar
  127             {
  128                 // Re-invoke g_MetaObject without meta flag or "base" param.
  129                 ExprTokenType base_token;
  130                 base_token.symbol = SYM_OBJECT;
  131                 base_token.object = &g_MetaObject;
  132                 g_MetaObject.Invoke(aResultToken, base_token, invoke_type, aParam + 1, aParamCount - 1);
  133             }
  134             else                    // "".base
  135             {
  136                 // Return a reference to g_MetaObject.  No need to AddRef as g_MetaObject ignores it.
  137                 aResultToken.symbol = SYM_OBJECT;
  138                 aResultToken.object = &g_MetaObject;
  139             }
  140         }
  141         else
  142         {
  143             // Since it wasn't handled (not even by g_MetaObject), maybe warn at this point:
  144             if (obj_param->symbol == SYM_VAR)
  145                 obj_param->var->MaybeWarnUninitialized();
  146         }
  147     }
  148     if (aResult == INVOKE_NOT_HANDLED)
  149         aResult = OK;
  150 }
  151     
  152 
  153 //
  154 // BIF_ObjGetInPlace - Handles part of a compound assignment like x.y += z.
  155 //
  156 
  157 BIF_DECL(BIF_ObjGetInPlace)
  158 {
  159     // Since the most common cases have two params, the "param count" param is omitted in
  160     // those cases. Otherwise we have one visible parameter, which indicates the number of
  161     // actual parameters below it on the stack.
  162     aParamCount = aParamCount ? (int)TokenToInt64(*aParam[0]) : 2; // x[<n-1 params>] : x.y
  163     BIF_ObjInvoke(aResult, aResultToken, aParam - aParamCount, aParamCount);
  164 }
  165 
  166 
  167 //
  168 // BIF_ObjNew - Handles "new" as in "new Class()".
  169 //
  170 
  171 BIF_DECL(BIF_ObjNew)
  172 {
  173     aResultToken.symbol = SYM_STRING;
  174     aResultToken.marker = _T("");
  175 
  176     ExprTokenType *class_token = aParam[0]; // Save this to be restored later.
  177 
  178     IObject *class_object = TokenToObject(*class_token);
  179     if (!class_object)
  180         return;
  181 
  182     Object *new_object = Object::Create();
  183     if (!new_object)
  184         return;
  185 
  186     new_object->SetBase(class_object);
  187 
  188     ExprTokenType name_token, this_token;
  189     this_token.symbol = SYM_OBJECT;
  190     this_token.object = new_object;
  191     name_token.symbol = SYM_STRING;
  192     aParam[0] = &name_token;
  193 
  194     ResultType result;
  195     LPTSTR buf = aResultToken.buf; // In case Invoke overwrites it via the union.
  196 
  197     Line *curr_line = g_script.mCurrLine;
  198 
  199     // __Init was added so that instance variables can be initialized in the correct order
  200     // (beginning at the root class and ending at class_object) before __New is called.
  201     // It shouldn't be explicitly defined by the user, but auto-generated in DefineClassVars().
  202     name_token.marker = _T("__Init");
  203     result = class_object->Invoke(aResultToken, this_token, IT_CALL | IF_METAOBJ, aParam, 1);
  204     if (result != INVOKE_NOT_HANDLED)
  205     {
  206         // It's possible that __Init is user-defined (despite recommendations in the
  207         // documentation) or built-in, so make sure the return value, if any, is freed:
  208         if (aResultToken.symbol == SYM_OBJECT)
  209             aResultToken.object->Release();
  210         if (aResultToken.mem_to_free)
  211         {
  212             free(aResultToken.mem_to_free);
  213             aResultToken.mem_to_free = NULL;
  214         }
  215         // Reset to defaults for __New, invoked below.
  216         aResultToken.symbol = SYM_STRING;
  217         aResultToken.marker = _T("");
  218         aResultToken.buf = buf;
  219         if (result == FAIL || result == EARLY_EXIT)
  220         {
  221             new_object->Release();
  222             aParam[0] = class_token; // Restore it to original caller-supplied value.
  223             aResult = result;
  224             return;
  225         }
  226     }
  227 
  228     g_script.mCurrLine = curr_line; // Prevent misleading error reports/Exception() stack trace.
  229     
  230     // __New may be defined by the script for custom initialization code.
  231     name_token.marker = Object::sMetaFuncName[4]; // __New
  232     result = class_object->Invoke(aResultToken, this_token, IT_CALL | IF_METAOBJ, aParam, aParamCount);
  233     if (result == EARLY_RETURN || !TokenIsEmptyString(aResultToken))
  234     {
  235         // __New() returned a value in aResultToken, so use it as our result.  aResultToken is checked
  236         // for the unlikely case that class_object is not an Object (perhaps it's a ComObject) or __New
  237         // points to a built-in function.  The older behaviour for those cases was to free the unexpected
  238         // return value, but this requires less code and might be useful somehow.
  239         new_object->Release();
  240     }
  241     else if (result == FAIL || result == EARLY_EXIT)
  242     {
  243         // An error was raised within __New() or while trying to call it, or Exit was called.
  244         new_object->Release();
  245         aResult = result;
  246     }
  247     else
  248     {
  249         // Either it wasn't handled (i.e. neither this class nor any of its super-classes define __New()),
  250         // or there was no explicit "return", so just return the new object.
  251         aResultToken.symbol = SYM_OBJECT;
  252         aResultToken.object = new_object;
  253     }
  254     aParam[0] = class_token;
  255 }
  256 
  257 
  258 //
  259 // BIF_ObjIncDec - Handles pre/post-increment/decrement for object fields, such as ++x[y].
  260 //
  261 
  262 BIF_DECL(BIF_ObjIncDec)
  263 {
  264     // Func::mName (which aResultToken.marker is set to) has been overloaded to pass
  265     // the type of increment/decrement to be performed on this object's field.
  266     SymbolType op = (SymbolType)(INT_PTR)aResultToken.marker;
  267 
  268     ExprTokenType temp_result, current_value, value_to_set;
  269 
  270     // Set the defaults expected by BIF_ObjInvoke:
  271     temp_result.symbol = SYM_INTEGER;
  272     temp_result.marker = (LPTSTR)IT_GET;
  273     temp_result.buf = aResultToken.buf;
  274     temp_result.mem_to_free = NULL;
  275 
  276     // Retrieve the current value.  Do it this way instead of calling Object::Invoke
  277     // so that if aParam[0] is not an object, g_MetaObject is correctly invoked.
  278     BIF_ObjInvoke(aResult, temp_result, aParam, aParamCount);
  279 
  280     if (aResult == FAIL || aResult == EARLY_EXIT)
  281         return;
  282 
  283     // Change SYM_STRING to SYM_OPERAND so below may treat it as a numeric string.
  284     if (temp_result.symbol == SYM_STRING)
  285     {
  286         temp_result.symbol = SYM_OPERAND;
  287         temp_result.buf = NULL; // Indicate that this SYM_OPERAND token LACKS a pre-converted binary integer.
  288     }
  289 
  290     switch (value_to_set.symbol = current_value.symbol = TokenIsPureNumeric(temp_result))
  291     {
  292     case PURE_INTEGER:
  293         value_to_set.value_int64 = (current_value.value_int64 = TokenToInt64(temp_result))
  294             + ((op == SYM_POST_INCREMENT || op == SYM_PRE_INCREMENT) ? +1 : -1);
  295         break;
  296 
  297     case PURE_FLOAT:
  298         value_to_set.value_double = (current_value.value_double = TokenToDouble(temp_result))
  299             + ((op == SYM_POST_INCREMENT || op == SYM_PRE_INCREMENT) ? +1 : -1);
  300         break;
  301     }
  302 
  303     // Free the object or string returned by BIF_ObjInvoke, if applicable.
  304     if (temp_result.symbol == SYM_OBJECT)
  305         temp_result.object->Release();
  306     if (temp_result.mem_to_free)
  307         free(temp_result.mem_to_free);
  308 
  309     if (current_value.symbol == PURE_NOT_NUMERIC)
  310     {
  311         // Value is non-numeric, so assign and return "".
  312         value_to_set.symbol = SYM_STRING;
  313         value_to_set.marker = _T("");
  314         //current_value.symbol = SYM_STRING; // Already done (SYM_STRING == PURE_NOT_NUMERIC).
  315         current_value.marker = _T("");
  316     }
  317 
  318     // Although it's likely our caller's param array has enough space to hold the extra
  319     // parameter, there's no way to know for sure whether it's safe, so we allocate our own:
  320     ExprTokenType **param = (ExprTokenType **)_alloca((aParamCount + 1) * sizeof(ExprTokenType *));
  321     memcpy(param, aParam, aParamCount * sizeof(ExprTokenType *)); // Copy caller's param pointers.
  322     param[aParamCount++] = &value_to_set; // Append new value as the last parameter.
  323 
  324     if (op == SYM_PRE_INCREMENT || op == SYM_PRE_DECREMENT)
  325     {
  326         aResultToken.marker = (LPTSTR)IT_SET;
  327         // Set the new value and pass the return value of the invocation back to our caller.
  328         // This should be consistent with something like x.y := x.y + 1.
  329         BIF_ObjInvoke(aResult, aResultToken, param, aParamCount);
  330     }
  331     else // SYM_POST_INCREMENT || SYM_POST_DECREMENT
  332     {
  333         // Must be re-initialized (and must use IT_SET instead of IT_GET):
  334         temp_result.symbol = SYM_INTEGER;
  335         temp_result.marker = (LPTSTR)IT_SET;
  336         temp_result.buf = aResultToken.buf;
  337         temp_result.mem_to_free = NULL;
  338         
  339         // Set the new value.
  340         BIF_ObjInvoke(aResult, temp_result, param, aParamCount);
  341         
  342         // Dispose of the result safely.
  343         if (temp_result.symbol == SYM_OBJECT)
  344             temp_result.object->Release();
  345         if (temp_result.mem_to_free)
  346             free(temp_result.mem_to_free);
  347 
  348         // Return the previous value.
  349         aResultToken.symbol = current_value.symbol;
  350         aResultToken.value_int64 = current_value.value_int64; // Union copy.
  351     }
  352 }
  353 
  354 
  355 //
  356 // Functions for accessing built-in methods (even if obscured by a user-defined method).
  357 //
  358 
  359 #define BIF_METHOD(name) \
  360     BIF_DECL(BIF_Obj##name) { \
  361         if (!BIF_ObjMethod(FID_Obj##name, aResultToken, aParam, aParamCount)) \
  362             aResult = FAIL; \
  363     }
  364 
  365 ResultType BIF_ObjMethod(int aID, ExprTokenType &aResultToken, ExprTokenType *aParam[], int aParamCount)
  366 {
  367     aResultToken.symbol = SYM_STRING;
  368     aResultToken.marker = _T("");
  369 
  370     Object *obj = dynamic_cast<Object*>(TokenToObject(*aParam[0]));
  371     if (!obj)
  372         return OK; // Return "".
  373     return obj->CallBuiltin(aID, aResultToken, aParam + 1, aParamCount - 1);
  374 }
  375 
  376 BIF_METHOD(Insert)
  377 BIF_METHOD(InsertAt)
  378 BIF_METHOD(Push)
  379 BIF_METHOD(Pop)
  380 BIF_METHOD(Delete)
  381 BIF_METHOD(Remove)
  382 BIF_METHOD(RemoveAt)
  383 BIF_METHOD(GetCapacity)
  384 BIF_METHOD(SetCapacity)
  385 BIF_METHOD(GetAddress)
  386 BIF_METHOD(Count)
  387 BIF_METHOD(Length)
  388 BIF_METHOD(MaxIndex)
  389 BIF_METHOD(MinIndex)
  390 BIF_METHOD(NewEnum)
  391 BIF_METHOD(HasKey)
  392 BIF_METHOD(Clone)
  393 
  394 
  395 //
  396 // ObjAddRef/ObjRelease - used with pointers rather than object references.
  397 //
  398 
  399 BIF_DECL(BIF_ObjAddRefRelease)
  400 {
  401     IObject *obj = (IObject *)TokenToInt64(*aParam[0]);
  402     if (obj < (IObject *)4096) // Rule out some obvious errors.
  403     {
  404         aResultToken.symbol = SYM_STRING;
  405         aResultToken.marker = _T("");
  406         return;
  407     }
  408     if (ctoupper(aResultToken.marker[3]) == 'A')
  409         aResultToken.value_int64 = obj->AddRef();
  410     else
  411         aResultToken.value_int64 = obj->Release();
  412 }
  413 
  414 
  415 //
  416 // ObjBindMethod(Obj, Method, Params...)
  417 //
  418 
  419 BIF_DECL(BIF_ObjBindMethod)
  420 {
  421     IObject *func, *bound_func;
  422     if (  !(func = TokenToObject(*aParam[0]))
  423         && !(func = TokenToFunc(*aParam[0]))  )
  424     {
  425         aResult = g_script.ScriptError(ERR_PARAM1_INVALID);
  426         return;
  427     }
  428     if (  !(bound_func = BoundFunc::Bind(func, aParam + 1, aParamCount - 1, IT_CALL))  )
  429     {
  430         aResult = g_script.ScriptError(ERR_OUTOFMEM);
  431         return;
  432     }
  433     aResultToken.symbol = SYM_OBJECT;
  434     aResultToken.object = bound_func;
  435 }
  436 
  437 
  438 //
  439 // ObjRawSet - set a value without invoking any meta-functions.
  440 //
  441 
  442 BIF_DECL(BIF_ObjRaw)
  443 {
  444     Object *obj = dynamic_cast<Object*>(TokenToObject(*aParam[0]));
  445     if (!obj)
  446     {
  447         aResult = g_script.ScriptError(ERR_PARAM1_INVALID);
  448         return;
  449     }
  450     if (ctoupper(aResultToken.marker[6]) == 'S')
  451     {
  452         if (!obj->SetItem(*aParam[1], *aParam[2]))
  453         {
  454             aResult = g_script.ScriptError(ERR_OUTOFMEM);
  455             return;
  456         }
  457     }
  458     else
  459     {
  460         ExprTokenType value;
  461         if (obj->GetItem(value, *aParam[1]))
  462         {
  463             switch (value.symbol)
  464             {
  465             case SYM_OPERAND:
  466                 aResultToken.symbol = SYM_STRING;
  467                 aResult = TokenSetResult(aResultToken, value.marker);
  468                 break;
  469             case SYM_OBJECT:
  470                 aResultToken.symbol = SYM_OBJECT;
  471                 aResultToken.object = value.object;
  472                 aResultToken.object->AddRef();
  473                 break;
  474             default:
  475                 aResultToken.symbol = value.symbol;
  476                 aResultToken.value_int64 = value.value_int64;
  477                 break;
  478             }
  479             return;
  480         }
  481     }
  482     aResultToken.symbol = SYM_STRING;
  483     aResultToken.marker = _T("");
  484 }
  485 
  486 
  487 //
  488 // ObjSetBase/ObjGetBase - Change or return Object's base without invoking any meta-functions.
  489 //
  490 
  491 BIF_DECL(BIF_ObjBase)
  492 {
  493     Object *obj = dynamic_cast<Object*>(TokenToObject(*aParam[0]));
  494     if (!obj)
  495     {
  496         aResult = g_script.ScriptError(ERR_PARAM1_INVALID);
  497         return;
  498     }
  499     if (ctoupper(aResultToken.marker[3]) == 'S') // ObjSetBase
  500     {
  501         IObject *new_base = TokenToObject(*aParam[1]);
  502         if (!new_base && !TokenIsEmptyString(*aParam[1]))
  503         {
  504             aResult = g_script.ScriptError(ERR_PARAM2_INVALID);
  505             return;
  506         }
  507         obj->SetBase(new_base);
  508     }
  509     else // ObjGetBase
  510     {
  511         if (IObject *obj_base = obj->Base())
  512         {
  513             obj_base->AddRef();
  514             aResultToken.SetValue(obj_base);
  515             return;
  516         }
  517     }
  518     aResultToken.SetValue(_T(""));
  519 }