Example #1
0
        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);
        }
Example #2
0
        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));
        }
Example #3
0
 public ResolveContextMethodGroup(ResolveContext parent, List<MethodGroupMember> methodGroup, string name)
     : base()
 {
     Parent = parent; MethodGroup = methodGroup; MethodName = name;
 }