Exemplo n.º 1
0
        internal override IList <Executable> Resolve(ParserContext parser)
        {
            TODO.MakeSwitchStatementFallthroughsErrors();
            if (this.explicitMax != null)
            {
                throw new ParserException(this.explicitMaxToken, "Unexpected token: '{'");
            }

            bool useExplicitMax = this.explicitMax != null;
            int  explicitMax    = 0;

            if (useExplicitMax)
            {
                this.explicitMax = this.explicitMax.Resolve(parser);
                if (!(this.explicitMax is IntegerConstant))
                {
                    throw new ParserException(this.explicitMax.FirstToken, "Explicit max must be an integer.");
                }
                explicitMax = ((IntegerConstant)this.explicitMax).Value;
            }

            this.Condition = this.Condition.Resolve(parser);
            int integers    = 0;
            int strings     = 0;
            int largestSpan = 0;

            HashSet <int>    intCases    = new HashSet <int>();
            HashSet <string> stringCases = new HashSet <string>();

            foreach (Chunk chunk in this.chunks)
            {
                if (chunk.Cases.Length > largestSpan)
                {
                    largestSpan = chunk.Cases.Length;
                }

                for (int i = 0; i < chunk.Cases.Length; ++i)
                {
                    if (chunk.Cases[i] != null)
                    {
                        Expression caseExpr = chunk.Cases[i].Resolve(parser);
                        chunk.Cases[i] = caseExpr;

                        if (caseExpr is IntegerConstant)
                        {
                            int intValue = ((IntegerConstant)caseExpr).Value;
                            if (intCases.Contains(intValue))
                            {
                                throw new ParserException(caseExpr.FirstToken, "Duplicate case value in same switch: " + intValue);
                            }
                            intCases.Add(intValue);
                        }
                        else if (caseExpr is StringConstant)
                        {
                            string strValue = ((StringConstant)caseExpr).Value;
                            if (stringCases.Contains(strValue))
                            {
                                throw new ParserException(caseExpr.FirstToken, "Duplicate case value in same switch: " + Util.ConvertStringValueToCode(strValue));
                            }
                            stringCases.Add(strValue);
                        }

                        if (chunk.Cases[i] is IntegerConstant)
                        {
                            integers++;
                        }
                        else if (chunk.Cases[i] is StringConstant)
                        {
                            strings++;
                        }
                        else
                        {
                            if (chunk.Cases[i] is DotStep)
                            {
                                // Since most enums are in all caps, offer a more helpful error message when there's a dot followed by all caps.
                                string field = ((DotStep)chunk.Cases[i]).StepToken.Value;
                                if (field.ToUpperInvariant() == field)
                                {
                                    throw new ParserException(chunk.Cases[i].FirstToken,
                                                              "Only strings, integers, and enums can be used in a switch statement. It looks like this is probably supposed to be an enum. Make sure that it is spelled correctly.");
                                }
                            }
                            throw new ParserException(chunk.Cases[i].FirstToken, "Only strings, integers, and enums can be used in a switch statement.");
                        }
                    }
                }

                chunk.Code = Resolve(parser, chunk.Code).ToArray();
            }

            if (integers != 0 && strings != 0)
            {
                throw new ParserException(this.FirstToken, "Cannot mix string and integer cases in a single switch statement.");
            }

            if (integers == 0 && strings == 0)
            {
                if (this.chunks.Length == 0)
                {
                    throw new ParserException(this.FirstToken, "Cannot have a blank switch statement.");
                }
                if (this.chunks.Length > 1)
                {
                    throw new Exception("only had default but had multiple chunks. This should have been prevented at parse-time.");
                }
                return(this.chunks[0].Code);
            }

            Chunk      lastChunk = this.chunks[this.chunks.Length - 1];
            Expression lastCase  = lastChunk.Cases[lastChunk.Cases.Length - 1];

            this.ContainsDefault = lastCase == null;
            this.UsesStrings     = strings != 0;
            this.IsSafe          = !this.ContainsDefault;
            this.IsContinuous    = integers != 0 && largestSpan == 1 && this.IsSafe && this.DetermineContinuousness();

            return(this.CompilationResolution(parser));
        }