Exemplo n.º 1
0
        public CapnpType ResolveFullName(FullName fullName)
        {
            // Find the first scope in which to start looking.
            CapnpComposite startScope = this;
            CapnpType      result     = null;

            for (var scope = startScope; scope != null; scope = scope.Scope)
            {
                result = scope._ResolveName(fullName[0], this, null);
                if (result != null)
                {
                    break;
                }
            }

            if (result == null || fullName.Count == 1)
            {
                return(result);
            }

            // Resolve rest.
            var container = result;

            for (var i = 1; i < fullName.Count; i++)
            {
                if (container is CapnpBoundGenericType)
                {
                    var generic = (CapnpBoundGenericType)container;
                    container = ((CapnpGenericType)generic.OpenType)._ResolveName(fullName[i], this, generic); // todo: this cast should succeed with correct grammar, but perhaps may fail with a bad one

                    // If the reference is to a generic parameter it must resolve.
                    // Note that if the type is still open it could resolve to a generic parameter.
                    if (container is CapnpGenericParameter)
                    {
                        container = generic.ResolveGenericParameter((CapnpGenericParameter)container);
                    }

                    if (container == null)
                    {
                        return(null);
                    }
                }
                else if (container is CapnpComposite)
                {
                    container = ((CapnpComposite)container)._ResolveName(fullName[i].Name);
                    if (container == null)
                    {
                        return(null);
                    }
                }
                else
                {
                    return(null);
                }
            }
            return(container);
        }
Exemplo n.º 2
0
        private CapnpType _ResolveName(NamePart part, CapnpComposite nameScope, CapnpBoundGenericType genericScope = null)
        {
            var result = _ResolveName(part.Name);

            if (result == null)
            {
                // Todo: this is somewhat "bolted" on, can we unify with generics?
                if (part.Name == "List" && part.TypeParameters.Length == 1)
                {
                    var param = nameScope.ResolveFullName(part.TypeParameters[0]);
                    if (param == null)
                    {
                        return(null);
                    }
                    return(new CapnpList
                    {
                        Parameter = param
                    });
                }
            }

            // E.g. an unresolved Using.
            if (result is CapnpReference)
            {
                return(result);
            }

            if (result is CapnpGenericType)
            {
                // Resolve generic parameters given our generic state.
                // Note that the name could refer to a generic parameter creating a *partially closed* type.
                var generic = (CapnpGenericType)result;

                // We don't allow *partial* closing of a generic type (there's no syntax for it).
                if (generic.TypeParameters.Length != part.TypeParameters.Length && part.TypeParameters.Length > 0)
                {
                    return(null);
                }

                // Nothing to parameterize.
                if (generic.TypeParameters.Length == 0 && part.TypeParameters.Length > 0)
                {
                    return(null);
                }

                // If the type does not actually have generic parameters, and we're not a nested type of a generic type, we're done.
                if (!generic.IsGeneric && genericScope == null)
                {
                    return(result);
                }

                Debug.Assert(generic.TypeParameters.Length == part.TypeParameters.Length || part.TypeParameters.Length == 0);

                var resolvedParams = part.TypeParameters.Length == 0 ? generic.TypeParameters : // the type is fully open
                                     part.TypeParameters.Select(p => nameScope.ResolveFullName(p)).ToArray();

                // If any of the type parameters are unresolved, we have to wait.
                if (resolvedParams.Any(p => p == null || p is CapnpReference))
                {
                    return(null);
                }

                // The generic scope is the scope in which generic parameters our bound.
                // If none are defined the parent scope is closed using just the generic parameters.
                var parentScope = genericScope ?? generic.Scope.MakeOpenGenericType();

                return(new CapnpBoundGenericType
                {
                    OpenType = generic,
                    ParentScope = parentScope,
                    TypeParameters = resolvedParams
                });
            }
            else if (result is CapnpBoundGenericType)
            {
                var closed = (CapnpBoundGenericType)result;

                if (part.TypeParameters.Length > 0 && closed.TypeParameters.Length != part.TypeParameters.Length)
                {
                    return(null);
                }

                var resolvedParams = closed.TypeParameters;

                if (part.TypeParameters.Length > 0)
                {
                    // Cannot be partially closed and it makes no sense to close an already fully closed generic type
                    Debug.Assert(closed.TypeParameters.All(p => (p is CapnpGenericParameter)));

                    resolvedParams = part.TypeParameters.Select(p => nameScope.ResolveFullName(p)).ToArray();
                    if (resolvedParams.Any(p => p == null || p is CapnpReference))
                    {
                        return(null);
                    }
                }

                // Return a new closed generic whose scope is the current genericScope if defined.
                // Note that in the case both genericScope and clode.ParentScope exist, genericScope is "more closed" but point
                // to the same open type.
                Debug.Assert(genericScope == null || closed.ParentScope == null || genericScope.OpenType == closed.ParentScope.OpenType);

                return(new CapnpBoundGenericType
                {
                    OpenType = closed.OpenType,
                    ParentScope = genericScope ?? closed.ParentScope,
                    TypeParameters = resolvedParams
                });
            }
            else if (part.TypeParameters.Length > 0)
            {
                // The name defines generic parameters but the type is not generic.
                return(null);
            }
            else if (result is CapnpGenericParameter)
            {
                return(result);
            }
            else if (genericScope != null)
            {
                // An annotation or enumeration or whatever contained within a generic struct is itself generic.
                return(new CapnpBoundGenericType
                {
                    OpenType = (CapnpNamedType)result,
                    ParentScope = genericScope,
                    TypeParameters = Empty <CapnpType> .Array
                });
            }
            else
            {
                return(result);
            }
        }