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)); }