public static Conversion Implicit(ResolveContext from, Type to) { var fromExpr = from as ResolveContextExpression; // 6.1.3 Implicit enumeration conversions if (to.IsEnum) { if (fromExpr != null) { var constExpr = fromExpr.Expression as ConstantExpression; if (constExpr != null && constExpr.Value is int && ((int) constExpr.Value) == 0) return new EnumConversion(to, true); } } // 6.1.9 Implicit constant expression conversions if (fromExpr != null) { var constExpr = fromExpr.Expression as ConstantExpression; if (constExpr != null && constExpr.Value is int) { var integer = (int) constExpr.Value; if (to == typeof(sbyte) && integer >= sbyte.MinValue && integer <= sbyte.MaxValue) return new ConstantExpressionConversion(to, true); if (to == typeof(byte) && integer >= byte.MinValue && integer <= byte.MaxValue) return new ConstantExpressionConversion(to, true); if (to == typeof(short) && integer >= short.MinValue && integer <= short.MaxValue) return new ConstantExpressionConversion(to, true); if (to == typeof(ushort) && integer >= ushort.MinValue && integer <= ushort.MaxValue) return new ConstantExpressionConversion(to, true); if (to == typeof(uint) && integer >= 0) return new ConstantExpressionConversion(to, true); if (to == typeof(ulong) && integer >= 0) return new ConstantExpressionConversion(to, true); } else if (constExpr != null && constExpr.Value is long && to == typeof(ulong)) { var integer = (long) constExpr.Value; if (integer >= 0) return new ConstantExpressionConversion(to, true); } } // 6.1.5 Null literal conversions if (to.IsGenericType && to.GetGenericTypeDefinition() == typeof(Nullable<>) && from is ResolveContextNullLiteral) return new NullLiteralConversion(to, true); if (!to.IsValueType && from is ResolveContextNullLiteral) return new NullLiteralConversion(to, true); if (from is ResolveContextLambda) return null; return Implicit(from.ExpressionType, to); }
internal ResolveContext ResolveSimpleName(CsIdentifier simpleName, ResolveContext context = null) { if (context is ResolveContextMethodGroup) throw new NotImplementedException("Access to method groups is not supported."); var simpleNameBuiltin = simpleName as CsKeywordIdentifier; if (simpleNameBuiltin != null) { if (context != null) throw new InvalidOperationException("Unexpected built-in: {0}.".Fmt(simpleNameBuiltin.ToString())); switch (simpleNameBuiltin.Keyword) { case "string": return new ResolveContextType(typeof(string)); case "sbyte": return new ResolveContextType(typeof(sbyte)); case "byte": return new ResolveContextType(typeof(byte)); case "short": return new ResolveContextType(typeof(short)); case "ushort": return new ResolveContextType(typeof(ushort)); case "int": return new ResolveContextType(typeof(int)); case "uint": return new ResolveContextType(typeof(uint)); case "long": return new ResolveContextType(typeof(long)); case "ulong": return new ResolveContextType(typeof(ulong)); case "object": return new ResolveContextType(typeof(object)); case "bool": return new ResolveContextType(typeof(bool)); case "char": return new ResolveContextType(typeof(char)); case "float": return new ResolveContextType(typeof(float)); case "double": return new ResolveContextType(typeof(double)); case "decimal": return new ResolveContextType(typeof(decimal)); case "this": if (_currentInstance == null) throw new InvalidOperationException("Cannot use ‘this’ pointer when no current instance exists."); return new ResolveContextConstant(_currentInstance); case "base": throw new InvalidOperationException("Base method calls are not supported."); default: throw new InvalidOperationException("Unexpected built-in: {0}.".Fmt(simpleNameBuiltin.ToString())); } } var simpleNameIdentifier = simpleName as CsNameIdentifier; if (simpleNameIdentifier == null) throw new InvalidOperationException("Unexpected simple-name type: {0}.".Fmt(simpleName.GetType().FullName)); // Is it a local? if (context == null && _localNames.ContainsKey(simpleNameIdentifier.Name)) return _localNames[simpleNameIdentifier.Name]; List<string> candidatePrefixes = new List<string>(); if (context is ResolveContextNamespace) candidatePrefixes.Add(((ResolveContextNamespace) context).Namespace); else if ((context == null && _currentNamespace == null) || context is ResolveContextGlobal) candidatePrefixes.Add(null); else if (context == null) { candidatePrefixes.Add(null); string soFar = null; foreach (var part in _currentNamespace.Split('.')) { soFar += (soFar == null ? "" : ".") + part; candidatePrefixes.Add(soFar); } candidatePrefixes.AddRange(_usingNamespaces); } // Is it a namespace? if (simpleNameIdentifier.GenericTypeArguments == null && (context == null || context is ResolveContextNamespace) && _assemblies != null) { foreach (var prefix in candidatePrefixes) { var prefixWithName = prefix == null ? simpleNameIdentifier.Name : prefix + "." + simpleNameIdentifier.Name; var typeWithNamespace = _assemblies.SelectMany(a => a.GetTypes()).FirstOrDefault(t => t.Namespace == prefixWithName || (t.Namespace != null && t.Namespace.StartsWith(prefixWithName + "."))); if (typeWithNamespace != null) return new ResolveContextNamespace(prefixWithName); } } // Custom resolver ICustomResolver icr; ResolveContextConstant rcc; if ((context == null && (icr = _currentInstance as ICustomResolver) != null) || ((rcc = context as ResolveContextConstant) != null && (icr = rcc.Constant as ICustomResolver) != null)) return new ResolveContextConstant(icr.Resolve(simpleNameIdentifier.Name)); // Is it a type? if (context == null || context is ResolveContextNamespace || context is ResolveContextType) { IEnumerable<Type> searchTypes; if (context is ResolveContextType) searchTypes = ((ResolveContextType) context).Type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance); else searchTypes = candidatePrefixes.SelectMany(prf => _assemblies.SelectMany(a => a.GetTypes()).Where(t => t.Namespace == prf)); foreach (var type in searchTypes.Where(t => t.Name == simpleNameIdentifier.Name)) { if (simpleNameIdentifier.GenericTypeArguments == null && !type.IsGenericType) return new ResolveContextType(type); if (simpleNameIdentifier.GenericTypeArguments != null && type.IsGenericType && type.GetGenericArguments().Length == simpleNameIdentifier.GenericTypeArguments.Count) return new ResolveContextType(type.MakeGenericType(simpleNameIdentifier.GenericTypeArguments.Select(tn => ResolveType(tn)).ToArray())); } } Type typeInContext = context == null ? _currentType : context.ExpressionType; if (typeInContext != null) { var parent = context ?? (_currentInstance != null ? (ResolveContext) new ResolveContextConstant(_currentInstance) : new ResolveContextType(_currentType)); if (simpleNameIdentifier.GenericTypeArguments == null) { bool expectStatic = (context == null && _currentInstance == null) || (context is ResolveContextType); // Is it a field or an event? (GetFields() finds the backing field of the event, which has the same name as the event) foreach (var field in typeInContext.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).Where(f => f.Name == simpleNameIdentifier.Name)) { if (field.IsStatic != expectStatic) throw new InvalidOperationException("Cannot access instance field through type name or static field through instance."); return new ResolveContextExpression(Expression.Field(field.IsStatic ? null : parent.ToExpression(), field)); } // Is it a non-indexed property? foreach (var property in typeInContext.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).Where(p => p.Name == simpleNameIdentifier.Name && p.GetIndexParameters().Length == 0)) { bool isStatic = property.GetGetMethod() != null ? property.GetGetMethod().IsStatic : property.GetSetMethod().IsStatic; if (isStatic != expectStatic) throw new InvalidOperationException("Cannot access instance property through type name or static property through instance."); return new ResolveContextExpression(Expression.Property(isStatic ? null : parent.ToExpression(), property)); } } // Is it a method group? var methodList = new List<MethodGroupMember>(); foreach (var method in typeInContext.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).Where(m => m.Name == simpleNameIdentifier.Name)) { if (simpleNameIdentifier.GenericTypeArguments == null) methodList.Add(new MethodGroupMember(method, isExtensionMethod: false)); else if (simpleNameIdentifier.GenericTypeArguments != null && method.IsGenericMethod && method.GetGenericArguments().Length == simpleNameIdentifier.GenericTypeArguments.Count) methodList.Add(new MethodGroupMember(method.MakeGenericMethod(simpleNameIdentifier.GenericTypeArguments.Select(tn => ResolveType(tn)).ToArray()), isExtensionMethod: false)); } // Is it an extension method? foreach (var method in _assemblies.SelectMany(a => a.GetTypes()).SelectMany(t => t.GetMethods(BindingFlags.Public | BindingFlags.Static)).Where(m => m.Name == simpleNameIdentifier.Name && m.IsDefined(typeof(ExtensionAttribute), false))) { var prms = method.GetParameters(); if (prms.Length == 0) continue; if (simpleNameIdentifier.GenericTypeArguments == null) methodList.Add(new MethodGroupMember(method, isExtensionMethod: true)); else if (simpleNameIdentifier.GenericTypeArguments != null && method.IsGenericMethod && method.GetGenericArguments().Length == simpleNameIdentifier.GenericTypeArguments.Count) methodList.Add(new MethodGroupMember(method.MakeGenericMethod(simpleNameIdentifier.GenericTypeArguments.Select(tn => ResolveType(tn)).ToArray()), isExtensionMethod: true)); } if (methodList.Count > 0) return new ResolveContextMethodGroup(parent, methodList, simpleNameIdentifier.Name); } throw new InvalidOperationException("The name “{0}” could not be resolved.".Fmt(simpleName)); }
public ResolveContextMethodGroup(ResolveContext parent, List<MethodGroupMember> methodGroup, string name) : base() { Parent = parent; MethodGroup = methodGroup; MethodName = name; }