Files
Flee/ExpressionElements/Conditional.cs

77 lines
2.8 KiB
C#

using System;
using System.Reflection.Emit;
using Flee.ExpressionElements.Base;
using Flee.InternalTypes;
using Flee.PublicTypes;
using Flee.Resources;
namespace Flee.ExpressionElements
{
internal class ConditionalElement : ExpressionElement
{
private readonly ExpressionElement _myCondition;
private readonly ExpressionElement _myWhenTrue;
private readonly ExpressionElement _myWhenFalse;
private readonly Type _myResultType;
public ConditionalElement(ExpressionElement condition, ExpressionElement whenTrue, ExpressionElement whenFalse)
{
_myCondition = condition;
_myWhenTrue = whenTrue;
_myWhenFalse = whenFalse;
if ((!object.ReferenceEquals(_myCondition.ResultType, typeof(bool))))
{
base.ThrowCompileException(CompileErrorResourceKeys.FirstArgNotBoolean, CompileExceptionReason.TypeMismatch);
}
// The result type is the type that is common to the true/false operands
if (ImplicitConverter.EmitImplicitConvert(_myWhenFalse.ResultType, _myWhenTrue.ResultType, null) == true)
{
_myResultType = _myWhenTrue.ResultType;
}
else if (ImplicitConverter.EmitImplicitConvert(_myWhenTrue.ResultType, _myWhenFalse.ResultType, null) == true)
{
_myResultType = _myWhenFalse.ResultType;
}
else
{
base.ThrowCompileException(CompileErrorResourceKeys.NeitherArgIsConvertibleToTheOther, CompileExceptionReason.TypeMismatch, _myWhenTrue.ResultType.Name, _myWhenFalse.ResultType.Name);
}
}
public override void Emit(FleeILGenerator ilg, IServiceProvider services)
{
this.EmitConditional(ilg, services);
}
private void EmitConditional(FleeILGenerator ilg, IServiceProvider services)
{
Label falseLabel = ilg.DefineLabel();
Label endLabel = ilg.DefineLabel();
// Emit the condition
_myCondition.Emit(ilg, services);
// On false go to the false operand
ilg.EmitBranchFalse(falseLabel);
// Emit the true operand
_myWhenTrue.Emit(ilg, services);
ImplicitConverter.EmitImplicitConvert(_myWhenTrue.ResultType, _myResultType, ilg);
// Jump to end
ilg.EmitBranch(endLabel);
ilg.MarkLabel(falseLabel);
// Emit the false operand
_myWhenFalse.Emit(ilg, services);
ImplicitConverter.EmitImplicitConvert(_myWhenFalse.ResultType, _myResultType, ilg);
// Fall through to end
ilg.MarkLabel(endLabel);
}
public override System.Type ResultType => _myResultType;
}
}