protected override AbstractSyntaxTree GenerateCodeForValue(CodeGenContext context, EvaluationIntention purpose) { bool so = false; switch (purpose) { case EvaluationIntention.SideEffectsOnly: so = true; break; case EvaluationIntention.Value: case EvaluationIntention.ValueOrNode: break; default: throw new AssertionFailedException("unexpected evaluation intention" + purpose); } var secondChoice = context.CreateLabel(); Pre.GenerateCodeForConditionalBranchWithPrettyPrint(context, secondChoice, false); Mid.GenerateCodeForValueWithPrettyPrint(context, so ? EvaluationIntention.SideEffectsOnly : EvaluationIntention.Value); var joinPoint = context.CreateLabel(); context.GenerateUnconditionalBranch(joinPoint); context.PlaceLabelHere(secondChoice); Post.GenerateCodeForValueWithPrettyPrint(context, so ? EvaluationIntention.SideEffectsOnly : EvaluationIntention.Value); context.PlaceLabelHere(joinPoint); return(null); }
// NB: Short Circut Evaluation (Left || Right): if "Left" evaluates to true we must not evaluate "Right" protected override AbstractSyntaxTree GenerateCodeForValue(CodeGenContext context, EvaluationIntention purpose) { switch (purpose) { case EvaluationIntention.SideEffectsOnly: // We have something like an expression statement: // a || b; // or perhaps a parameter as in // f(a||b); // This requires differentiated evaluation for left/first and right/second as follows: // a's truth value determines whether b is executed or skipped (short-circuted). // if a is false, then b is executed; otherwise if a is true, b is skipped. // thus, we need to evaluate "a" for conditional branch, and to branch around "b"! // however, b does not affect anything further (and we don't need a final value for (a||b) either). // Thus, b is evaluated for side effects only. var joinPoint1 = context.CreateLabel(); Left.GenerateCodeForConditionalBranchWithPrettyPrint(context, joinPoint1, true); Right.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.SideEffectsOnly); context.PlaceLabelHere(joinPoint1); return(null); case EvaluationIntention.Value: case EvaluationIntention.ValueOrNode: // we have an expression like (a || b) + 3 so we treat that like: ((a || b) ? 1 : 0) + 3; var zero = context.CreateLabel(); context.EvalEither(Left, Right, zero, false); // get temp, so easy on stack machine context.GenerateInstruction("PUSH", "#1"); var joinPoint2 = context.CreateLabel(); context.GenerateUnconditionalBranch(joinPoint2); context.PlaceLabelHere(zero); context.GenerateInstruction("PUSH", "#0"); context.PlaceLabelHere(joinPoint2); return(null); default: throw new AssertionFailedException("unexpected evaluation intention" + purpose); } }