void BIF_ObjInvoke(ExprTokenType &aResultToken, ExprTokenType *aParam[], int aParamCount) { int invoke_type; IObject *obj; ExprTokenType *obj_param; // Since ObjGet/ObjSet/ObjCall are not publicly accessible as functions, Func::mName // (passed via aResultToken.marker) contains the actual flag rather than a name. invoke_type = (int)(INT_PTR)aResultToken.marker; // Set default return value; ONLY AFTER THE ABOVE. aResultToken.symbol = SYM_STRING; aResultToken.marker = _T(""); obj_param = *aParam; // aParam[0]. Load-time validation has ensured at least one parameter was specified. ++aParam; --aParamCount; if (obj = TokenToObject(*obj_param)) { bool param_is_var = obj_param->symbol == SYM_VAR; if (param_is_var) // Since the variable may be cleared as a side-effect of the invocation, call AddRef to ensure the object does not expire prematurely. // This is not necessary for SYM_OBJECT since that reference is already counted and cannot be released before we return. Each object // could take care not to delete itself prematurely, but it seems more proper, more reliable and more maintainable to handle it here. obj->AddRef(); obj->Invoke(aResultToken, *obj_param, invoke_type, aParam, aParamCount); if (param_is_var) obj->Release(); } // Invoke meta-functions of g_MetaObject. else if (INVOKE_NOT_HANDLED == g_MetaObject.Invoke(aResultToken, *obj_param, invoke_type | IF_META, aParam, aParamCount) // If above did not handle it, check for attempts to access .base of non-object value (g_MetaObject itself). // CALL is unsupported (for simplicity); SET is supported only in "multi-dimensional" mode: "".base[x]:=y && invoke_type != IT_CALL && (invoke_type == IT_SET ? aParamCount > 2 : aParamCount) && !_tcsicmp(TokenToString(*aParam[0]), _T("base"))) { if (aParamCount > 1) // "".base[x] or similar { // Re-invoke g_MetaObject without meta flag or "base" param. ExprTokenType base_token; base_token.symbol = SYM_OBJECT; base_token.object = &g_MetaObject; g_MetaObject.Invoke(aResultToken, base_token, invoke_type, aParam + 1, aParamCount - 1); } else // "".base { // Return a reference to g_MetaObject. No need to AddRef as g_MetaObject ignores it. aResultToken.symbol = SYM_OBJECT; aResultToken.object = &g_MetaObject; } } }
void BIF_ObjInvoke(ExprTokenType &aResultToken, ExprTokenType *aParam[], int aParamCount) { int invoke_type; IObject *obj; ExprTokenType *obj_param; // Since ObjGet/ObjSet/ObjCall are not publicly accessible as functions, Func::mName // (passed via aResultToken.marker) contains the actual flag rather than a name. invoke_type = (int)(INT_PTR)aResultToken.marker; // Set default return value; ONLY AFTER THE ABOVE. aResultToken.symbol = SYM_STRING; aResultToken.marker = _T(""); obj_param = *aParam; // aParam[0]. Load-time validation has ensured at least one parameter was specified. ++aParam; --aParamCount; // The following is used in place of TokenToObject to bypass #Warn UseUnset: if (obj_param->symbol == SYM_OBJECT) obj = obj_param->object; else if (obj_param->symbol == SYM_VAR && obj_param->var->HasObject()) obj = obj_param->var->Object(); else obj = NULL; if (obj) { bool param_is_var = obj_param->symbol == SYM_VAR; if (param_is_var) // Since the variable may be cleared as a side-effect of the invocation, call AddRef to ensure the object does not expire prematurely. // This is not necessary for SYM_OBJECT since that reference is already counted and cannot be released before we return. Each object // could take care not to delete itself prematurely, but it seems more proper, more reliable and more maintainable to handle it here. obj->AddRef(); obj->Invoke(aResultToken, *obj_param, invoke_type, aParam, aParamCount); if (param_is_var) obj->Release(); } // Invoke meta-functions of g_MetaObject. else if (INVOKE_NOT_HANDLED == g_MetaObject.Invoke(aResultToken, *obj_param, invoke_type | IF_META, aParam, aParamCount)) { // Since above did not handle it, check for attempts to access .base of non-object value (g_MetaObject itself). if ( invoke_type != IT_CALL // Exclude things like "".base(). && aParamCount > (invoke_type == IT_SET ? 2 : 0) // SET is supported only when an index is specified: "".base[x]:=y && !_tcsicmp(TokenToString(*aParam[0]), _T("base")) ) { if (aParamCount > 1) // "".base[x] or similar { // Re-invoke g_MetaObject without meta flag or "base" param. ExprTokenType base_token; base_token.symbol = SYM_OBJECT; base_token.object = &g_MetaObject; g_MetaObject.Invoke(aResultToken, base_token, invoke_type, aParam + 1, aParamCount - 1); } else // "".base { // Return a reference to g_MetaObject. No need to AddRef as g_MetaObject ignores it. aResultToken.symbol = SYM_OBJECT; aResultToken.object = &g_MetaObject; } } else { // Since it wasn't handled (not even by g_MetaObject), maybe warn at this point: if (obj_param->symbol == SYM_VAR) obj_param->var->MaybeWarnUninitialized(); } } }