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); }
private object Optimize(DekiScriptCaseBlock expr, DekiScriptExpression value, DekiScriptEvalMode mode, DekiScriptEnv env, out bool isDefaultCase) { List <DekiScriptExpression> conditions = new List <DekiScriptExpression>(); isDefaultCase = false; for (int i = 0; i < expr.Conditions.Length; i++) { if (expr.Conditions[i] != null) { DekiScriptExpression condition = expr.Conditions[i].VisitWith(this, new DekiScriptOptimizerState(mode, env)); // check if condition always succeeds or always fails if ((value is DekiScriptLiteral) && (condition is DekiScriptLiteral)) { DekiScriptBinary test = new DekiScriptBinary(0, 0, DekiScriptBinary.Op.Equal, value, condition); if (!test.Evaluate(env).IsNilFalseZero) { // NOTE (steveb): we wrap the outcome into a sequence to ensure proper handling of break/continue statements // condition succeeded, return it return(DekiScriptSequence.New(DekiScriptSequence.ScopeKind.ScopeCatchBreakAndContinue, expr.Body.VisitWith(this, new DekiScriptOptimizerState(mode, env)))); } } else { conditions.Add(condition); } } else { isDefaultCase = true; conditions.Add(null); } } // check if any conditions were true or unknown if (conditions.Count == 0) { return(null); } DekiScriptExpression body = expr.Body.VisitWith(this, new DekiScriptOptimizerState(mode, env)); return(new DekiScriptCaseBlock(conditions.ToArray(), body, expr.IsBlock)); }