public override BoundNode VisitSwitchStatement(BoundSwitchStatement node) { var newInnerLocals = RewriteLocals(node.InnerLocals); BoundExpression boundExpression = (BoundExpression)this.Visit(node.BoundExpression); ImmutableArray <BoundSwitchSection> switchSections = (ImmutableArray <BoundSwitchSection>) this.VisitList(node.SwitchSections); return(node.Update(boundExpression, node.ConstantTargetOpt, newInnerLocals, switchSections, node.BreakLabel, node.StringEquality)); }
protected virtual void VisitSwitchStatement(BoundSwitchStatement node) { VisitExpression(node.Expression); foreach (var section in node.Sections) { VisitSwitchSection(section); } }
public override BoundNode VisitSwitchStatement(BoundSwitchStatement node) { var oldScope = _currentScope; _currentScope = CreateOrReuseScope(node, node.InnerLocals); var result = base.VisitSwitchStatement(node); _currentScope = oldScope; return(result); }
public override object VisitSwitchStatement(BoundSwitchStatement node, object arg) { VisitExpression(node.BoundExpression); // TODO: switch cases missing from bound switch node // TODO: make sure to take into account the possibility of constant switch expression // TODO: take into account the possibility of no switch blocks // TODO: give an error when the end of a switch block is reachable (falls through) Unimplemented(node, "switch statement"); return(null); }
internal void Parse(BoundSwitchStatement boundSwitchStatement) { if (boundSwitchStatement == null) { throw new ArgumentNullException(); } var boundCall = boundSwitchStatement.Expression as BoundCall; if (boundCall != null && boundCall.ReceiverOpt != null) { this.isNullableType = boundCall.ReceiverOpt.Type.IsNullableType(); } /* * if (boundSwitchStatement.OuterLocals != null) * { * AddLocals(boundSwitchStatement.OuterLocals, this.statements); * } */ if (boundSwitchStatement.InnerLocals != null) { AddLocals(boundSwitchStatement.InnerLocals, this.statements); } this.expression = Deserialize(boundSwitchStatement.Expression) as Expression; foreach (var boundSwitchSection in boundSwitchStatement.SwitchSections) { var switchSection = new SwitchSection(); switchSection.SwitchType = this.expression.Type; switchSection.Parse(boundSwitchSection); switchSection.IsNullableType = this.isNullableType; this.switchCases.Add(switchSection); } this.stringEquality = boundSwitchStatement.StringEquality; // disable all 'auto' variables this.Visit( (e) => { var assignmentOperator = e as AssignmentOperator; if (assignmentOperator != null) { var local = assignmentOperator.Left as Local; if (local != null && boundSwitchStatement.InnerLocals.Any(ol => ol.Name == local.Name)) { assignmentOperator.TypeDeclaration = false; } } }); }
public override BoundNode VisitSwitchStatement(BoundSwitchStatement node) { Debug.Assert(EvalStackIsEmpty()); DeclareLocals(node.InnerLocals, 0); // switch needs a byval local or a parameter as a key. // if this is already a fitting local, let's keep it that way BoundExpression boundExpression = node.BoundExpression; if (boundExpression.Kind == BoundKind.Local) { var localSym = ((BoundLocal)boundExpression).LocalSymbol; if (localSym.RefKind == RefKind.None) { ShouldNotSchedule(localSym); } } boundExpression = (BoundExpression)this.Visit(boundExpression); // expression value is consumed by the switch PopEvalStack(); // implicit control flow EnsureOnlyEvalStack(); // switch sections ImmutableArray<BoundSwitchSection> switchSections = this.VisitList(node.SwitchSections); // break label var breakLabel = node.BreakLabel; if (breakLabel != null) { this.RecordLabel(breakLabel); } var result = node.Update(boundExpression, node.ConstantTargetOpt, node.InnerLocals, switchSections, breakLabel, node.StringEquality); // implicit control flow EnsureOnlyEvalStack(); return result; }
public override BoundNode VisitSwitchStatement(BoundSwitchStatement node) { var breakLabelClone = GetLabelClone(node.BreakLabel); var preambleOpt = (BoundStatement)this.Visit(node.LoweredPreambleOpt); // expressions do not contain labels or branches BoundExpression boundExpression = node.Expression; ImmutableArray<BoundSwitchSection> switchSections = (ImmutableArray<BoundSwitchSection>)this.VisitList(node.SwitchSections); return node.Update(preambleOpt, boundExpression, node.ConstantTargetOpt, node.InnerLocals, node.InnerLocalFunctions, switchSections, breakLabelClone, node.StringEquality); }
private void EmitStringSwitchJumpTable( BoundSwitchStatement switchStatement, KeyValuePair<ConstantValue, object>[] switchCaseLabels, LabelSymbol fallThroughLabel, LocalOrParameter key, SyntaxNode syntaxNode) { LocalDefinition keyHash = null; // Condition is necessary, but not sufficient (e.g. might be missing a special or well-known member). if (SwitchStringJumpTableEmitter.ShouldGenerateHashTableSwitch(_module, switchCaseLabels.Length)) { Debug.Assert(_module.SupportsPrivateImplClass); var privateImplClass = _module.GetPrivateImplClass(syntaxNode, _diagnostics); Cci.IReference stringHashMethodRef = privateImplClass.GetMethod(PrivateImplementationDetails.SynthesizedStringHashFunctionName); // Heuristics and well-known member availability determine the existence // of this helper. Rather than reproduce that (language-specific) logic here, // we simply check for the information we really want - whether the helper is // available. if (stringHashMethodRef != null) { // static uint ComputeStringHash(string s) // pop 1 (s) // push 1 (uint return value) // stackAdjustment = (pushCount - popCount) = 0 _builder.EmitLoad(key); _builder.EmitOpCode(ILOpCode.Call, stackAdjustment: 0); _builder.EmitToken(stringHashMethodRef, syntaxNode, _diagnostics); var UInt32Type = _module.Compilation.GetSpecialType(SpecialType.System_UInt32); keyHash = AllocateTemp(UInt32Type, syntaxNode); _builder.EmitLocalStore(keyHash); } } Cci.IReference stringEqualityMethodRef = _module.Translate(switchStatement.StringEquality, syntaxNode, _diagnostics); Cci.IMethodReference stringLengthRef = null; var stringLengthMethod = _module.Compilation.GetSpecialTypeMember(SpecialMember.System_String__Length) as MethodSymbol; if (stringLengthMethod != null && !stringLengthMethod.HasUseSiteError) { stringLengthRef = _module.Translate(stringLengthMethod, syntaxNode, _diagnostics); } SwitchStringJumpTableEmitter.EmitStringCompareAndBranch emitStringCondBranchDelegate = (keyArg, stringConstant, targetLabel) => { if (stringConstant == ConstantValue.Null) { // if (key == null) // goto targetLabel _builder.EmitLoad(keyArg); _builder.EmitBranch(ILOpCode.Brfalse, targetLabel, ILOpCode.Brtrue); } else if (stringConstant.StringValue.Length == 0 && stringLengthRef != null) { // if (key != null && key.Length == 0) // goto targetLabel object skipToNext = new object(); _builder.EmitLoad(keyArg); _builder.EmitBranch(ILOpCode.Brfalse, skipToNext, ILOpCode.Brtrue); _builder.EmitLoad(keyArg); // Stack: key --> length _builder.EmitOpCode(ILOpCode.Call, 0); var diag = DiagnosticBag.GetInstance(); _builder.EmitToken(stringLengthRef, null, diag); Debug.Assert(diag.IsEmptyWithoutResolution); diag.Free(); _builder.EmitBranch(ILOpCode.Brfalse, targetLabel, ILOpCode.Brtrue); _builder.MarkLabel(skipToNext); } else { this.EmitStringCompareAndBranch(key, syntaxNode, stringConstant, targetLabel, stringEqualityMethodRef); } }; _builder.EmitStringSwitchJumpTable( caseLabels: switchCaseLabels, fallThroughLabel: fallThroughLabel, key: key, keyHash: keyHash, emitStringCondBranchDelegate: emitStringCondBranchDelegate, computeStringHashcodeDelegate: SynthesizedStringSwitchHashMethod.ComputeStringHash); if (keyHash != null) { FreeTemp(keyHash); } }
private void EmitSwitchHeader( BoundSwitchStatement switchStatement, BoundExpression expression, KeyValuePair<ConstantValue, object>[] switchCaseLabels, LabelSymbol fallThroughLabel) { Debug.Assert(expression.ConstantValue == null); Debug.Assert((object)expression.Type != null && expression.Type.IsValidV6SwitchGoverningType()); Debug.Assert(switchCaseLabels.Length > 0); Debug.Assert(switchCaseLabels != null); LocalDefinition temp = null; LocalOrParameter key; BoundSequence sequence = null; if (expression.Kind == BoundKind.Sequence) { sequence = (BoundSequence)expression; DefineLocals(sequence); EmitSideEffects(sequence); expression = sequence.Value; } if (expression.Kind == BoundKind.SequencePointExpression) { var sequencePointExpression = (BoundSequencePointExpression)expression; EmitSequencePoint(sequencePointExpression); expression = sequencePointExpression.Expression; } switch (expression.Kind) { case BoundKind.Local: var local = ((BoundLocal)expression).LocalSymbol; if (local.RefKind == RefKind.None && !IsStackLocal(local)) { key = this.GetLocal(local); break; } goto default; case BoundKind.Parameter: var parameter = (BoundParameter)expression; if (parameter.ParameterSymbol.RefKind == RefKind.None) { key = ParameterSlot(parameter); break; } goto default; default: EmitExpression(expression, true); temp = AllocateTemp(expression.Type, expression.Syntax); _builder.EmitLocalStore(temp); key = temp; break; } // Emit switch jump table if (expression.Type.SpecialType != SpecialType.System_String) { _builder.EmitIntegerSwitchJumpTable(switchCaseLabels, fallThroughLabel, key, expression.Type.EnumUnderlyingType().PrimitiveTypeCode); } else { this.EmitStringSwitchJumpTable(switchStatement, switchCaseLabels, fallThroughLabel, key, expression.Syntax); } if (temp != null) { FreeTemp(temp); } if (sequence != null) { FreeLocals(sequence, doNotRelease: null); } }
private void EmitSwitchStatement(BoundSwitchStatement switchStatement) { var preambleOpt = switchStatement.LoweredPreambleOpt; if (preambleOpt != null) { EmitStatement(preambleOpt); } // Switch expression must have a valid switch governing type Debug.Assert((object)switchStatement.Expression.Type != null); Debug.Assert(switchStatement.Expression.Type.IsValidV6SwitchGoverningType()); // We must have rewritten nullable switch expression into non-nullable constructs. Debug.Assert(!switchStatement.Expression.Type.IsNullableType()); BoundExpression expression = switchStatement.Expression; ImmutableArray<BoundSwitchSection> switchSections = switchStatement.SwitchSections; GeneratedLabelSymbol breakLabel = switchStatement.BreakLabel; LabelSymbol constantTargetOpt = switchStatement.ConstantTargetOpt; if ((object)constantTargetOpt != null) { EmitConstantSwitchHeader(expression, constantTargetOpt); } else { // ConstantTargetOpt should be set to breakLabel for empty switch statement Debug.Assert(switchStatement.SwitchSections.Any()); // Get switch case labels (indexed by their constant value) for emitting switch header and jump table LabelSymbol fallThroughLabel = breakLabel; KeyValuePair<ConstantValue, object>[] switchCaseLabels = GetSwitchCaseLabels(switchSections, ref fallThroughLabel); // CONSIDER: EmitSwitchHeader may modify the switchCaseLabels array by sorting it. // CONSIDER: Currently, only purpose of creating this switchCaseLabels array is for Emitting the switch header. // CONSIDER: If this requirement changes, we may want to pass in ArrayBuilder<KeyValuePair<ConstantValue, object>> instead. if (switchCaseLabels.Length == 0) { // no case labels EmitExpression(expression, used: false); _builder.EmitBranch(ILOpCode.Br, fallThroughLabel); } else { EmitSwitchHeader(switchStatement, expression, switchCaseLabels, fallThroughLabel); } } EmitSwitchBody(switchStatement.InnerLocals, switchSections, breakLabel, switchStatement.Syntax); }
public override BoundNode VisitSwitchStatement(BoundSwitchStatement node) { var breakLabelClone = GetLabelClone(node.BreakLabel); // expressions do not contain labels or branches BoundExpression boundExpression = node.BoundExpression; ImmutableArray<BoundSwitchSection> switchSections = (ImmutableArray<BoundSwitchSection>)this.VisitList(node.SwitchSections); Debug.Assert(node.OuterLocals.IsEmpty); return node.Update(node.OuterLocals, boundExpression, node.ConstantTargetOpt, node.InnerLocals, switchSections, breakLabelClone, node.StringEquality); }
private void EmitSwitchHeader( BoundSwitchStatement switchStatement, BoundExpression expression, KeyValuePair<ConstantValue, object>[] switchCaseLabels, LabelSymbol fallThroughLabel) { Debug.Assert(expression.ConstantValue == null); Debug.Assert((object)expression.Type != null && expression.Type.IsValidSwitchGoverningType()); Debug.Assert(switchCaseLabels.Length > 0); Debug.Assert(switchCaseLabels != null); var exprType = expression.Type; LocalDefinition temp = null; // Emit switch jump table if (expression.Type.SpecialType != SpecialType.System_String) { if (expression.Kind == BoundKind.Local && ((BoundLocal)expression).LocalSymbol.RefKind == RefKind.None) { builder.EmitIntegerSwitchJumpTable(switchCaseLabels, fallThroughLabel, this.GetLocal((BoundLocal)expression), exprType.EnumUnderlyingType().PrimitiveTypeCode); } else if (expression.Kind == BoundKind.Parameter && ((BoundParameter)expression).ParameterSymbol.RefKind == RefKind.None) { builder.EmitIntegerSwitchJumpTable(switchCaseLabels, fallThroughLabel, ParameterSlot((BoundParameter)expression), exprType.EnumUnderlyingType().PrimitiveTypeCode); } else { EmitExpression(expression, true); temp = AllocateTemp(exprType, expression.Syntax); builder.EmitLocalStore(temp); builder.EmitIntegerSwitchJumpTable(switchCaseLabels, fallThroughLabel, temp, exprType.EnumUnderlyingType().PrimitiveTypeCode); } } else { if (expression.Kind == BoundKind.Local && ((BoundLocal)expression).LocalSymbol.RefKind == RefKind.None) { this.EmitStringSwitchJumpTable(switchStatement, switchCaseLabels, fallThroughLabel, this.GetLocal((BoundLocal)expression), expression.Syntax); } else { EmitExpression(expression, true); temp = AllocateTemp(exprType, expression.Syntax); builder.EmitLocalStore(temp); this.EmitStringSwitchJumpTable(switchStatement, switchCaseLabels, fallThroughLabel, temp, expression.Syntax); } } if (temp != null) { FreeTemp(temp); } }
public override BoundNode VisitSwitchStatement(BoundSwitchStatement node) { var preambleOpt = (BoundStatement)this.Visit(node.LoweredPreambleOpt); var newInnerLocals = RewriteLocals(node.InnerLocals); BoundExpression boundExpression = (BoundExpression)this.Visit(node.Expression); ImmutableArray<BoundSwitchSection> switchSections = (ImmutableArray<BoundSwitchSection>)this.VisitList(node.SwitchSections); return node.Update(preambleOpt, boundExpression, node.ConstantTargetOpt, newInnerLocals, node.InnerLocalFunctions, switchSections, node.BreakLabel, node.StringEquality); }
public override BoundNode VisitSwitchStatement(BoundSwitchStatement node) { Debug.Assert(node.OuterLocals.IsEmpty); Debug.Assert(this.evalStack == 0); DeclareLocals(node.InnerLocals, 0); var origStack = this.evalStack; // switch expects that key local stays local EnsureOnlyEvalStack(); BoundExpression boundExpression = (BoundExpression)this.Visit(node.BoundExpression); // expression value is consumed by the switch this.evalStack = origStack; // implicit control flow EnsureOnlyEvalStack(); // switch sections ImmutableArray<BoundSwitchSection> switchSections = this.VisitList(node.SwitchSections); // break label var breakLabel = node.BreakLabel; if (breakLabel != null) { this.RecordLabel(breakLabel); } var result = node.Update(node.OuterLocals, boundExpression, node.ConstantTargetOpt, node.InnerLocals, switchSections, breakLabel, node.StringEquality); // implicit control flow EnsureOnlyEvalStack(); return result; }
public override BoundNode VisitSwitchStatement(BoundSwitchStatement node) { Debug.Assert(this.evalStack == 0); DeclareLocals(node.LocalsOpt, 0); var origStack = this.evalStack; // switch expects that key local stays local EnsureOnlyEvalStack(); BoundExpression boundExpression = (BoundExpression)this.Visit(node.BoundExpression); // expression value is consumed by the switch this.evalStack = origStack; // implicit control flow EnsureOnlyEvalStack(); ImmutableArray<BoundSwitchSection> switchSections = this.VisitList(node.SwitchSections); var result = node.Update(boundExpression, node.ConstantTargetOpt, node.LocalsOpt, switchSections, node.BreakLabel, node.StringEquality); // implicit control flow EnsureOnlyEvalStack(); return result; }