Exec_stat MCComref::exec(MCExecPoint &ep) { if (MCscreen->abortkey()) { MCeerror->add(EE_HANDLER_ABORT, line, pos); return ES_ERROR; } if (!resolved) { // MW-2008-01-28: [[ Inherited parentScripts ]] // If we are in parentScript context, then the object we search for // private handlers in is the parentScript's object, rather than the // ep's. MCParentScriptUse *t_parentscript; t_parentscript = ep . getparentscript(); MCObject *t_object; if (t_parentscript == NULL) t_object = ep . getobj(); else t_object = t_parentscript -> GetParent() -> GetObject(); // MW-2008-10-28: [[ ParentScripts ]] Private handlers are resolved // relative to the object containing the handler we are executing. MCHandler *t_resolved_handler; t_resolved_handler = t_object -> findhandler(HT_MESSAGE, name); if (t_resolved_handler != NULL && t_resolved_handler -> isprivate()) handler = t_resolved_handler; resolved = true; } Exec_stat stat; MCParameter *tptr = params; while (tptr != NULL) { MCVariable* t_var; t_var = tptr -> evalvar(ep); if (t_var == NULL) { tptr -> clear_argument(); while ((stat = tptr->eval(ep)) != ES_NORMAL && (MCtrace || MCnbreakpoints) && !MCtrylock && !MClockerrors) MCB_error(ep, line, pos, EE_STATEMENT_BADPARAM); if (stat != ES_NORMAL) { MCeerror->add(EE_STATEMENT_BADPARAM, line, pos); return ES_ERROR; } tptr->set_argument(ep); } else tptr->set_argument_var(t_var); tptr = tptr->getnext(); } MCObject *p = ep.getobj(); MCExecPoint *oldep = MCEPptr; MCEPptr = &ep; stat = ES_NOT_HANDLED; Boolean added = False; if (MCnexecutioncontexts < MAX_CONTEXTS) { ep.setline(line); MCexecutioncontexts[MCnexecutioncontexts++] = &ep; added = True; } if (handler != nil) { // MW-2008-10-28: [[ ParentScripts ]] If we are in the context of a // parent, then use a special method. if (ep . getparentscript() == NULL) stat = p -> exechandler(handler, params); else stat = p -> execparenthandler(handler, params, ep . getparentscript()); switch(stat) { case ES_ERROR: case ES_PASS: MCeerror->add(EE_STATEMENT_BADCOMMAND, line, pos, handler -> getname()); if (MCerrorptr == NULL) MCerrorptr = p; stat = ES_ERROR; break; case ES_EXIT_HANDLER: stat = ES_NORMAL; break; default: break; } } else { stat = MCU_dofrontscripts(HT_MESSAGE, name, params); Boolean olddynamic = MCdynamicpath; MCdynamicpath = MCdynamiccard != NULL; if (stat == ES_PASS || stat == ES_NOT_HANDLED) switch (stat = p->handle(HT_MESSAGE, name, params, p)) { case ES_ERROR: case ES_NOT_FOUND: case ES_NOT_HANDLED: case ES_PASS: MCeerror->add(EE_STATEMENT_BADCOMMAND, line, pos, name); stat = ES_ERROR; break; case ES_EXIT_HANDLER: stat = ES_NORMAL; break; default: break; } MCdynamicpath = olddynamic; } MCEPptr = oldep; if (added) MCnexecutioncontexts--; return stat; }
void MCKeywordsExecCommandOrFunction(MCExecContext& ctxt, bool resolved, MCHandler *handler, MCParameter *params, MCNameRef name, uint2 line, uint2 pos, bool global_handler, bool is_function) { if (MCscreen->abortkey()) { ctxt . LegacyThrow(EE_HANDLER_ABORT); return; } if (!resolved) { // MW-2008-01-28: [[ Inherited parentScripts ]] // If we are in parentScript context, then the object we search for // private handlers in is the parentScript's object, rather than the // ep's. MCParentScriptUse *t_parentscript; t_parentscript = ctxt . GetParentScript(); MCObject *t_object; if (t_parentscript == NULL) t_object = ctxt . GetObject(); else t_object = t_parentscript -> GetParent() -> GetObject(); // MW-2008-10-28: [[ ParentScripts ]] Private handlers are resolved // relative to the object containing the handler we are executing. MCHandler *t_resolved_handler; t_resolved_handler = t_object -> findhandler(is_function ? HT_FUNCTION : HT_MESSAGE, name); if (t_resolved_handler != NULL && t_resolved_handler -> isprivate()) handler = t_resolved_handler; resolved = true; } if (is_function) MCexitall = False; // Go through all the parameters to the function, if they are not variables, clear their current value. Each parameter stores an expression // which allows its value to be re-evaluated in a given context. Re-evaluate each in the context of ep and set it to the new value. // As the ep should contain the context of the caller at this point, the expression should be evaluated in that context. Exec_stat stat; MCParameter *tptr = params; while (tptr != NULL) { // AL-2014-08-20: [[ ArrayElementRefParams ]] Use containers for potential reference parameters MCAutoPointer<MCContainer> t_container = new (nothrow) MCContainer; if (tptr -> evalcontainer(ctxt, **t_container)) tptr -> set_argument_container(t_container.Release()); else { tptr -> clear_argument(); MCExecValue t_value; //HERE if (!ctxt . TryToEvaluateParameter(tptr, line, pos, is_function ? EE_FUNCTION_BADSOURCE : EE_STATEMENT_BADPARAM, t_value)) return; tptr->give_exec_argument(t_value); } tptr = tptr->getnext(); } MCObject *p = ctxt . GetObject(); MCExecContext *oldctxt = MCECptr; MCECptr = &ctxt; stat = ES_NOT_HANDLED; Boolean added = False; if (MCnexecutioncontexts < MAX_CONTEXTS) { ctxt . SetLineAndPos(line, pos); MCexecutioncontexts[MCnexecutioncontexts++] = &ctxt; added = True; } if (handler != nil) { // MW-2008-10-28: [[ ParentScripts ]] If we are in the context of a // parent, then use a special method. if (ctxt . GetParentScript() == nil) stat = p -> exechandler(handler, params); else stat = p -> execparenthandler(handler, params, ctxt . GetParentScript()); switch(stat) { case ES_ERROR: case ES_PASS: MCeerror->add(is_function ? EE_FUNCTION_BADFUNCTION : EE_STATEMENT_BADCOMMAND, line, pos, handler -> getname()); if (!MCerrorptr) MCerrorptr = p; stat = ES_ERROR; break; case ES_EXIT_HANDLER: stat = ES_NORMAL; break; default: break; } } else { stat = MCU_dofrontscripts(is_function ? HT_FUNCTION : HT_MESSAGE, name, params); Boolean olddynamic = MCdynamicpath; MCdynamicpath = MCdynamiccard.IsValid(); if (stat == ES_PASS || stat == ES_NOT_HANDLED) { if (is_function) { // PASS STATE FIX Exec_stat oldstat = stat; stat = p->handle(HT_FUNCTION, name, params, p); if (oldstat == ES_PASS && stat == ES_NOT_HANDLED) stat = ES_PASS; } else { switch (stat = p->handle(HT_MESSAGE, name, params, p)) { case ES_ERROR: case ES_NOT_FOUND: case ES_NOT_HANDLED: case ES_PASS: if (!global_handler) { MCeerror->add(EE_STATEMENT_BADCOMMAND, line, pos, name); stat = ES_ERROR; } break; case ES_EXIT_HANDLER: stat = ES_NORMAL; break; default: break; } } if (global_handler && (stat == ES_NOT_FOUND || stat == ES_NOT_HANDLED)) { if (!MCRunGlobalHandler(name, params, stat)) stat = ES_NOT_HANDLED; // AL-2014-03-14: Currently no mobile handler's execution is halted when ES_ERROR // is returned. Error info is returned via the result. #ifdef _MOBILE if (stat != ES_NOT_HANDLED) stat = ES_NORMAL; #endif } } MCdynamicpath = olddynamic; } MCECptr = oldctxt; if (added) MCnexecutioncontexts--; if (stat != ES_NORMAL && stat != ES_PASS && stat != ES_EXIT_HANDLER) ctxt . SetExecStat(stat); else ctxt . SetExecStat(ES_NORMAL); // AL-2014-09-17: [[ Bug 13465 ]] Clear parameters after executing command/function tptr = params; while (tptr != NULL) { tptr -> clear_argument(); tptr = tptr->getnext(); } }