예제 #1
0
void MCKeywordsExecSwitch(MCExecContext& ctxt, MCExpression *condition, MCExpression **cases, uindex_t case_count, int2 default_case, uint2 *case_offsets, MCStatement *statements, uint2 line, uint2 pos)
{
    MCAutoValueRef t_value;
    MCAutoStringRef t_cond;
	if (condition != NULL)
	{
        if (!ctxt . TryToEvaluateExpression(condition, line, pos, EE_SWITCH_BADCOND, &t_value))
            return;
        
        if (!ctxt . ConvertToString(*t_value, &t_cond))
        {
            ctxt . LegacyThrow(EE_SWITCH_BADCOND);
            return;
        }
	}
    else
        t_cond = MCValueRetain(kMCTrueString);
    
	int2 match = default_case;
	uint2 i;
	for (i = 0 ; i < case_count ; i++)
	{
        MCAutoValueRef t_case;
        MCAutoStringRef t_case_string;
        
        if (!ctxt . TryToEvaluateExpression(cases[i], line, pos, EE_SWITCH_BADCASE, &t_case))
            return;
        
        if (!ctxt . ConvertToString(*t_case, &t_case_string))
        {
            ctxt . LegacyThrow(EE_SWITCH_BADCASE);
            return;
        }
        
		if (MCStringIsEqualTo(*t_cond, *t_case_string, ctxt . GetStringComparisonType()))
        {
            match = case_offsets[i];
            break;
        }
	}
    
	if (match >= 0)
	{
		MCStatement *tspr = statements;
		while (match--)
			tspr = tspr->getnext();
        
        // SN-2014-08-06: [[ Bug 13122 ]] If we get an EXIT_SWITCH, it's all right
        Exec_stat t_stat;
        t_stat = MCKeywordsExecuteStatements(ctxt, tspr, EE_SWITCH_BADSTATEMENT);
        if (t_stat == ES_EXIT_SWITCH)
            t_stat = ES_NORMAL;
        
        ctxt . SetExecStat(t_stat);
    }
}
예제 #2
0
void MCKeywordsExecTry(MCExecContext& ctxt, MCStatement *trystatements, MCStatement *catchstatements, MCStatement *finallystatements, MCVarref *errorvar, uint2 line, uint2 pos)
{
	Try_state state = TS_TRY;
	MCStatement *tspr = trystatements;
	Exec_stat stat;
	Exec_stat retcode = ES_NORMAL;
	MCtrylock++;
	while (tspr != NULL)
	{
		if (MCtrace || MCnbreakpoints)
		{
			MCB_trace(ctxt, tspr->getline(), tspr->getpos());
			if (MCexitall)
				break;
		}
		ctxt . SetLineAndPos(tspr->getline(), tspr->getpos());
        
		//stat = tspr->exec(ctxt . GetEP());
        tspr->exec_ctxt(ctxt);
        stat = ctxt . GetExecStat();
        ctxt . IgnoreLastError();
        
        MCActionsRunAll();
        
		switch(stat)
		{
            case ES_NORMAL:
                tspr = tspr->getnext();
                if (MCexitall)
                {
                    retcode = ES_NORMAL;
                    tspr = NULL;
                }
                
                if (tspr == NULL && state != TS_FINALLY)
                {
                    // Everything has executed normally but there may have been an
                    // error added on another event. The trylock needs refactoring to
                    // ensure a trylock on one event can't cause issues in another
                    // event.
                    MCeerror->clear();
                    
                    tspr = finallystatements;
                    state = TS_FINALLY;
                }
                break;
            case ES_ERROR:
                if ((MCtrace || MCnbreakpoints) && state != TS_TRY)
                    do
                    {
                        if (MCB_error(ctxt, tspr->getline(), tspr->getpos(), EE_TRY_BADSTATEMENT))
                            break;
                        ctxt.IgnoreLastError();
                        tspr->exec_ctxt(ctxt);
                    }
				while(MCtrace && (stat = ctxt . GetExecStat()) != ES_NORMAL);
                
                if (stat == ES_ERROR)
                {
                    if (MCexitall)
                    {
                        retcode = ES_NORMAL;
                        tspr = NULL;
                    }
                    else
                        if (state != TS_TRY)
                        {
                            MCtrylock--;
                            return;
                        }
                        else
                        {
                            if (errorvar != NULL)
                            {
                                MCAutoStringRef t_error;
                                MCeerror -> copyasstringref(&t_error);
                                errorvar->set(ctxt, *t_error);
                            }
                            
                            // MW-2007-09-04: At this point we need to clear the execution error
                            //   stack so that errors inside the catch statements are reported
                            //   correctly.
                            MCeerror->clear();
                            MCperror->clear();
                            
                            
                            tspr = catchstatements;
                            state = TS_CATCH;
                            
                            // MW-2007-07-03: [[ Bug 3029 ]] - If there is no catch clause
                            //   we end up skipping the finally as the loop terminates
                            //   before a state transition is made, thus we force it here.
                            if (catchstatements == NULL)
                            {
                                MCeerror -> clear();
                                tspr = finallystatements;
                                state = TS_FINALLY;
                            }
                        }
                }
                else
                    tspr = tspr->getnext();
                break;
            case ES_PASS:
                if (state == TS_CATCH)
                {
                    MCAutoValueRef t_value;
                    MCAutoStringRef t_string;
                    if ((errorvar->eval(ctxt, &t_value), !ctxt.HasError()) &&
                        ctxt . ConvertToString(*t_value, &t_string))
                    {
                        MCeerror->copystringref(*t_string, False);
                    }
                    
                    MCeerror->add(EE_TRY_BADSTATEMENT, line, pos);
                    stat = ES_ERROR;
                }
            default:
                if (state == TS_FINALLY)
                {
                    MCeerror->clear();
                    retcode = ES_NORMAL;
                    tspr = NULL;
                }
                else
                {
                    retcode = stat;
                    tspr = finallystatements;
                    state = TS_FINALLY;
                }
		}
	}
	if (state == TS_CATCH)
		MCeerror->clear();
	MCtrylock--;
	ctxt . SetExecStat(retcode);
}
예제 #3
0
static Exec_stat MCKeywordsExecuteStatements(MCExecContext& ctxt, MCStatement *p_statements, Exec_errors p_error)
{
    Exec_stat stat = ES_NORMAL;
    MCStatement *tspr = p_statements;
    while (tspr != NULL)
    {
        if (MCtrace || MCnbreakpoints)
        {
            MCB_trace(ctxt, tspr->getline(), tspr->getpos());
            if (MCexitall)
                break;
        }
        ctxt . SetLineAndPos(tspr->getline(), tspr->getpos());
        
       // stat = tspr->exec(ctxt . GetEP());
        tspr->exec_ctxt(ctxt);
        stat = ctxt . GetExecStat();
        ctxt . IgnoreLastError();
        
        MCActionsRunAll();
        
        switch(stat)
        {
            case ES_NORMAL:
                if (MCexitall)
                    return ES_NORMAL;
                tspr = tspr->getnext();
                break;
            case ES_NEXT_REPEAT:
                tspr = NULL;
                break;
            // SN-2014-08-06: [[ Bug 13122 ]] We want to know that we got an EXIT_SWITCH,
            //  since we might be inside an IF statement
            case ES_EXIT_REPEAT:
            case ES_EXIT_SWITCH:
                return stat;
            case ES_ERROR:
                if ((MCtrace || MCnbreakpoints) && !MCtrylock && !MClockerrors)
                    do
                    {
                        if (!MCB_error(ctxt, tspr->getline(), tspr->getpos(),
                                  p_error))
                            break;
                        ctxt . IgnoreLastError();
                        tspr->exec_ctxt(ctxt);
                    }
                while (MCtrace && (stat = ctxt . GetExecStat()) != ES_NORMAL);
                if (stat == ES_ERROR)
                {
                    if (MCexitall)  
                        return ES_NORMAL;
                    
                    ctxt . LegacyThrow(p_error);
                    return stat;
                }
                else
                    tspr = tspr->getnext();
                break;
            default:
                return stat;
        }
    }
    return stat;
}
예제 #4
0
Exec_stat MCRepeat::exec(MCExecPoint &ep)
{
	real8 endn = 0.0;
	int4 count = 0;
	MCExecPoint ep2(ep);
	MCScriptPoint *sp = NULL;
	Parse_stat ps;
	const char *sptr;
	uint4 l;
	MCVariableValue *tvar = NULL;
	MCHashentry *hptr = NULL;
	uint4 kindex = 0;
	Boolean donumeric = False;
	Exec_stat stat;
	switch (form)
	{
	case RF_FOR:
		if (loopvar != NULL)
		{
			while ((stat = endcond->eval(ep2)) != ES_NORMAL
			        && (MCtrace || MCnbreakpoints) && !MCtrylock && !MClockerrors)
				MCB_error(ep2, getline(), getpos(), EE_REPEAT_BADFORCOND);
			if (stat != ES_NORMAL)
			{
				MCeerror->add(EE_REPEAT_BADFORCOND, line, pos);
				return ES_ERROR;
			}
			if (each == FU_ELEMENT)
			{
				tvar = ep2.getarray();
				if (tvar != NULL && tvar -> is_array())
				{
					l = 1;
					kindex = 0;
					donumeric = tvar -> get_array() -> isnumeric();
					hptr = tvar -> get_array() -> getnextelement(kindex, hptr, donumeric, ep);
					if (hptr == NULL)
					{
						kindex = 0;
						donumeric = False;
						hptr = tvar -> get_array() -> getnextelement(kindex, hptr, donumeric, ep);
					}
				}
				else
					l = 0;
			}
			else if (each == FU_KEY)
			{
				tvar = ep2.getarray();
				if (tvar != NULL && tvar -> is_array())
				{
					l = 1;
					kindex = 0;
					donumeric = False;
					hptr = tvar -> get_array() -> getnextkey(kindex, hptr);
					// [[ Bug 3871 ]] : If hptr is NULL then we are done already (this can happen
					//                  with an empty custom property set).
					if (hptr == NULL)
						l = 0;
				}
				else
					l = 0;
			}
			else
			{
				sptr = ep2.getsvalue().getstring();
				l = ep2.getsvalue().getlength();
				if (each == FU_WORD)
					MCU_skip_spaces(sptr, l);
				else
					if (each == FU_TOKEN)
					{
						sp = new MCScriptPoint(ep2);
						ps = sp->nexttoken();
						if (ps == PS_ERROR || ps == PS_EOF)
							l = 0;
					}
			}
		}
		else
		{
			while (((stat = endcond->eval(ep)) != ES_NORMAL
			        || (stat = ep.ton()) != ES_NORMAL) && (MCtrace || MCnbreakpoints)
			        && !MCtrylock && !MClockerrors)
				MCB_error(ep, getline(), getpos(), EE_REPEAT_BADFORCOND);
			if (stat != ES_NORMAL)
			{
				MCeerror->add
				(EE_REPEAT_BADFORCOND, line, pos);
				return ES_ERROR;
			}
			count = MCU_max(ep.getint4(), 0);
		}
		break;
	case RF_WITH:
		if (step != NULL)
		{
			while (((stat = step->eval(ep)) != ES_NORMAL
			        || (stat = ep.ton()) != ES_NORMAL) && (MCtrace || MCnbreakpoints)
			        && !MCtrylock && !MClockerrors)
				MCB_error(ep, getline(), getpos(), EE_REPEAT_BADWITHSTEP);
			stepval = ep.getnvalue();
			if (stat != ES_NORMAL || stepval == 0.0)
			{
				MCeerror->add
				(EE_REPEAT_BADWITHSTEP, line, pos);
				return ES_ERROR;
			}
		}
		while (((stat = startcond->eval(ep)) != ES_NORMAL
		        || (stat = ep.ton()) != ES_NORMAL) && (MCtrace || MCnbreakpoints)
		        && !MCtrylock && !MClockerrors)
			MCB_error(ep, getline(), getpos(), EE_REPEAT_BADWITHSTART);
		if (stat != ES_NORMAL)
		{
			MCeerror->add
			(EE_REPEAT_BADWITHSTART, line, pos);
			return ES_ERROR;
		}
		ep.setnvalue(ep.getnvalue() - stepval);
		while ((stat = loopvar->set
		               (ep)) != ES_NORMAL
		        && (MCtrace || MCnbreakpoints) && !MCtrylock && !MClockerrors)
			MCB_error(ep, getline(), getpos(), EE_REPEAT_BADWITHVAR);
		if (stat != ES_NORMAL)
		{
			MCeerror->add
			(EE_REPEAT_BADWITHVAR, line, pos);
			return ES_ERROR;
		}
		while (((stat = endcond->eval(ep)) != ES_NORMAL
		        || (stat = ep.ton()) != ES_NORMAL)
		        && (MCtrace || MCnbreakpoints) && !MCtrylock && !MClockerrors)
			MCB_error(ep, getline(), getpos(), EE_REPEAT_BADWITHEND);
		if (stat != ES_NORMAL)
		{
			MCeerror->add
			(EE_REPEAT_BADWITHEND, line, pos);
			return ES_ERROR;
		}
		endn = ep.getnvalue();
		break;
	default:
		break;
	}

	MCString s;
	Boolean done = False;
	bool t_first;
	t_first = false;
	while (True)
	{
		switch (form)
		{
		case RF_FOREVER:
			break;
		case RF_FOR:
			if (loopvar != NULL)
			{
				if (l == 0)
				{
					done = True;
					// OK-2007-12-05 : Bug 5605. If there has been at least one iteration, set the loop variable to 
					// whatever the value was in the last iteration. 
					if (!t_first)
					{
						// MW-2011-02-08: [[ Bug ]] Make sure we don't use 's' if the repeat type is 'key' or
						//   'element'.
						if (each != FU_ELEMENT && each != FU_KEY)
						{
							ep.setsvalue(s);
							loopvar->set(ep);
						}
					}
				}
				else
				{
					const char *startptr; // = sptr;
					switch (each)
					{
					case FU_KEY:
						// MW-2010-12-15: [[ Bug 9218 ]] Make a copy of the key so that it can't be mutated
						//   accidentally.
						ep . setstaticcstring(hptr -> string);
						loopvar -> set(ep);
						hptr = tvar -> get_array() -> getnextkey(kindex, hptr);
						if (hptr == NULL)
							l = 0;
						break;
					case FU_ELEMENT:
						hptr -> value . fetch(ep);
						loopvar -> set(ep);
						hptr = tvar -> get_array() -> getnextelement(kindex, hptr, donumeric, ep);
						if (hptr == NULL)
							l = 0;
						break;
					case FU_LINE:
						startptr = sptr;
						if (!MCU_strchr(sptr, l, ep.getlinedel()))
						{
							sptr += l;
							l = 0;
						}
						s.set(startptr, sptr - startptr);
						MCU_skip_char(sptr, l);
						break;
					case FU_ITEM:
						startptr = sptr;
						if (!MCU_strchr(sptr, l, ep.getitemdel()))
						{
							sptr += l;
							l = 0;
						}
						s.set(startptr, sptr - startptr);
						MCU_skip_char(sptr, l);
						break;
					case FU_WORD:
						startptr = sptr;
						if (*sptr == '\"')
						{
							MCU_skip_char(sptr, l);
							while (l && *sptr != '\"' && *sptr != '\n')
								MCU_skip_char(sptr, l);
							MCU_skip_char(sptr, l);
						}
						else
							while (l && !isspace((uint1)*sptr))
								MCU_skip_char(sptr, l);
						s.set(startptr, sptr - startptr);
						MCU_skip_spaces(sptr, l);
						break;
					case FU_TOKEN:
						s = sp->gettoken();
						ps = sp->nexttoken();
						if (ps == PS_ERROR || ps == PS_EOF)
							l = 0;
						break;
					case FU_CHARACTER:
					default:
						startptr = sptr;
						s.set(startptr, 1);
						MCU_skip_char(sptr, l);
					}
					// MW-2010-12-15: [[ Bug 9218 ]] Added KEY to the type of repeat that already
					//   copies the value.
					if (each != FU_ELEMENT && each != FU_KEY)
					{
						if (MCtrace)
						{
							ep.setsvalue(s);
							loopvar->set(ep);
						}
						else
							loopvar->sets(s);
					}
				}
			}
			else
				done = count-- == 0;
			break;
		case RF_UNTIL:
			while ((stat = endcond->eval(ep)) != ES_NORMAL
			        && (MCtrace || MCnbreakpoints) && !MCtrylock && !MClockerrors)
				MCB_error(ep, getline(), getpos(), EE_REPEAT_BADUNTILCOND);
			if (stat != ES_NORMAL)
			{
				MCeerror->add
				(EE_REPEAT_BADUNTILCOND, line, pos);
				return ES_ERROR;
			}
			done = ep.getsvalue() == MCtruemcstring;
			break;
		case RF_WHILE:
			while ((stat = endcond->eval(ep)) != ES_NORMAL
			        && (MCtrace || MCnbreakpoints) && !MCtrylock && !MClockerrors)
				MCB_error(ep, getline(), getpos(), EE_REPEAT_BADWHILECOND);
			if (stat != ES_NORMAL)
			{
				MCeerror->add
				(EE_REPEAT_BADWHILECOND, line, pos);
				return ES_ERROR;
			}
			done = ep.getsvalue() != MCtruemcstring;
			break;
		case RF_WITH:
			while (((stat = loopvar->eval(ep)) != ES_NORMAL
			        || (stat = ep.ton()) != ES_NORMAL)
			        && (MCtrace || MCnbreakpoints) && !MCtrylock && !MClockerrors)
				MCB_error(ep, getline(), getpos(), EE_REPEAT_BADWITHVAR);
			if (stat != ES_NORMAL)
			{
				MCeerror->add
				(EE_REPEAT_BADWITHVAR, line, pos);
				return ES_ERROR;
			}
			if (stepval < 0)
			{
				if (ep.getnvalue() <= endn)
					done = True;
			}
			else
				if (ep.getnvalue() >= endn)
					done = True;
			if (!done)
			{
				ep.setnvalue(ep.getnvalue() + stepval);
				while ((stat = loopvar->set
				               (ep)) != ES_NORMAL
				        && (MCtrace || MCnbreakpoints) && !MCtrylock && !MClockerrors)
					MCB_error(ep, getline(), getpos(), EE_REPEAT_BADWITHVAR);
				if (stat != ES_NORMAL)
				{
					MCeerror->add
					(EE_REPEAT_BADWITHVAR, line, pos);
					return ES_ERROR;
				}
			}
			break;
		default:
			break;
		}
		if (done)
			break;

		Exec_stat stat;
		MCStatement *tspr = statements;
		while (tspr != NULL)
		{
			if (MCtrace || MCnbreakpoints)
			{
				MCB_trace(ep, tspr->getline(), tspr->getpos());
				if (MCexitall)
					break;
			}
			ep.setline(tspr->getline());

			stat = tspr->exec(ep);

			// MW-2011-08-17: [[ Redraw ]] Flush any screen updates.
			MCRedrawUpdateScreen();
			
			switch(stat)
			{
			case ES_NORMAL:
				if (MCexitall)
				{
					// OK-2007-12-05 : Bug 5605 : If exiting loop, set the loop variable to the value it had
					//   in the last iteration.
					// MW-2011-02-08: [[ Bug ]] Make sure we don't use 's' if the repeat type is 'key' or
					//   'element'.
					if (form == RF_FOR && loopvar != NULL && each != FU_ELEMENT && each != FU_KEY)
					{
						ep.setsvalue(s);
						loopvar->set(ep);
					}
					delete sp;
					return ES_NORMAL;
				}
				tspr = tspr->getnext();
				break;
			case ES_NEXT_REPEAT:
				tspr = NULL;
				break;
			case ES_EXIT_REPEAT:
				// OK-2007-12-05 : Bug 5605 : If exiting loop, set the loop variable to the value it had
				//   in the last iteration.
				// MW-2011-02-08: [[ Bug ]] Make sure we don't use 's' if the repeat type is 'key' or
				//   'element'.
				if (form == RF_FOR && loopvar != NULL && each != FU_ELEMENT && each != FU_KEY)
				{
					ep.setsvalue(s);
					loopvar->set(ep);
				}
				delete sp;
				return ES_NORMAL;
			case ES_ERROR:
				if ((MCtrace || MCnbreakpoints) && !MCtrylock && !MClockerrors)
					do
					{
						MCB_error(ep, tspr->getline(), tspr->getpos(),
						          EE_REPEAT_BADSTATEMENT);
					}
					while (MCtrace && (stat = tspr->exec(ep)) != ES_NORMAL);
				if (stat == ES_ERROR)
				{
					// OK-2007-12-05 : Bug 5605 : If exiting loop, set the loop variable to the value it had
					//   in the last iteration.
					// MW-2011-02-08: [[ Bug ]] Make sure we don't use 's' if the repeat type is 'key' or
					//   'element'.
					if (form == RF_FOR && loopvar != NULL && each != FU_ELEMENT && each != FU_KEY)
					{
						ep.setsvalue(s);
						loopvar->set(ep);
					}
					delete sp;
					if (MCexitall)
						return ES_NORMAL;
					else
					{
						MCeerror->add(EE_REPEAT_BADSTATEMENT, line, pos);
						return ES_ERROR;
					}
				}
				else
					tspr = tspr->getnext();
				break;
			default:
				// OK-2007-12-05 : Bug 5605 : If exiting loop, set the loop variable to the value it had
				//   in the last iteration.
				// MW-2011-02-08: [[ Bug ]] Make sure we don't use 's' if the repeat type is 'key' or
				//   'element'.
				if (form == RF_FOR && loopvar != NULL && each != FU_ELEMENT && each != FU_KEY)
				{
					ep.setsvalue(s);
					loopvar->set(ep);
				}
				delete sp;
				return stat;
			}
		}
		if (MCscreen->abortkey())
		{
			// OK-2007-12-05 : Bug 5605 : If exiting loop, set the loop variable to the value it had
			//   in the last iteration.
			// MW-2011-02-08: [[ Bug ]] Make sure we don't use 's' if the repeat type is 'key' or
			//   'element'.
			if (form == RF_FOR && loopvar != NULL && each != FU_ELEMENT && each != FU_KEY)
			{
				ep.setsvalue(s);
				loopvar->set(ep);
			}
			delete sp;
			MCeerror->add(EE_REPEAT_ABORT, line, pos);
			return ES_ERROR;
		}
		if (MCtrace || MCnbreakpoints)
		{
			MCB_trace(ep, getline(), getpos());
			if (MCexitall)
				break;
		}

		t_first = false;
	}
	delete sp;
	return ES_NORMAL;
}
예제 #5
0
Exec_stat MCIf::exec(MCExecPoint &ep)
{
	Exec_stat stat;
	while ((stat = cond->eval(ep)) != ES_NORMAL && (MCtrace || MCnbreakpoints)
	        && !MCtrylock && !MClockerrors)
		MCB_error(ep, getline(), getpos(), EE_IF_BADCOND);
	if (stat != ES_NORMAL)
	{
		MCeerror->add
		(EE_IF_BADCOND, line, pos);
		return ES_ERROR;
	}

	Boolean then = ep.getsvalue() == MCtruemcstring;
	MCStatement *tspr;
	if (then)
		tspr = thenstatements;
	else
		tspr = elsestatements;

	while (tspr != NULL)
	{
		if (MCtrace || MCnbreakpoints)
		{
			MCB_trace(ep, tspr->getline(), tspr->getpos());
			if (MCexitall)
				break;
		}
		ep.setline(tspr->getline());
		
		stat = tspr->exec(ep);
		
		// MW-2011-08-17: [[ Redraw ]] Flush any screen updates.
		MCRedrawUpdateScreen();

		switch(stat)
		{
		case ES_NORMAL:
			if (MCexitall)
				return ES_NORMAL;
			tspr = tspr->getnext();
			break;
		case ES_ERROR:
			if ((MCtrace || MCnbreakpoints) && !MCtrylock && !MClockerrors)
				do
				{
					MCB_error(ep, tspr->getline(), tspr->getpos(), EE_IF_BADSTATEMENT);
				}
				while (MCtrace && (stat = tspr->exec(ep)) != ES_NORMAL);
			if (stat == ES_ERROR)
				if (MCexitall)
					return ES_NORMAL;
				else
				{
					MCeerror->add(EE_IF_BADSTATEMENT, line, pos);
					return ES_ERROR;
				}
			else
				tspr = tspr->getnext();
			break;
		default:
			return stat;
		}
	}
	return ES_NORMAL;
}
예제 #6
0
Parse_stat MCRepeat::parse(MCScriptPoint &sp)
{
	Parse_stat stat;
	Symbol_type type;
	const LT *te;

	initpoint(sp);
	if ((stat = sp.next(type)) != PS_NORMAL)
	{
		if (stat == PS_EOL)
		{
			if (sp.skip_eol() != PS_NORMAL)
			{
				MCperror->add
				(PE_REPEAT_BADCONDEOL, sp);
				return PS_ERROR;
			}
		}
		else
		{
			MCperror->add
			(PE_REPEAT_BADCONDTYPE, sp);
			return PS_ERROR;
		}
	}
	else
		switch (stat)
		{
		case PS_NORMAL:
			if (sp.lookup(SP_REPEAT, te) != PS_NORMAL)
			{
				sp.backup();
				form = RF_FOR;
				if (sp.parseexp(False, True, &endcond) != PS_NORMAL)
				{
					MCperror->add
					(PE_REPEAT_BADCOND, sp);
					return PS_ERROR;
				}
			}
			else
			{
				MCExpression *newfact = NULL;
				switch (form = (Repeat_form)te->which)
				{
				case RF_FOREVER:
					break;
				case RF_FOR:
					if (sp.skip_token(SP_REPEAT, TT_UNDEFINED, RF_EACH) == PS_NORMAL)
					{
						if (sp.next(type) != PS_NORMAL
						        || sp.lookup(SP_UNIT, te) != PS_NORMAL
						        || sp.next(type) != PS_NORMAL)
						{
							MCperror->add(PE_REPEAT_BADCOND, sp);
							return PS_ERROR;
						}
						each = (File_unit)te->which;
						if (sp.lookupconstant(&newfact) == PS_NORMAL
						        || sp . findnewvar(sp.gettoken_nameref(), kMCEmptyName, &loopvar) != PS_NORMAL)
						{
							delete newfact;
							MCperror->add(PE_REPEAT_BADWITHVAR, sp);
							return PS_ERROR;
						}
						if (sp.skip_token(SP_FACTOR, TT_IN) != PS_NORMAL)
						{
							MCperror->add(PE_REPEAT_NOOF, sp);
							return PS_ERROR;
						}
					}
				case RF_UNTIL:
				case RF_WHILE:
					if (sp.parseexp(False, True, &endcond) != PS_NORMAL)
					{
						MCperror->add
						(PE_REPEAT_BADCOND, sp);
						return PS_ERROR;
					}
					break;
				case RF_WITH:
					if ((stat = sp.next(type)) != PS_NORMAL)
					{
						MCperror->add
						(PE_REPEAT_NOWITHVAR, sp);
						return PS_ERROR;
					}
					if (sp.lookupconstant(&newfact) == PS_NORMAL
					        || sp.findnewvar(sp.gettoken_nameref(), kMCEmptyName, &loopvar) != PS_NORMAL)
					{
						delete newfact;
						MCperror->add
						(PE_REPEAT_BADWITHVAR, sp);
						return PS_ERROR;
					}
					if ((stat = sp.next(type)) != PS_NORMAL)
					{
						MCperror->add
						(PE_REPEAT_NOEQUALS, sp);
						return PS_ERROR;
					}
					if (sp.lookup(SP_FACTOR, te) != PS_NORMAL
					        || te->type != TT_BINOP || te->which != O_EQ)
					{
						MCperror->add
						(PE_REPEAT_NOTEQUALS, sp);
						return PS_ERROR;
					}
					if (sp.parseexp(False, True, &startcond) != PS_NORMAL)
					{
						MCperror->add
						(PE_REPEAT_BADWITHSTARTEXP, sp);
						return PS_ERROR;
					}
					if ((stat = sp.next(type)) != PS_NORMAL)
					{
						MCperror->add
						(PE_REPEAT_NOWITHTO, sp);
						return PS_ERROR;
					}
					if (sp.lookup(SP_FACTOR, te) != PS_NORMAL)
					{
						if (sp.gettoken() != "down")
						{
							MCperror->add
							(PE_REPEAT_NOWITHTO, sp);
							return PS_ERROR;
						}
						stepval = -1.0;
						if (sp.skip_token(SP_FACTOR, TT_TO) != PS_NORMAL)
						{
							MCperror->add
							(PE_REPEAT_NODOWNTO, sp);
							return PS_ERROR;
						}
					}
					else
						if (te->type != TT_TO)
						{
							MCperror->add
							(PE_REPEAT_NOTWITHTO, sp);
							return PS_ERROR;
						}
						else
							stepval = 1.0;
					if (sp.parseexp(False, True, &endcond) != PS_NORMAL)
					{
						MCperror->add
						(PE_REPEAT_BADWITHENDEXP, sp);
						return PS_ERROR;
					}
					if (sp.skip_token(SP_REPEAT, TT_UNDEFINED, RF_STEP) == PS_NORMAL)
						if (sp.parseexp(False, True, &step) != PS_NORMAL)
						{
							MCperror->add
							(PE_REPEAT_BADWITHSTARTEXP, sp);
							return PS_ERROR;
						}
					break;
				default: /* repeat form */
					fprintf(stderr, "Repeat: ERROR bad control form\n");
					return PS_ERROR;
				}
			}
			if (sp.skip_eol() != PS_NORMAL)
			{
				MCperror->add
				(PE_REPEAT_BADFORMEOL, sp);
				return PS_ERROR;
			}
			break;
		case PS_EOL:
			break;
		default: /* token type */
			MCperror->add
			(PE_REPEAT_BADFORMTYPE, sp);
			return PS_ERROR;
		}

	MCStatement *curstatement = NULL;
	MCStatement *newstatement = NULL;
	while (True)
	{
		switch (sp.next(type))
		{
		case PS_NORMAL:
			if (type == ST_DATA)
				newstatement = new MCEcho;
			else if (sp.lookup(SP_COMMAND, te) != PS_NORMAL)
			{
				if (type == ST_ID)
					newstatement = new MCComref(sp.gettoken_nameref());
				else
				{
					MCperror->add
					(PE_REPEAT_NOTCOMMAND, sp);
					return PS_ERROR;
				}
			}
			else
			{
				switch (te->type)
				{
				case TT_STATEMENT:
					newstatement = MCN_new_statement(te->which);
					break;
				case TT_END:
					if (sp.skip_token(SP_COMMAND, TT_STATEMENT, S_REPEAT) != PS_NORMAL)
					{
						MCperror->add
						(PE_REPEAT_WANTEDENDREPEAT, sp);
						return PS_ERROR;
					}
					return PS_NORMAL;
				default:
					MCperror->add
					(PE_REPEAT_BADSTATEMENT, sp);
					return PS_ERROR;
				}
			}
			break;
		case PS_EOL:
			if (sp.skip_eol() != PS_NORMAL)
			{
				MCperror->add
				(PE_REPEAT_WANTEDENDREPEAT, sp);
				return PS_ERROR;
			}
			continue;
		default:
			MCperror->add
			(PE_REPEAT_BADTOKEN, sp);
			return PS_ERROR;
		}
		if (newstatement->parse(sp) != PS_NORMAL)
		{
			MCperror->add
			(PE_REPEAT_BADCOMMAND, sp);
			delete newstatement;
			return PS_ERROR;
		}
		if (statements == NULL)
			statements = curstatement = newstatement;
		else
		{
			curstatement->setnext(newstatement);
			curstatement = newstatement;
		}
	}
	return PS_NORMAL;
}
예제 #7
0
Parse_stat MCIf::parse(MCScriptPoint &sp)
{
	initpoint(sp);
	if (sp.parseexp(False, True, &cond) != PS_NORMAL)
	{
		MCperror->add
		(PE_IF_BADCONDITION, sp);
		return PS_ERROR;
	}

	Symbol_type type;
	const LT *te;
	MCStatement *curstatement = NULL;
	MCStatement *newstatement = NULL;
	If_state state = IS_UNDEFINED;
	If_format format = IF_UNDEFINED;
	Boolean needstatement = False;

	while (True)
	{
		switch (sp.next(type))
		{
		case PS_NORMAL:
			if (type == ST_DATA || sp.lookup(SP_COMMAND, te) != PS_NORMAL)
			{
				if (needstatement)
				{
					if (type == ST_ID)
						newstatement = new MCComref(sp.gettoken_nameref());
					else if (type == ST_DATA)
						newstatement = new MCEcho;
					else
					{
						MCperror->add(PE_IF_NOTCOMMAND, sp);
						return PS_ERROR;
					}
				}
				else
				{
					if (state == IS_UNDEFINED)
					{
						MCperror->add(PE_IF_NOTHEN, sp);
						return PS_ERROR;
					}
					sp.backup();
					return PS_NORMAL;
				}
			}
			else
			{
				switch (te->type)
				{
				case TT_STATEMENT:
					if (needstatement)
						newstatement = MCN_new_statement(te->which);
					else
					{
						if (state == IS_UNDEFINED)
						{
							MCperror->add(PE_IF_NOTHEN, sp);
							return PS_ERROR;
						}
						sp.backup();
						return PS_NORMAL;
					}
					break;
				case TT_THEN:
					state = IS_THEN;
					needstatement = True;
					continue;
				case TT_ELSE:
					state = IS_ELSE;
					needstatement = True;
					continue;
				case TT_END:
					if (needstatement)
					{
						if (sp.skip_token(SP_COMMAND, TT_STATEMENT, S_IF) != PS_NORMAL)
						{
							MCperror->add(PE_IF_WANTEDENDIF, sp);
							return PS_ERROR;
						}
					}
					else
						sp.backup();
					return PS_NORMAL;
				default: /* token type */
					if (needstatement)
					{
						MCperror->add(PE_IF_WANTEDENDIF, sp);
						return PS_ERROR;
					}
					sp.backup();
					return PS_NORMAL;
				}
			}
			break;
		case PS_EOL:
			switch (format)
			{
			case IF_UNDEFINED:
				if (state == IS_THEN)
					format = IF_MULTIPLE;
				else
					format = IF_SINGLE;
				break;
			case IF_ONELINE:
				if (state == IS_ELSE)
					return PS_NORMAL;
				format = IF_SINGLE;
				needstatement = False;
				break;
			case IF_SINGLE:
				if (state == IS_ELSE)
					format = IF_ELSEMULTIPLE;
				else
					format = IF_MULTIPLE;
				break;
			case IF_MULTIPLE:
				if (state == IS_ELSE)
					format = IF_ELSEMULTIPLE;
				break;
			case IF_ELSEMULTIPLE:
				break;
			}
			if (sp.skip_eol() != PS_NORMAL)
			{
				MCperror->add(PE_IF_BADEOL, sp);
				return PS_ERROR;
			}
			continue;
		case PS_EOF:
			return PS_NORMAL;
		default:
			MCperror->add(PE_IF_BADTYPE, sp);
			return PS_ERROR;
		}
		if (newstatement->parse(sp) != PS_NORMAL)
		{
			MCperror->add(PE_IF_BADSTATEMENT, sp);
			delete newstatement;
			return PS_ERROR;
		}
		switch (state)
		{
		case IS_THEN:
			if (thenstatements == NULL)
				thenstatements = curstatement = newstatement;
			else
			{
				curstatement->setnext(newstatement);
				curstatement = newstatement;
			}
			switch (format)
			{
			case IF_UNDEFINED:
				format = IF_ONELINE;
				needstatement = False;
				break;
			case IF_SINGLE:
				needstatement = False;
				break;
			case IF_MULTIPLE:
				break;
			default: // may be unreachable
				return PS_ERROR;
			}
			break;
		case IS_ELSE:
			if (elsestatements == NULL)
				elsestatements = curstatement = newstatement;
			else
			{
				curstatement->setnext(newstatement);
				curstatement = newstatement;
			}
			if (format != IF_ELSEMULTIPLE)
				return PS_NORMAL;
			break;
		case IS_UNDEFINED:
			MCperror->add(PE_IF_NOTHEN, sp);
			delete newstatement;
			return PS_ERROR;
		}
	}
	return PS_NORMAL;
}
예제 #8
0
Exec_stat MCTry::exec(MCExecPoint &ep)
{
	Try_state state = TS_TRY;
	MCStatement *tspr = trystatements;
	Exec_stat stat;
	Exec_stat retcode = ES_NORMAL;
	MCtrylock++;
	while (tspr != NULL)
	{
		if (MCtrace || MCnbreakpoints)
		{
			MCB_trace(ep, tspr->getline(), tspr->getpos());
			if (MCexitall)
				break;
		}
		ep.setline(tspr->getline());

		stat = tspr->exec(ep);

		// MW-2011-08-17: [[ Redraw ]] Flush any screen updates.
		MCRedrawUpdateScreen();

		switch(stat)
		{
		case ES_NORMAL:
			tspr = tspr->getnext();
			if (MCexitall)
			{
				retcode = ES_NORMAL;
				tspr = NULL;
			}

			if (tspr == NULL && state != TS_FINALLY)
			{
				if (state == TS_CATCH)
					MCeerror->clear();

				tspr = finallystatements;
				state = TS_FINALLY;
			}
			break;
		case ES_ERROR:
			if ((MCtrace || MCnbreakpoints) && state != TS_TRY)
				do
				{
					MCB_error(ep, tspr->getline(), tspr->getpos(), EE_TRY_BADSTATEMENT);
				}
				while(MCtrace && (stat = tspr->exec(ep)) != ES_NORMAL);

			if (stat == ES_ERROR)
			{
				if (MCexitall)
				{
					retcode = ES_NORMAL;
					tspr = NULL;
				}
				else
					if (state != TS_TRY)
					{
						MCtrylock--;
						MCeerror->add(EE_TRY_BADSTATEMENT, line, pos);
						return ES_ERROR;
					}
					else
					{
						if (errorvar != NULL)
							errorvar->evalvar(ep)->copysvalue(MCeerror->getsvalue());

						// MW-2007-09-04: At this point we need to clear the execution error
						//   stack so that errors inside the catch statements are reported
						//   correctly.
						MCeerror->clear();
						MCperror->clear();


						tspr = catchstatements;
						state = TS_CATCH;

						// MW-2007-07-03: [[ Bug 3029 ]] - If there is no catch clause
						//   we end up skipping the finally as the loop terminates
						//   before a state transition is made, thus we force it here.
						if (catchstatements == NULL)
						{
							MCeerror -> clear();
							tspr = finallystatements;
							state = TS_FINALLY;
						}
					}
			}
			else
				tspr = tspr->getnext();
			break;
		case ES_PASS:
			if (state == TS_CATCH)
			{
				errorvar->evalvar(ep)->fetch(ep);
				MCeerror->copysvalue(ep.getsvalue(), False);
				MCeerror->add(EE_TRY_BADSTATEMENT, line, pos);
				stat = ES_ERROR;
			}
		default:
			if (state == TS_FINALLY)
			{
				MCeerror->clear();
				retcode = ES_NORMAL;
				tspr = NULL;
			}
			else
			{
				retcode = stat;
				tspr = finallystatements;
				state = TS_FINALLY;
			}
		}
	}
	if (state == TS_CATCH)
		MCeerror->clear();
	MCtrylock--;
	return retcode;
}
예제 #9
0
Parse_stat MCTry::parse(MCScriptPoint &sp)
{
	initpoint(sp);
	Try_state state = TS_TRY;
	if (sp.skip_eol() != PS_NORMAL)
	{
		MCperror->add
		(PE_TRY_WANTEDENDTRY, sp);
		return PS_ERROR;
	}
	MCStatement *curstatement = NULL;
	MCStatement *newstatement = NULL;
	while (True)
	{
		Symbol_type type;
		const LT *te;
		switch (sp.next(type))
		{
		case PS_NORMAL:
			if (type == ST_DATA)
				newstatement = new MCEcho;
			else if (sp.lookup(SP_COMMAND, te) != PS_NORMAL)
			{
				if (type == ST_ID)
					newstatement = new MCComref(sp.gettoken_nameref());
				else
				{
					MCperror->add
					(PE_TRY_NOTCOMMAND, sp);
					return PS_ERROR;
				}
			}
			else
			{
				Parse_stat stat;
				MCExpression *newfact = NULL;
				switch (te->type)
				{
				case TT_STATEMENT:
					newstatement = MCN_new_statement(te->which);
					break;
				case TT_CATCH:
					state = TS_CATCH;
					curstatement = NULL;
					stat = sp.next(type);
					if (errorvar != NULL || stat != PS_NORMAL || type != ST_ID
					        || sp.lookup(SP_FACTOR, te) != PS_NO_MATCH
					        || sp.lookupconstant(&newfact) == PS_NORMAL
					        || sp . findnewvar(sp.gettoken_nameref(), kMCEmptyName, &errorvar) != PS_NORMAL)
					{
						delete newfact;
						MCperror->add(PE_LOCAL_BADNAME, sp);
						return PS_ERROR;
					}
					continue;
					break;
				case TT_FINALLY:
					state = TS_FINALLY;
					curstatement = NULL;
					continue;
					break;
				case TT_END:
					if (sp.skip_token(SP_COMMAND, TT_STATEMENT, S_TRY) != PS_NORMAL)
					{
						MCperror->add
						(PE_TRY_WANTEDENDTRY, sp);
						return PS_ERROR;
					}
					return PS_NORMAL;
				default: /* token type */
					MCperror->add
					(PE_TRY_BADSTATEMENT, sp);
					return PS_ERROR;
				}
			}
			break;
		case PS_EOL:
			if (sp.skip_eol() != PS_NORMAL)
			{
				MCperror->add
				(PE_TRY_WANTEDENDTRY, sp);
				return PS_ERROR;
			}
			continue;
		case PS_EOF:
			return PS_NORMAL;
		default:
			MCperror->add
			(PE_TRY_BADTYPE, sp);
			return PS_ERROR;
		}
		if (newstatement->parse(sp) != PS_NORMAL)
		{
			MCperror->add
			(PE_TRY_BADSTATEMENT, sp);
			delete newstatement;
			return PS_ERROR;
		}
		if (curstatement != NULL)
		{
			curstatement->setnext(newstatement);
			curstatement = newstatement;
		}
		else
			switch (state)
			{
			case TS_TRY:
				trystatements = curstatement = newstatement;
				break;
			case TS_CATCH:
				catchstatements = curstatement = newstatement;
				break;
			case TS_FINALLY:
				finallystatements = curstatement = newstatement;
				break;
			}
	}
	return PS_NORMAL;
}
예제 #10
0
Exec_stat MCSwitch::exec(MCExecPoint &ep)
{
	MCExecPoint ep2(ep);
	Exec_stat stat;
	if (cond != NULL)
	{
		while ((stat = cond->eval(ep2)) != ES_NORMAL
		        && (MCtrace || MCnbreakpoints) && !MCtrylock && !MClockerrors)
			MCB_error(ep2, getline(), getpos(), EE_SWITCH_BADCOND);
		if (stat != ES_NORMAL)
		{
			MCeerror->add(EE_SWITCH_BADCOND, line, pos);
			return ES_ERROR;
		}
	}
	else
		ep2.setboolean(true);
	int2 match = defaultcase;
	uint2 i;
	for (i = 0 ; i < ncases ; i++)
	{
		while ((stat = cases[i]->eval(ep)) != ES_NORMAL
		        && (MCtrace || MCnbreakpoints) && !MCtrylock && !MClockerrors)
			MCB_error(ep2, getline(), getpos(), EE_SWITCH_BADCASE);
		if (stat != ES_NORMAL)
		{
			MCeerror->add
			(EE_SWITCH_BADCASE, line, pos);
			return ES_ERROR;
		}
		uint4 l1 = ep.getsvalue().getlength();
		uint4 l2 = ep2.getsvalue().getlength();
		if (l1 == l2)
		{
			const char *s1 = ep.getsvalue().getstring();
			const char *s2 = ep2.getsvalue().getstring();
			if (ep.getcasesensitive() && !strncmp(s1, s2, l1)
			        || !ep.getcasesensitive() && !MCU_strncasecmp(s1, s2, l1))
			{
				match = caseoffsets[i];
				break;
			}
		}
	}
	if (match >= 0)
	{
		MCStatement *tspr = statements;
		while (match--)
			tspr = tspr->getnext();
		Exec_stat stat;
		while (tspr != NULL)
		{
			if (MCtrace || MCnbreakpoints)
			{
				MCB_trace(ep, tspr->getline(), tspr->getpos());
				if (MCexitall)
					break;
			}
			ep.setline(tspr->getline());
			
			stat = tspr->exec(ep);
			
			// MW-2011-08-17: [[ Redraw ]] Flush any screen updates.
			MCRedrawUpdateScreen();

			switch(stat)
			{
			case ES_NORMAL:
				if (MCexitall)
					return ES_NORMAL;
				tspr = tspr->getnext();
				break;
			case ES_ERROR:
				if ((MCtrace || MCnbreakpoints) && !MCtrylock && !MClockerrors)
					do
					{
						MCB_error(ep, tspr->getline(), tspr->getpos(),
						          EE_SWITCH_BADSTATEMENT);
					}
					while (MCtrace && (stat = tspr->exec(ep)) != ES_NORMAL);
				if (stat == ES_ERROR)
					if (MCexitall)
						return ES_NORMAL;
					else
					{
						MCeerror->add
						(EE_SWITCH_BADSTATEMENT, line, pos);
						return ES_ERROR;
					}
				else
					tspr = tspr->getnext();
				break;
			case ES_EXIT_SWITCH:
				return ES_NORMAL;
			default:
				return stat;
			}
		}
	}
	return ES_NORMAL;
}
예제 #11
0
Parse_stat MCSwitch::parse(MCScriptPoint &sp)
{
	Symbol_type type;
	const LT *te;

	initpoint(sp);
	if (sp.next(type) == PS_NORMAL)
	{
		sp.backup();
		if (sp.parseexp(False, True, &cond) != PS_NORMAL)
		{
			MCperror->add
			(PE_SWITCH_BADCONDITION, sp);
			return PS_ERROR;
		}
	}
	else
		if (sp.skip_eol() != PS_NORMAL)
		{
			MCperror->add
			(PE_SWITCH_WANTEDENDSWITCH, sp);
			return PS_ERROR;
		}
	uint2 snum = 0;
	MCStatement *curstatement = NULL;
	MCStatement *newstatement = NULL;
	while (True)
	{
		switch (sp.next(type))
		{
		case PS_NORMAL:
			if (type == ST_DATA)
				newstatement = new MCEcho;
			else if (sp.lookup(SP_COMMAND, te) != PS_NORMAL)
			{
				if (type == ST_ID)
					newstatement = new MCComref(sp.gettoken_nameref());
				else
				{
					MCperror->add
					(PE_SWITCH_NOTCOMMAND, sp);
					return PS_ERROR;
				}
			}
			else
			{
				switch (te->type)
				{
				case TT_STATEMENT:
					newstatement = MCN_new_statement(te->which);
					break;
				case TT_CASE:
					MCU_realloc((char **)&cases, ncases, ncases + 1,
					            sizeof(MCExpression *));
					if (sp.parseexp(False, True, &cases[ncases]) != PS_NORMAL)
					{
						MCperror->add
						(PE_SWITCH_BADCASECONDITION, sp);
						return PS_ERROR;
					}
					MCU_realloc((char **)&caseoffsets, ncases, ncases + 1,
					            sizeof(uint2));
					caseoffsets[ncases++] = snum;
					continue;
				case TT_DEFAULT:
					defaultcase = snum;
					continue;
				case TT_END:
					if (sp.skip_token(SP_COMMAND, TT_STATEMENT, S_SWITCH) != PS_NORMAL)
					{
						MCperror->add
						(PE_SWITCH_WANTEDENDSWITCH, sp);
						return PS_ERROR;
					}
					return PS_NORMAL;
				default: /* token type */
					MCperror->add
					(PE_SWITCH_BADCASECONDITION, sp);
					return PS_ERROR;
				}
			}
			break;
		case PS_EOL:
			if (sp.skip_eol() != PS_NORMAL)
			{
				MCperror->add
				(PE_SWITCH_WANTEDENDSWITCH, sp);
				return PS_ERROR;
			}
			continue;
		case PS_EOF:
			return PS_NORMAL;
		default:
			MCperror->add
			(PE_SWITCH_BADTYPE, sp);
			return PS_ERROR;
		}
		if (newstatement->parse(sp) != PS_NORMAL)
		{
			MCperror->add
			(PE_SWITCH_BADSTATEMENT, sp);
			delete newstatement;
			return PS_ERROR;
		}
		if (statements == NULL)
			statements = curstatement = newstatement;
		else
		{
			curstatement->setnext(newstatement);
			curstatement = newstatement;
		}
		snum++;
	}
	return PS_NORMAL;
}