Example #1
0
 // SwitchCase
 private void DefaultWalk(SwitchCase node)
 {
     if (Walk(node)) {
         WalkNode(node.Body);
     }
     PostWalk(node);
 }
Example #2
0
        // SwitchStatement
        protected internal override bool Walk(SwitchStatement node)
        {
            // The expression is evaluated always.
            // Then each case clause expression is evaluated until match is found.
            // Therefore, the effects of the case clause expressions accumulate.
            // Default clause is evaluated last (so all case clause expressions must
            // accumulate first)
            WalkNode(node.TestValue);

            // Flow all the cases, they all start with the same initial state
            int count;
            IList <SwitchCase> cases = node.Cases;

            if (cases != null && (count = cases.Count) > 0)
            {
                SwitchCase @default = null;
                // Save the initial state
                BitArray entry = _bits;
                // The state to progressively accumualte effects of the case clause expressions
                BitArray values = new BitArray(entry);
                // State to flow the case clause bodies.
                BitArray caseFlow = new BitArray(_bits.Length);
                // The state to accumulate results into
                BitArray result = new BitArray(_bits.Length, true);

                PushStatement(result);

                for (int i = 0; i < count; i++)
                {
                    if (cases[i].IsDefault)
                    {
                        Debug.Assert(@default == null);

                        // postpone the default case
                        @default = cases[i];
                        continue;
                    }

                    // Set the state for the walking of the body
                    caseFlow.SetAll(false);
                    caseFlow.Or(values);

                    // Walk the body
                    _bits = caseFlow;
                    WalkNode(cases[i].Body);

                    // Accumulate the result into the overall case statement result.
                    result.And(caseFlow);
                }

                // Walk the default at the end.
                if (@default != null)
                {
                    // Initialize
                    caseFlow.SetAll(false);
                    caseFlow.Or(values);

                    // Walk the default body
                    _bits = caseFlow;
                    WalkNode(@default.Body);

                    // Accumulate.
                    result.And(caseFlow);

                    // If there's a default clause, exactly one case got executed.
                    // The final state is 'and' across all cases, stored in 'result'
                    entry.SetAll(false);
                    entry.Or(result);
                }
                else
                {
                    // In the absence of default clause, we may have executed case,
                    // but didn't have to, so the result is an 'and' between the cases
                    // and the initial state.
                    entry.And(result);
                }

                PopStatement();

                // Restore the original state.
                _bits = entry;
            }

            return(false);
        }
Example #3
0
        private static bool UniqueCaseValues(SwitchCase[] cases, int min, int max)
        {
            int length = cases.Length;

            // If we have small number of cases, use straightforward N2 algorithm
            // which doesn't allocate memory
            if (length < N2Threshold) {
                for (int i = 0; i < length; i++) {
                    SwitchCase sci = cases[i];
                    if (sci.IsDefault) {
                        continue;
                    }
                    for (int j = i + 1; j < length; j++) {
                        SwitchCase scj = cases[j];
                        if (scj.IsDefault) {
                            continue;
                        }

                        if (sci.Value == scj.Value) {
                            // Duplicate value found
                            return false;
                        }
                    }
                }

                return true;
            }

            // We have at least N2Threshold items so the min and max values
            // are set to actual values and not the Int32.MaxValue and Int32.MaxValue
            Debug.Assert(min <= max);
            long delta = (long)max - (long)min;
            if (delta < BitArrayThreshold) {
                BitArray ba = new BitArray((int)delta + 1, false);

                for (int i = 0; i < length; i++) {
                    SwitchCase sc = cases[i];
                    if (sc.IsDefault) {
                        continue;
                    }
                    // normalize to 0 .. (max - min)
                    int val = sc.Value - min;
                    if (ba.Get(val)) {
                        // Duplicate value found
                        return false;
                    }
                    ba.Set(val, true);
                }

                return true;
            }

            // Too many values that are too spread around. Use dictionary
            // Using Dictionary<int, object> as it is used elsewhere to
            // minimize the impact of generic instantiation
            Dictionary<int, object> dict = new Dictionary<int, object>(length);
            for (int i = 0; i < length; i++) {
                SwitchCase sc = cases[i];
                if (sc.IsDefault) {
                    continue;
                }
                int val = sc.Value;
                if (dict.ContainsKey(val)) {
                    // Duplicate value found
                    return false;
                }
                dict[val] = null;
            }

            return true;
        }
        internal Expression Reduce()
        {
            // Visit body
            Expression body = Visit(_generator.Body);

            Debug.Assert(_returnLabels.Count == 1);

            // Add the switch statement to the body
            int count = _yields.Count;
            var cases = new SwitchCase[count + 1];

            for (int i = 0; i < count; i++)
            {
                cases[i] = Expression.SwitchCase(Expression.Goto(_yields[i].Label), AstUtils.Constant(_yields[i].State));
            }
            cases[count] = Expression.SwitchCase(Expression.Goto(_returnLabels.Peek()), AstUtils.Constant(Finished));

            Type generatorNextOfT = typeof(GeneratorNext <>).MakeGenericType(_generator.Target.Type);

            // Create the lambda for the GeneratorNext<T>, hoisting variables
            // into a scope outside the lambda
            var allVars = new List <ParameterExpression>(_vars);

            allVars.AddRange(_temps);

            // Collect temps that don't have to be closed over
            var innerTemps = new ReadOnlyCollectionBuilder <ParameterExpression>(1 + (_labelTemps?.Count ?? 0));

            innerTemps.Add(_gotoRouter);
            if (_labelTemps != null)
            {
                foreach (LabelInfo info in _labelTemps.Values)
                {
                    innerTemps.Add(info.Temp);
                }
            }

            body = Expression.Block(
                allVars,
                Expression.Lambda(
                    generatorNextOfT,
                    Expression.Block(
                        innerTemps,
                        Expression.Switch(Expression.Assign(_gotoRouter, _state), cases),
                        body,
                        Expression.Assign(_state, AstUtils.Constant(Finished)),
                        Expression.Label(_returnLabels.Peek())
                        ),
                    _generator.Name,
                    new ParameterExpression[] { _state, _current }
                    )
                );

            // Enumerable factory takes Func<GeneratorNext<T>> instead of GeneratorNext<T>
            if (_generator.IsEnumerable)
            {
                body = Expression.Lambda(body);
            }

            // We can't create a ConstantExpression of _debugCookies array here because we walk the tree
            // after constants have already been rewritten.  Instead we create a NewArrayExpression node
            // which initializes the array with contents from _debugCookies
            Expression debugCookiesArray = null;

            if (_debugCookies != null)
            {
                Expression[] debugCookies = new Expression[_debugCookies.Count];
                for (int i = 0; i < _debugCookies.Count; i++)
                {
                    debugCookies[i] = AstUtils.Constant(_debugCookies[i]);
                }

                debugCookiesArray = Expression.NewArrayInit(
                    typeof(int),
                    debugCookies);
            }

            // Generate a call to ScriptingRuntimeHelpers.MakeGenerator<T>(args)
            return(Expression.Call(
                       typeof(ScriptingRuntimeHelpers),
                       "MakeGenerator",
                       new[] { _generator.Target.Type },
                       (debugCookiesArray != null)
                    ? new[] { body, debugCookiesArray }
                    : new[] { body }
                       ));
        }