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; }
Exec_stat MCFunction::evalparams(Functions func, MCParameter *params, MCExecPoint &ep) { uint4 nparams = 0; real8 n, tn, oldn; n = oldn = 0.0; MCSortnode *mditems = NULL; // JS-2013-06-19: [[ StatsFunctions ]] Support for new stats functions based on arithmeticMean if (func == F_AVG_DEV || func == F_POP_STD_DEV || func == F_POP_VARIANCE || func == F_SMP_STD_DEV || func == F_SMP_VARIANCE) { //use recursion to get average first if (evalparams(F_ARI_MEAN, params, ep) != ES_NORMAL) return ES_ERROR; oldn = ep.getnvalue(); } // JS-2013-06-19: [[ StatsFunctions ]] Support for geometricMean if (func == F_GEO_MEAN) { //use recursion to count items first if (evalparams(F_UNDEFINED, params, ep) != ES_NORMAL) return ES_ERROR; oldn = ep.getnvalue(); } if (func == F_MEDIAN) { //use recursion to count items first if (evalparams(F_UNDEFINED, params, ep) != ES_NORMAL) return ES_ERROR; mditems = new MCSortnode[(uint4)ep.getnvalue()]; } if (params != NULL && params->getnext() == NULL) { if (params->eval(ep) != ES_NORMAL) { MCeerror->add(EE_FUNCTION_BADSOURCE, line, pos); return ES_ERROR; } if (ep.getformat() == VF_ARRAY) { if (ep.getarray() -> is_array() && ep.getarray()->get_array()->dofunc(ep, func, nparams, n, oldn, mditems) != ES_NORMAL) { MCeerror->add(EE_FUNCTION_BADSOURCE, line, pos); return ES_ERROR; } } else { MCString s(ep.getsvalue()); uint4 length = s.getlength(); const char *sptr = s.getstring(); MCU_skip_spaces(sptr, length); while (length != 0) { s.setstring(sptr); if (!MCU_strchr(sptr, length, ',')) { s.setlength(length); length = 0; } else { s.setlength(sptr - s.getstring()); MCU_skip_char(sptr, length); MCU_skip_spaces(sptr, length); } if (s.getlength() == 0) tn = 0.0; else if (!MCU_stor8(s, tn)) { MCeerror->add (EE_FUNCTION_NAN, 0, 0, s); return ES_ERROR; } MCU_dofunc(func, nparams, n, tn, oldn, mditems); } } } else { MCParameter *tparam = params; while (tparam != NULL) { if (tparam->eval(ep) != ES_NORMAL || ep.ton() != ES_NORMAL) { MCeerror->add(EE_FUNCTION_BADSOURCE, line, pos); return ES_ERROR; } MCU_dofunc(func, nparams, n, ep.getnvalue(), oldn, mditems); tparam = tparam->getnext(); } } if (nparams != 0) switch (func) { // JS-2013-06-19: [[ StatsFunctions ]] Support for arithmeticMean (was average) case F_ARI_MEAN: n /= nparams; break; // JS-2013-06-19: [[ StatsFunctions ]] Support for averageDeviation case F_AVG_DEV: n /= nparams; break; // JS-2013-06-19: [[ StatsFunctions ]] Support for harmonicMean case F_HAR_MEAN: n = nparams/n; break; case F_MEDIAN: { uint4 toffset; MCU_sort(mditems, nparams, ST_ASCENDING, ST_NUMERIC); toffset = (nparams + 1)/2 - 1; if ((nparams % 2) != 0) //odd n = mditems[toffset].nvalue; else //even average 2 closest values n = (mditems[toffset].nvalue + mditems[toffset+1].nvalue)/2; break; } // JS-2013-06-19: [[ StatsFunctions ]] Support for populationStandardDeviation case F_POP_STD_DEV: n = sqrt(n/nparams); break; // JS-2013-06-19: [[ StatsFunctions ]] Support for populationVariance case F_POP_VARIANCE: n /= nparams; break; // JS-2013-06-19: [[ StatsFunctions ]] Support for sampleStandardDeviation (was stdDev) case F_SMP_STD_DEV: n = sqrt(n/(nparams - 1)); break; // JS-2013-06-19: [[ StatsFunctions ]] Support for sampleVariance case F_SMP_VARIANCE: n /= nparams - 1; break; case F_UNDEFINED: n = nparams; break; default: break; } ep.setnvalue(n); delete mditems; return ES_NORMAL; }
Parse_stat MCStatement::getparams(MCScriptPoint &sp, MCParameter **params) { Boolean needparam = False; MCParameter *pptr = NULL; while (True) { if (sp.skip_token(SP_COMMAND, TT_ELSE, S_UNDEFINED) == PS_NORMAL) { sp.backup(); return PS_NORMAL; } Symbol_type type; switch (sp.next(type)) { case PS_NORMAL: sp.backup(); break; case PS_ERROR: return PS_ERROR; case PS_EOL: case PS_EOF: if (needparam) { MCperror->add (PE_STATEMENT_BADPARAM, sp); return PS_ERROR; } return PS_NORMAL; default: sp.backup(); return PS_NORMAL; } MCParameter *newptr = new MCParameter; if (newptr->parse(sp) != PS_NORMAL) { delete newptr; MCperror->add (PE_STATEMENT_BADPARAM, sp); return PS_ERROR; } if (pptr == NULL) *params = pptr = newptr; else { pptr->setnext(newptr); pptr = newptr; } if (sp.skip_token(SP_COMMAND, TT_ELSE, S_UNDEFINED) == PS_NORMAL) { sp.backup(); return PS_NORMAL; } switch (sp.next(type)) { case PS_NORMAL: break; case PS_EOL: case PS_EOF: return PS_NORMAL; default: MCperror->add (PE_STATEMENT_NOTSEP, sp); return PS_ERROR; } if (type != ST_SEP) { MCperror->add (PE_STATEMENT_BADSEP, sp); return PS_ERROR; } needparam = True; } return PS_NORMAL; }
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(); } }