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); }
private object Optimize(DekiScriptSwitch.CaseBlock expr, DekiScriptExpression value, DekiScriptExpressionEvaluationState state, 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, state); // check if condition always succeeds or always fails if ((value is DekiScriptLiteral) && (condition is DekiScriptLiteral)) { var test = DekiScriptExpression.BinaryOp(Location.None, DekiScriptBinary.Op.Equal, value, condition); var result = state.Pop(test.VisitWith(DekiScriptExpressionEvaluation.Instance, state)); if (!result.IsNilFalseZero) { // NOTE (steveb): we wrap the outcome into a sequence to ensure proper handling of break/continue statements // condition succeeded, return it return(DekiScriptExpression.Block(expr.Location, new[] { expr.Body.VisitWith(this, state) })); } } 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, state); return(new DekiScriptSwitch.CaseBlock(expr.Location, conditions.ToArray(), body)); }