123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974 |
- #if REFLECTION_EMIT_COMPILER
- using Microsoft.CodeAnalysis.CSharp.Syntax;
- using Microsoft.CodeAnalysis.CSharp;
- using System.Reflection.Emit;
- using System.Reflection;
- using System.Diagnostics;
- using System.Linq.Expressions;
- using System;
- using System.Collections.Generic;
- using System.Security.Cryptography;
- using FastReport.Utils;
- using System.Linq;
- using System.Runtime.CompilerServices;
- #if DEBUG
- using ILGenerator = FastReport.Code.Expressions.ILGeneratorDebugger;
- #endif
- namespace FastReport.Code.Expressions
- {
- /* TODO:
- * new [] {}
- * static Type searching
- * extension methods
- * 'dynamic' support
- */
- internal sealed class CSharpILParser : ILParser
- {
- ILGenerator gen;
- private readonly Report _report;
- private Type[] argTypes;
- private static readonly Type _returnType = typeof(object);
- public CSharpILParser(Report report)
- {
- _report = report;
- }
- protected override MethodInfo CompileExpression(string expression, Type[] argTypes)
- {
- ExpressionSyntax parse = SyntaxFactory.ParseExpression(expression);
- return StartDynamic(parse, argTypes);
- }
- private MethodInfo StartDynamic(ExpressionSyntax expressionSyntax, Type[] argTypes)
- {
- const string myMthdName = "CalcExpression";
- this.argTypes = argTypes;
- DynamicMethod dynamicMethod = new DynamicMethod(myMthdName,
- _returnType,
- argTypes,
- typeof(ILGenerator).Module,
- true
- //typeof(string).Module
- );
- #if DEBUG
- gen = new ILGeneratorDebugger(dynamicMethod.GetILGenerator());
- #else
- gen = dynamicMethod.GetILGenerator();
- #endif
- StartParse(expressionSyntax);
- return dynamicMethod;
- }
- private void StartParse(ExpressionSyntax expressionSyntax)
- {
- Type returnType = ParseToIL(expressionSyntax);
- CastTo(returnType, _returnType);
- gen.Emit(OpCodes.Ret);
- }
- public Type ParseToIL(ExpressionSyntax expression, Type leftType = null)
- {
- if (expression is BinaryExpressionSyntax binary)
- return BinaryOp(binary);
- else if (expression is LiteralExpressionSyntax literal)
- return PutValueOnStack(literal.Token.Value);
- else if (expression is InvocationExpressionSyntax invocation)
- return ParseToIL(invocation.Expression, leftType);
- else if (expression is MemberAccessExpressionSyntax memberAccess)
- return MemberAccessOp(memberAccess);
- else if (expression is IdentifierNameSyntax identifierName)
- return SearchIdentifier(identifierName, leftType);
- else if (expression is PredefinedTypeSyntax predefinedType)
- return ParsePredefinedType(predefinedType.Keyword.Value.ToString());
- else if (expression is PostfixUnaryExpressionSyntax postfixUnary)
- return UnaryPostOp(postfixUnary);
- else if (expression is PrefixUnaryExpressionSyntax prefixUnary)
- return UnaryPreOp(prefixUnary);
- else if (expression is ConditionalExpressionSyntax conditional) // a ? b : c
- return ConditionalOp(conditional);
- else if (expression is AssignmentExpressionSyntax assignment) // =
- return AssignmentOp(assignment);
- else if (expression is ParenthesizedExpressionSyntax parenthesized) // (a)
- return ParseToIL(parenthesized.Expression, leftType);
- else if (expression is CastExpressionSyntax cast) // ()a
- return ExplicitCastOp(cast);
- else if (expression is ConditionalAccessExpressionSyntax conditionalAccess) // ?.
- return ConditionalAccessOp(conditionalAccess);
- else if (expression is MemberBindingExpressionSyntax memberBinding)
- return MemberAccessOp(memberBinding, leftType);
- else if (expression is ElementAccessExpressionSyntax elementAccess) // a[0]
- return ElementAccessOp(elementAccess);
- else if (expression is ArrayCreationExpressionSyntax arrayCreation) // new int[] { }
- {
- // TODO:
- var arrayType = ParseToIL(arrayCreation.Type);
- }
- else if (expression is ImplicitArrayCreationExpressionSyntax implicitArrayCreation) // new[] { }
- {
- }
- throw new NotImplementedException();
- }
- private Type SearchIdentifier(IdentifierNameSyntax identifierName, Type leftType)
- {
- var identifier = identifierName.Identifier.ValueText;
- // leftType can be null => it's static class etc
- if (identifierName.Parent is InvocationExpressionSyntax invocation)
- {
- // method:
- Type[] argumentTypes = ExecuteArguments(invocation.ArgumentList);
- FunctionInfo info = RegisteredObjects.Functions.Find(identifier);
- if (info == null)
- throw new NotSupportedException($"Method '{identifier}' wasn't found");
- return MethodCall(leftType, info.Function);
- }
- else
- {
- // class, parameter, property, field etc
- if (identifier == "Report") // hard
- {
- return LoadReport();
- }
- else if (identifier == "Value")
- {
- gen.Emit(OpCodes.Ldarg_1);
- return argTypes[1];
- }
- else if (identifier == "Engine")
- {
- var reportType = LoadReport();
- return MemberAccessOp(identifier, identifierName, reportType);
- }
- var type = ParseKnownType(identifier);
- if (type != null)
- return type;
- // report objects
- Base obj = _report.FindObject(identifier);
- if (obj != null)
- {
- // IT'S DYNAMIC STATE! We should't store it!
- var reportType = LoadReport();
- var argType = PutValueOnStack(identifier);
- var findObjectMethod = reportType.GetMethod(nameof(_report.FindObject), new[] {argType});
- var findObjectReturnType = MethodCall(reportType, findObjectMethod);
- // cast to necessary type:
- var reportObjectType = obj.GetType();
- CastTo(findObjectReturnType, reportObjectType);
- return reportObjectType;
- }
- if (type == null)
- type = Type.GetType(identifier, false, false);
- if (type != null)
- return type;
- }
- throw new NotSupportedException();
- }
- private Type LoadReport()
- {
- gen.Emit(OpCodes.Ldarg_0);
- return argTypes[0];
- }
- private static Type ParsePredefinedType(string typeName)
- {
- switch (typeName)
- {
- case "object": return typeof(object);
- case "string": return typeof(string);
- case "bool": return typeof(bool);
- case "byte": return typeof(byte);
- case "sbyte": return typeof(sbyte);
- case "char": return typeof(char);
- case "short": return typeof(short);
- case "ushort": return typeof(ushort);
- case "int": return typeof(int);
- case "uint": return typeof(uint);
- case "long": return typeof(long);
- case "ulong": return typeof(ulong);
- case "float": return typeof(float);
- case "double": return typeof(double);
- case "decimal": return typeof(decimal);
- }
- throw new NotSupportedException();
- }
- private static Type ParseKnownType(string typeName)
- {
- switch (typeName)
- {
- case "Object": return typeof(object);
- case "String": return typeof(string);
- case "Boolean": return typeof(Boolean);
- case "Byte": return typeof(Byte);
- case "SByte": return typeof(SByte);
- case "Char": return typeof(Char);
- case "Int16": return typeof(Int16);
- case "UInt16": return typeof(UInt16);
- case "Int32": return typeof(Int32);
- case "UInt32": return typeof(UInt32);
- case "Int64": return typeof(Int64);
- case "UInt64": return typeof(UInt64);
- case "Single": return typeof(Single);
- case "Double": return typeof(Double);
- case "Decimal": return typeof(Decimal);
- case "DateTime": return typeof(DateTime);
- case "DateTimeOffset": return typeof(DateTimeOffset);
- }
- return null;
- }
- private Type MemberAccessOp(MemberAccessExpressionSyntax memberAccess)
- {
- Type type = ParseToIL(memberAccess.Expression);
- var name = memberAccess.Name.Identifier.ValueText;
- return MemberAccessOp(name, memberAccess, type);
- }
- private Type MemberAccessOp(MemberBindingExpressionSyntax memberAccess, Type leftType)
- {
- var name = memberAccess.Name.Identifier.ValueText;
- return MemberAccessOp(name, memberAccess, leftType);
- }
- private Type MemberAccessOp(string name, ExpressionSyntax expression, Type leftType)
- {
- if (expression.Parent is InvocationExpressionSyntax invocation)
- {
- // method
- Type[] argumentTypes = ExecuteArguments(invocation.ArgumentList);
- var methodInfo = CustomMethodSearcher.Search(leftType, name, argumentTypes);
- return MethodCall(leftType, methodInfo);
- }
- else
- {
- // property or field
- var property = leftType.GetProperty(name);
- // if it's not a property => try to find a field
- if (property == null)
- {
- var field = leftType.GetField(name);
- gen.Emit(OpCodes.Ldfld, field);
- return field.FieldType;
- }
- // only get
- var methodInfo = property.GetGetMethod();
- return MethodCall(leftType, methodInfo);
- }
- }
- private Type MethodCall(Type targetType, MethodInfo methodInfo)
- {
- if (methodInfo.IsStatic)
- {
- gen.EmitCall(OpCodes.Call, methodInfo, null);
- }
- else
- {
- if (targetType.IsValueType)
- {
- // if local:
- var local = gen.DeclareLocal(targetType);
- gen.Emit(OpCodes.Stloc, local);
- gen.Emit(OpCodes.Ldloca_S, local);
- gen.EmitCall(OpCodes.Call, methodInfo, null);
- }
- else
- gen.EmitCall(OpCodes.Callvirt, methodInfo, null);
- }
- return methodInfo.ReturnType;
- }
- private Type AssignmentOp(AssignmentExpressionSyntax assignment)
- {
- var type = ParseToIL(assignment.Right);
- ParseToIL(assignment.Left);
- if (false) // if field
- {
- var local = gen.DeclareLocal(type);
- gen.Emit(OpCodes.Starg_S, local);
- }
- // TODO: assignment
- throw new NotImplementedException();
- //return type;
- return typeof(void);
- }
- private Type[] ExecuteArguments(BaseArgumentListSyntax argumentList)
- {
- var arguments = argumentList.Arguments;
- List<Type> types = new List<Type>();
- foreach (var argument in arguments)
- {
- var resultTypeArg = ParseToIL(argument.Expression);
- types.Add(resultTypeArg);
- }
- return types.ToArray();
- }
- private Type ConditionalOp(ConditionalExpressionSyntax conditional)
- {
- Label ifTrue = gen.DefineLabel();
- Label next = gen.DefineLabel();
- var conditionType = ParseToIL(conditional.Condition);
- //if (conditionType != typeof(bool))
- // throw new Exception();
- gen.Emit(OpCodes.Brtrue_S, ifTrue);
- var type1 = ParseToIL(conditional.WhenFalse);
- gen.Emit(OpCodes.Br_S, next);
- gen.MarkLabel(ifTrue);
- var type2 = ParseToIL(conditional.WhenTrue);
- gen.MarkLabel(next);
- //if (type1 != type2)
- // throw new Exception();
- return type1;
- }
- private Type ConditionalAccessOp(ConditionalAccessExpressionSyntax conditionalAccess)
- {
- Label ifTrue = gen.DefineLabel();
- Label next = gen.DefineLabel();
- var type = ParseToIL(conditionalAccess.Expression);
- gen.Emit(OpCodes.Dup);
- gen.Emit(OpCodes.Brtrue_S, ifTrue);
- gen.Emit(OpCodes.Pop);
- gen.Emit(OpCodes.Ldnull);
- gen.Emit(OpCodes.Br_S, next);
- gen.MarkLabel(ifTrue);
- var resultType = ParseToIL(conditionalAccess.WhenNotNull, type);
- gen.MarkLabel(next);
- return resultType;
- }
- private Type UnaryPreOp(PrefixUnaryExpressionSyntax prefixUnary)
- {
- var kind = prefixUnary.Kind();
- var op = prefixUnary.Operand;
- Type returnType = ParseToIL(op);
- if (returnType == typeof(decimal))
- return BinaryCustomTypeOp(returnType, kind);
- switch (kind)
- {
- case SyntaxKind.BitwiseNotExpression: // ~
- gen.Emit(OpCodes.Not);
- break;
- case SyntaxKind.UnaryMinusExpression: // -
- gen.Emit(OpCodes.Neg);
- break;
- case SyntaxKind.LogicalNotExpression: // !
- returnType = CompareWithZero();
- break;
- case SyntaxKind.PreIncrementExpression: // ++a
- gen.Emit(OpCodes.Ldc_I4_1);
- gen.Emit(OpCodes.Add);
- break;
- case SyntaxKind.PreDecrementExpression: // --a
- gen.Emit(OpCodes.Ldc_I4_1);
- gen.Emit(OpCodes.Sub);
- break;
- }
- return returnType;
- }
- private Type UnaryPostOp(PostfixUnaryExpressionSyntax postfixUnary)
- {
- var op = postfixUnary.Operand;
- var kind = postfixUnary.Kind();
- Type returnType = ParseToIL(op);
- if (returnType == typeof(decimal))
- return BinaryCustomTypeOp(returnType, kind);
- switch (kind)
- {
- case SyntaxKind.PostIncrementExpression: // a++
- gen.Emit(OpCodes.Ldc_I4_1);
- gen.Emit(OpCodes.Add);
- break;
- case SyntaxKind.PostDecrementExpression: // a--
- gen.Emit(OpCodes.Ldc_I4_1);
- gen.Emit(OpCodes.Sub);
- break;
- }
- return returnType;
- }
- private Type PutValueOnStack(object value)
- {
- if (value == null)
- {
- gen.Emit(OpCodes.Ldnull);
- return typeof(object);
- }
- var type = value.GetType();
- if (type == typeof(int))
- {
- gen.Emit(OpCodes.Ldc_I4, Convert.ToInt32(value));
- }
- else if (type == typeof(bool))
- {
- if (Convert.ToBoolean(value))
- gen.Emit(OpCodes.Ldc_I4_1);
- else
- gen.Emit(OpCodes.Ldc_I4_0);
- }
- else if (type == typeof(float))
- {
- gen.Emit(OpCodes.Ldc_R4, Convert.ToSingle(value));
- }
- else if (type == typeof(double))
- {
- gen.Emit(OpCodes.Ldc_R8, Convert.ToDouble(value));
- }
- //else if (type == typeof(char)) // => int32
- //{}
- else if (type == typeof(string))
- {
- gen.Emit(OpCodes.Ldstr, Convert.ToString(value));
- }
- else if (type == typeof(long))
- {
- gen.Emit(OpCodes.Ldc_I8, Convert.ToInt64(value));
- }
- else
- {
- gen.Emit(OpCodes.Ldc_I4, Convert.ToInt32(value));
- }
- return type;
- }
- private Type ElementAccessOp(ElementAccessExpressionSyntax elementAccess)
- {
- var type = ParseToIL(elementAccess.Expression);
- var args = ExecuteArguments(elementAccess.ArgumentList);
- if(type.IsArray)
- {
- var elementType = type.GetElementType();
- if (elementType.IsClass || elementType.IsInterface)
- gen.Emit(OpCodes.Ldelem_Ref);
- else
- gen.Emit(OpCodes.Ldelem, elementType);
- return elementType;
- }
- else
- {
- string propertyName = "Item";
- if (type == typeof(string))
- propertyName = "Chars";
- var property = type.GetProperty(propertyName, args);
- var method = property.GetGetMethod();
- return MethodCall(type, method);
- }
- }
- private Type BinaryOp(BinaryExpressionSyntax binary)
- {
- var kind = binary.Kind();
- switch(kind)
- {
- case SyntaxKind.LogicalOrExpression:
- case SyntaxKind.LogicalAndExpression:
- return LogicalOp(binary, kind);
- case SyntaxKind.IsExpression:
- case SyntaxKind.AsExpression:
- return IsAsOp(binary, kind);
- default:
- return BinaryOpWithCast(binary, kind);
- }
- }
- private Type BinaryOpWithCast(BinaryExpressionSyntax binary, SyntaxKind kind)
- {
- Type leftType = ParseToIL(binary.Left);
- Type rightType = ParseToIL(binary.Right);
- if (leftType == typeof(Variant) || rightType == typeof(Variant))
- return VariantOp(kind, leftType, rightType);
- Type returnType = CastToGreaterType(leftType, rightType);
- if (returnType == typeof(decimal) || returnType == typeof(string))
- return BinaryCustomTypeOp(returnType, kind);
- switch (kind)
- {
- case SyntaxKind.AddExpression: // +
- gen.Emit(OpCodes.Add);
- break;
- case SyntaxKind.SubtractExpression: // -
- gen.Emit(OpCodes.Sub);
- break;
- case SyntaxKind.MultiplyExpression: // *
- gen.Emit(OpCodes.Mul);
- break;
- case SyntaxKind.DivideExpression: // /
- gen.Emit(OpCodes.Div);
- break;
- case SyntaxKind.ModuloExpression: // %
- gen.Emit(OpCodes.Rem);
- break;
- case SyntaxKind.EqualsExpression: // ==
- gen.Emit(OpCodes.Ceq);
- returnType = typeof(bool);
- break;
- case SyntaxKind.NotEqualsExpression: // !=
- // == and NOT
- gen.Emit(OpCodes.Ceq);
- returnType = CompareWithZero();
- break;
- case SyntaxKind.LessThanExpression: // <
- gen.Emit(OpCodes.Clt);
- returnType = typeof(bool);
- break;
- case SyntaxKind.LessThanOrEqualExpression: // <=
- // > and NOT
- gen.Emit(OpCodes.Cgt);
- returnType = CompareWithZero();
- break;
- case SyntaxKind.GreaterThanExpression: // >
- gen.Emit(OpCodes.Cgt);
- returnType = typeof(bool);
- break;
- case SyntaxKind.GreaterThanOrEqualExpression: // >=
- // < and NOT
- gen.Emit(OpCodes.Clt);
- returnType = CompareWithZero();
- break;
- case SyntaxKind.BitwiseOrExpression: // |
- gen.Emit(OpCodes.Or);
- break;
- case SyntaxKind.ExclusiveOrExpression: // ^
- gen.Emit(OpCodes.Xor);
- break;
- case SyntaxKind.BitwiseAndExpression: // &
- gen.Emit(OpCodes.And);
- break;
- }
- return returnType;
- }
- private Type BinaryCustomTypeOp(Type type, SyntaxKind kind)
- {
- string methodName = GetOperatorName(kind);
- MethodInfo method;
- if (type == typeof(string) && kind == SyntaxKind.AddExpression)
- method = type.GetMethod(nameof(string.Concat), new Type[] { type, type });
- else
- method = type.GetMethod(methodName);
- return MethodCall(type, method);
- }
- private Type VariantOp(SyntaxKind kind, Type left, Type right)
- {
- Type variantType = typeof(Variant);
- string methodName = GetOperatorName(kind);
- MethodInfo method = variantType.GetMethod(methodName);
- // because 1 argument in Variant must be 'Variant'
- if (left != variantType)
- PreviousCastTo(left, variantType);
- // because 2 argument in Variant operator is object
- var parameters = method.GetParameters();
- if (parameters.Length == 2)
- {
- CastTo(right, parameters[1].ParameterType);
- }
- return MethodCall(variantType, method);
- }
- private static string GetOperatorName(SyntaxKind kind)
- {
- string methodName;
- switch (kind)
- {
- case SyntaxKind.AddExpression: // +
- methodName = "op_Addition";
- break;
- case SyntaxKind.SubtractExpression: // -
- methodName = "op_Subtraction";
- break;
- case SyntaxKind.MultiplyExpression: // *
- methodName = "op_Multiply";
- break;
- case SyntaxKind.DivideExpression: // /
- methodName = "op_Division";
- break;
- case SyntaxKind.ModuloExpression: // %
- methodName = "op_Modulus";
- break;
- case SyntaxKind.EqualsExpression: // ==
- methodName = "op_Equality";
- break;
- case SyntaxKind.NotEqualsExpression: // !=
- methodName = "op_Inequality";
- break;
- case SyntaxKind.LessThanExpression: // <
- methodName = "op_LessThan";
- break;
- case SyntaxKind.LessThanOrEqualExpression: // <=
- methodName = "op_LessThanOrEqual";
- break;
- case SyntaxKind.GreaterThanExpression: // >
- methodName = "op_GreaterThan";
- break;
- case SyntaxKind.GreaterThanOrEqualExpression: // >=
- methodName = "op_GreaterThanOrEqual";
- break;
- case SyntaxKind.UnaryMinusExpression: // unary -
- methodName = "op_UnaryNegation";
- break;
- case SyntaxKind.PreIncrementExpression: // ++a
- case SyntaxKind.PostIncrementExpression: // a++
- methodName = "op_Increment";
- break;
- case SyntaxKind.PreDecrementExpression: // --a
- case SyntaxKind.PostDecrementExpression: // a--
- methodName = "op_Decrement";
- break;
- default:
- throw new NotSupportedException("This operation isn't supported with this type");
- }
- return methodName;
- }
- private Type IsAsOp(BinaryExpressionSyntax binary, SyntaxKind kind)
- {
- var type1 = ParseToIL(binary.Left);
- var type2 = ParseToIL(binary.Right);
- Type returnType = type1;
- switch (kind)
- {
- case SyntaxKind.IsExpression: // is
- gen.Emit(OpCodes.Isinst, type2);
- gen.Emit(OpCodes.Ldnull);
- gen.Emit(OpCodes.Cgt_Un);
- returnType = typeof(bool);
- break;
- case SyntaxKind.AsExpression: // as
- // 'as' cannot be applied to non-reference types
- if (type2.IsValueType)
- throw new NotSupportedException();
- gen.Emit(OpCodes.Isinst, type2);
- returnType = type2;
- break;
- }
- return returnType;
- }
- private Type CastToGreaterType(Type leftType, Type rightType)
- {
- if (leftType == rightType)
- return leftType;
- Type result;
- result = CompareAndCastTo(leftType, rightType, typeof(Variant));
- if (result != null)
- return result;
- result = CompareAndCastTo(leftType, rightType, typeof(string)); // string is the strongest type
- if (result != null)
- return result;
- result = CompareAndCastTo(leftType, rightType, typeof(decimal));
- if (result != null)
- return result;
- result = CompareAndCastTo(leftType, rightType, typeof(double));
- if (result != null)
- return result;
- result = CompareAndCastTo(leftType, rightType, typeof(float));
- if (result != null)
- return result;
- result = CompareAndCastTo(leftType, rightType, typeof(ulong));
- if (result != null)
- return result;
- result = CompareAndCastTo(leftType, rightType, typeof(long));
- if (result != null)
- return result;
- throw new NotImplementedException();
- }
- private Type CompareAndCastTo(Type leftType, Type rightType, Type comparableType)
- {
- if (rightType == comparableType
- || leftType == comparableType)
- {
- if (leftType == comparableType)
- return CastTo(rightType, leftType);
- else
- return PreviousCastTo(leftType, rightType);
- }
- return null;
- }
- private Type PreviousCastTo(Type original, Type toType)
- {
- var local = gen.DeclareLocal(toType);
- gen.Emit(OpCodes.Stloc, local);
- // cast leftType:
- toType = CastTo(original, toType);
- gen.Emit(OpCodes.Ldloc, local);
- return toType;
- }
- private Type LogicalOp(BinaryExpressionSyntax binary, SyntaxKind kind)
- {
- var type1 = ParseToIL(binary.Left);
- Label answer = gen.DefineLabel();
- OpCode answerOpcode;
- Label next = gen.DefineLabel();
- switch (kind)
- {
- case SyntaxKind.LogicalOrExpression: // ||
- gen.Emit(OpCodes.Brtrue_S, answer);
- answerOpcode = OpCodes.Ldc_I4_1;
- break;
- case SyntaxKind.LogicalAndExpression: // &&
- gen.Emit(OpCodes.Brfalse_S, answer);
- answerOpcode = OpCodes.Ldc_I4_0;
- break;
- default: throw new Exception();
- }
- Type type2 = ParseToIL(binary.Right);
- gen.Emit(OpCodes.Br_S, next);
- gen.MarkLabel(answer);
- gen.Emit(answerOpcode);
- gen.MarkLabel(next);
- return typeof(bool);
- }
- private Type ExplicitCastOp(CastExpressionSyntax cast)
- {
- var originType = ParseToIL(cast.Expression);
- var type = ParseToIL(cast.Type);
- return CastTo(originType, type, true);
- }
- private Type CastTo(Type original, Type toType, bool _explicit = false)
- {
- if (original.IsClass)
- {
- if(toType.IsValueType)
- {
- if (original != typeof(object)) // Unbox only for object
- throw new NotSupportedException($"You cannot cast type \"{original}\" to type \"{toType}\"");
- gen.Emit(OpCodes.Unbox_Any, toType);
- }
- else if (toType == typeof(object))
- return toType; // do nothing
- else
- gen.Emit(OpCodes.Castclass, toType);
- }
- else if (original.IsValueType)
- {
- if (toType == typeof(object))
- gen.Emit(OpCodes.Box, original);
- // decimal has special operators for parsing into different types (exclude object)
- else if (original == typeof(decimal))
- {
- var methods = original.GetMethods(BindingFlags.Static | BindingFlags.Public);
- foreach (var method in methods)
- if (method.ReturnType == toType && method.IsSpecialName)
- return MethodCall(original, method);
- }
- else if (toType == typeof(decimal))
- {
- var method = toType.GetMethod("op_Implicit", new Type[] { original });
- if (method != null)
- return MethodCall(toType, method);
- // float and double require explicit casting
- if (_explicit)
- {
- method = toType.GetMethod("op_Explicit", new Type[] { original });
- if (method != null)
- return MethodCall(toType, method);
- }
- throw new NotSupportedException($"You cannot cast type \"{original}\" to type \"{toType}\"");
- }
- else if (toType == typeof(double))
- gen.Emit(OpCodes.Conv_R8);
- else if (toType == typeof(float))
- gen.Emit(OpCodes.Conv_R4);
- else if (toType == typeof(ulong))
- gen.Emit(OpCodes.Conv_U8);
- else if (toType == typeof(long))
- gen.Emit(OpCodes.Conv_I8);
- else if (toType.IsPrimitive)
- {
- // else int, uint etc
- // do nothing
- // TODO:
- // int + uint => long
- }
- else
- {
- var method = toType.GetMethod("op_Implicit", new Type[] { original });
- if (method != null)
- return MethodCall(toType, method);
- if (_explicit)
- {
- method = toType.GetMethod("op_Explicit", new Type[] { original });
- if (method != null)
- return MethodCall(toType, method);
- }
- if (toType.IsClass || toType.IsInterface)
- throw new NotSupportedException($"You cannot cast type \"{original}\" to type \"{toType}\"");
- }
- }
- else if (original.IsInterface)
- {
- if (toType == typeof(object))
- return toType; // do nothing
- if (toType.IsValueType)
- {
- if (original.IsAssignableFrom(toType))
- throw new NotSupportedException($"You cannot cast type \"{original}\" to type \"{toType}\"");
- gen.Emit(OpCodes.Unbox_Any, toType);
- }
- else
- gen.Emit(OpCodes.Castclass, toType);
- }
- else
- gen.Emit(OpCodes.Castclass, toType);
- return toType;
- }
- private Type CompareWithZero()
- {
- gen.Emit(OpCodes.Ldc_I4_0);
- gen.Emit(OpCodes.Ceq);
- return typeof(bool);
- }
- }
- }
- #endif
|