public DekiScriptOutputBuffer.Range Visit(DekiScriptSwitch expr, DekiScriptExpressionEvaluationState state)
        {
            DekiScriptLiteral value = state.Pop(expr.Value.VisitWith(this, state));

            DekiScriptSwitch.CaseBlock caseBlock = null;

            // have to use for instead of foreach, since a fallthrough default case needs to be able to look ahead
            for (int i = 0; i < expr.Cases.Length; i++)
            {
                DekiScriptSwitch.CaseBlock current = expr.Cases[i];

                // check for default case
                foreach (DekiScriptExpression condition in current.Conditions)
                {
                    if (condition == null)
                    {
                        // check if this is the first default we've found
                        if (caseBlock == null)
                        {
                            caseBlock = current;
                        }

                        // continue in case loop, since default only gets executed if there is no match
                        continue;
                    }

                    // evaluate test
                    DekiScriptExpression test      = DekiScriptExpression.BinaryOp(current.Location, DekiScriptBinary.Op.Equal, value, condition);
                    DekiScriptLiteral    caseMatch = state.Pop(test.VisitWith(this, state));

                    // evaluate body on success
                    if (!caseMatch.IsNilFalseZero)
                    {
                        // found a matching cast statement
                        caseBlock = current;
                        break;
                    }
                }
            }

            // haven't found a match yet, so if we have a default, return it
            if (caseBlock != null)
            {
                int marker = state.Buffer.Marker;
                try {
                    return(caseBlock.Body.VisitWith(this, state));
                } catch (DekiScriptBreakException) {
                    // nothing to do
                }
                return(state.Buffer.Since(marker));
            }
            return(DekiScriptOutputBuffer.Range.Empty);
        }
        public DekiScriptLiteral Visit(DekiScriptSwitch expr, DekiScriptEnv env)
        {
            DekiScriptLiteral   value       = expr.Value.VisitWith(this, env);
            DekiScriptCaseBlock defaultCase = null;

            // have to use for instead of foreach, since a fallthrough default case needs to be able to look ahead
            for (int i = 0; i < expr.Cases.Length; i++)
            {
                DekiScriptCaseBlock c = expr.Cases[i];

                // check for default case
                DekiScriptEnv locals = env.NewLocalScope();
                foreach (DekiScriptExpression condition in c.Conditions)
                {
                    if (condition == null)
                    {
                        // check if this is the first default we've found
                        if (defaultCase == null)
                        {
                            defaultCase = c;
                        }

                        // continue in case loop, since default only gets executed if there is no match
                        continue;
                    }

                    // evaluate test
                    DekiScriptBinary  test      = new DekiScriptBinary(0, 0, DekiScriptBinary.Op.Equal, value, condition);
                    DekiScriptLiteral caseMatch = test.VisitWith(this, locals);

                    // evaluate body on success
                    if (!caseMatch.IsNilFalseZero)
                    {
                        return(EvalBody(locals, c.Body));
                    }
                }
            }

            // haven't found a match yet, so if we have a default, return it
            if (defaultCase != null)
            {
                return(EvalBody(env.NewLocalScope(), defaultCase.Body));
            }
            return(DekiScriptNil.Value);
        }
        public DekiScriptExpression Visit(DekiScriptSwitch expr, DekiScriptExpressionEvaluationState state)
        {
            DekiScriptExpression value = expr.Value.VisitWith(this, state);
            List <DekiScriptSwitch.CaseBlock> cases = new List <DekiScriptSwitch.CaseBlock>();
            int defaultCaseIndex = -1;

            for (int i = 0; i < expr.Cases.Length; ++i)
            {
                bool   isDefaultCase;
                object outcome = Optimize(expr.Cases[i], value, state, out isDefaultCase);
                if (outcome is DekiScriptExpression)
                {
                    return((DekiScriptExpression)outcome);
                }
                if (outcome != null)
                {
                    cases.Add((DekiScriptSwitch.CaseBlock)outcome);
                }

                // check if case block contains a default case statement
                if (isDefaultCase && (defaultCaseIndex == -1))
                {
                    defaultCaseIndex = cases.Count - 1;
                }
            }

            // check if all matches failed, but we found a default branch
            if ((cases.Count == 1) && (defaultCaseIndex == 0) && (cases[0].Conditions.Length == 1))
            {
                return(cases[0].Body);
            }
            if (cases.Count > 0)
            {
                return(DekiScriptExpression.SwitchStatement(expr.Location, value, cases.ToArray()));
            }
            return(DekiScriptNil.Value);
        }
示例#4
0
	void CaseStatement(out DekiScriptSwitch.CaseBlock block) {
		List<DekiScriptExpression> conditions = new List<DekiScriptExpression>();
		DekiScriptExpression caseexpr = null;
		DekiScriptExpression expr = DekiScriptNil.Value;
		Location location = t.Location;
		
		if (la.kind == 30) {
			Get();
			Expression(out caseexpr);
			Expect(31);
			conditions.Add(caseexpr); 
		} else if (la.kind == 32) {
			Get();
			Expect(31);
			conditions.Add(null); 
		} else SynErr(81);
		while (la.kind == 30 || la.kind == 32) {
			if (la.kind == 30) {
				Get();
				Expression(out caseexpr);
				Expect(31);
				conditions.Add(caseexpr); 
			} else {
				Get();
				Expect(31);
				conditions.Add(null); 
			}
		}
		if (StartOf(1)) {
			if (la.kind == 9) {
				Get();
				if (StartOf(1)) {
					Statements(out expr);
				}
				Expect(10);
			} else {
				Statements(out expr);
			}
		}
		block = DekiScriptExpression.SwitchCaseBlock(location, conditions, expr); 
	}