public override object VisitBinaryExpression(BoundBinaryEx x) { return(x.Update( (BoundExpression)Accept(x.Left), (BoundExpression)Accept(x.Right), x.Operation)); }
public override void VisitBinaryExpression(BoundBinaryEx x) { base.VisitBinaryExpression(x); // switch (x.Operation) { case Operations.Div: if (x.Right.IsConstant()) { if (x.Right.ConstantValue.IsZero()) { Add(x.Right.PhpSyntax.Span, Devsense.PHP.Errors.Warnings.DivisionByZero); } } break; } }
public override object VisitBinaryExpression(BoundBinaryEx x) { // AND, OR: if (x.Operation == Ast.Operations.And || x.Operation == Ast.Operations.Or) { if (x.Left.ConstantValue.TryConvertToBool(out var bleft)) { if (x.Operation == Ast.Operations.And) { TransformationCount++; // TRUE && Right => Right // FALSE && Right => FALSE return(bleft ? x.Right : x.Left); } else if (x.Operation == Ast.Operations.Or) { TransformationCount++; // TRUE || Right => TRUE // FALSE || Right => Right return(bleft ? x.Left : x.Right); } } if (x.Right.ConstantValue.TryConvertToBool(out var bright)) { if (x.Operation == Ast.Operations.And && bright == true) { TransformationCount++; return(x.Left); // Left && TRUE => Left } else if (x.Operation == Ast.Operations.Or && bright == false) { TransformationCount++; // Left || FALSE => Left return(x.Left); } } } // return(base.VisitBinaryExpression(x)); }
public sealed override T VisitBinaryExpression(BoundBinaryEx x) { Visit(x, ConditionBranch.Default); return(default);
internal override void Generate(CodeGenerator cg) { // four cases: // 1. just single or none case label that can be replaced with single IF // 2. switch over integers, using native CIL switch // 3. switch over strings, using C# static Dictionary and CIL switch // 4. PHP style switch which is just a bunch of IFs if (this.CaseBlocks.Length == 0 || this.CaseBlocks[0].IsDefault) { Debug.Assert(this.CaseBlocks.Length <= 1); // no SWITCH or IF needed cg.EmitPop(this.SwitchValue.WithAccess(BoundAccess.None).Emit(cg)); // None Access, also using BoundExpression.Emit directly to avoid CodeGenerator type specialization which is not needed if (this.CaseBlocks.Length == 1) { cg.GenerateScope(this.CaseBlocks[0], NextBlock.Ordinal); } } else { // CIL Switch: bool allconsts = this.CaseBlocks.All(c => c.IsDefault || c.CaseValue.ConstantObject.HasValue); bool allconstints = allconsts && this.CaseBlocks.All(c => c.IsDefault || IsInt32(c.CaseValue.ConstantObject.Value)); //bool allconststrings = allconsts && this.CaseBlocks.All(c => c.IsDefault || IsString(c.CaseValue.ConstantValue.Value)); var default_block = this.DefaultBlock; // <switch_loc> = <SwitchValue>; TypeSymbol switch_type; LocalDefinition switch_loc; // Switch Header if (allconstints) { switch_type = cg.CoreTypes.Int32; cg.EmitSequencePoint(this.SwitchValue.PhpSyntax); cg.EmitConvert(this.SwitchValue, switch_type); switch_loc = cg.GetTemporaryLocal(switch_type); cg.Builder.EmitLocalStore(switch_loc); // switch (labels) cg.Builder.EmitIntegerSwitchJumpTable(GetSwitchCaseLabels(CaseBlocks), default_block ?? NextBlock, switch_loc, switch_type.PrimitiveTypeCode); } //else if (allconststrings) //{ //} else { // legacy jump table // IF (case_i) GOTO label_i; cg.EmitSequencePoint(this.SwitchValue.PhpSyntax); switch_type = cg.Emit(this.SwitchValue); switch_loc = cg.GetTemporaryLocal(switch_type); cg.Builder.EmitLocalStore(switch_loc); // for (int i = 0; i < this.CaseBlocks.Length; i++) { var this_block = this.CaseBlocks[i]; if (this_block.CaseValue != null) { // <CaseValue>: cg.EmitSequencePoint(this_block.CaseValue.PhpSyntax); // if (<switch_loc> == c.CaseValue) goto this_block; cg.Builder.EmitLocalLoad(switch_loc); BoundBinaryEx.EmitEquality(cg, switch_type, this_block.CaseValue); cg.Builder.EmitBranch(ILOpCode.Brtrue, this_block); } } // default: cg.Builder.EmitBranch(ILOpCode.Br, default_block ?? NextBlock); } // FREE <switch_loc> cg.ReturnTemporaryLocal(switch_loc); // Switch Body this.CaseBlocks.ForEach((i, this_block) => { var next_case = (i + 1 < this.CaseBlocks.Length) ? this.CaseBlocks[i + 1] : null; // { cg.GenerateScope(this_block, (next_case ?? NextBlock).Ordinal); // } }); } // cg.Scope.ContinueWith(NextBlock); }
internal override void Generate(CodeGenerator cg) { // four cases: // 1. just single or none case label that can be replaced with single IF // 2. switch over integers, using native CIL switch // 3. switch over strings, using C# static Dictionary and CIL switch // 4. PHP style switch which is just a bunch of IFs if (this.CaseBlocks.Length == 0 || (this.CaseBlocks[0].IsDefault && this.CaseBlocks.Length == 1)) { Debug.Assert(this.CaseBlocks.Length <= 1); // no SWITCH or IF needed cg.EmitPop(this.SwitchValue.WithAccess(BoundAccess.None).Emit(cg)); // None Access, also using BoundExpression.Emit directly to avoid CodeGenerator type specialization which is not needed if (this.CaseBlocks.Length != 0) { cg.GenerateScope(this.CaseBlocks[0], NextBlock.Ordinal); } } else { // CIL Switch: bool allConst = this.CaseBlocks.All(c => c.IsDefault || (c.CaseValue.IsOnlyBoundElement && c.CaseValue.BoundElement.ConstantValue.HasValue)); bool allIntConst = allConst && this.CaseBlocks.All(c => c.IsDefault || IsInt32(c.CaseValue.BoundElement.ConstantValue.Value)); //bool allconststrings = allconsts && this.CaseBlocks.All(c => c.IsDefault || IsString(c.CaseValue.ConstantValue.Value)); var default_block = this.DefaultBlock; // <switch_loc> = <SwitchValue>; TypeSymbol switch_type; LocalDefinition switch_loc; // Switch Header if (allIntConst) { switch_type = cg.CoreTypes.Int32; cg.EmitSequencePoint(this.SwitchValue.PhpSyntax); cg.EmitConvert(this.SwitchValue, switch_type); switch_loc = cg.GetTemporaryLocal(switch_type); cg.Builder.EmitLocalStore(switch_loc); // switch (labels) cg.Builder.EmitIntegerSwitchJumpTable(GetSwitchCaseLabels(CaseBlocks), default_block ?? NextBlock, switch_loc, switch_type.PrimitiveTypeCode); } //else if (allconststrings) //{ //} else { // legacy jump table // IF (case_i) GOTO label_i; cg.EmitSequencePoint(this.SwitchValue.PhpSyntax); switch_type = cg.Emit(this.SwitchValue); switch_loc = cg.GetTemporaryLocal(switch_type); cg.Builder.EmitLocalStore(switch_loc); // foreach (var this_block in this.CaseBlocks) { var caseValueBag = this_block.CaseValue; if (caseValueBag.IsEmpty) { continue; } if (!caseValueBag.IsOnlyBoundElement) { cg.ReturnTemporaryLocal(switch_loc); // statements in pre-bound-blocks could return (e.g. yieldStatement) & destroy stack-local switch_loc variable -> be defensive caseValueBag.PreBoundBlockFirst.Emit(cg); // emit all blocks that have to go before case value emit } // reininiaze switch_loc if destroyed previously if (!caseValueBag.IsOnlyBoundElement) { cg.Emit(this.SwitchValue); switch_loc = cg.GetTemporaryLocal(switch_type); cg.Builder.EmitLocalStore(switch_loc); } // <CaseValue>: var caseValue = caseValueBag.BoundElement; cg.EmitSequencePoint(caseValue.PhpSyntax); // if (<switch_loc> == c.CaseValue) goto this_block; cg.Builder.EmitLocalLoad(switch_loc); BoundBinaryEx.EmitEquality(cg, switch_type, caseValue); cg.Builder.EmitBranch(ILOpCode.Brtrue, this_block); } // default: cg.Builder.EmitBranch(ILOpCode.Br, default_block ?? NextBlock); } // FREE <switch_loc> cg.ReturnTemporaryLocal(switch_loc); // Switch Body this.CaseBlocks.ForEach((i, this_block) => { var next_case = (i + 1 < this.CaseBlocks.Length) ? this.CaseBlocks[i + 1] : null; // { cg.GenerateScope(this_block, (next_case ?? NextBlock).Ordinal); // } }); } cg.Scope.ContinueWith(NextBlock); }
protected virtual void Visit(BoundBinaryEx x, ConditionBranch branch) { base.VisitBinaryExpression(x); }
public sealed override void VisitBinaryExpression(BoundBinaryEx x) => Visit(x, ConditionBranch.Default);