// Take either an XML type declaration or a type.dotident element, and return the associated // TypeDeclaration instance if it is declared somewhere in the XML, null otherwise public static TypeDeclaration New(XElement elem, Container <Declaration> super, TypeScriptDefContext context) { // If the argument passed is an XML type declaration, we don't search // in the XML and directly return the associated instance if (TypeDeclaration.GetClass(elem) != null) { return(TypeDeclaration.GetInstance(elem, super, context)); } string[] name = elem.Attribute("text").Value.Split('.'); XElement parent; TypeDeclaration typeDeclaration = null; do { // We check if there is a declaration in the current namespace parent = elem.Ancestors().FirstOrDefault(e => TypeDeclaration.IsTypeDeclarationContainer(e)); if (parent != null) { typeDeclaration = TypeDeclaration.New(name, parent, super, context); elem = parent; } } // If not, we check in the parent namespace, and if not in the parent of the parent, // and so on until we reach the root namespace while (typeDeclaration == null && parent != null); return(typeDeclaration); }
// Return the TypeDeclaration instance associated with a given XML type declaration, // or a newly created one that is added to the dictionary if it doesn't exist private static TypeDeclaration GetInstance(XElement elem, Container <Declaration> super, TypeScriptDefContext context) { Type typeDeclarationClass = TypeDeclaration.GetClass(elem); string typeDeclarationName = TypeDeclaration.GetFullName(elem); try { var inst = TypeDeclaration.Instances[typeDeclarationName]; // We update the declaration's Super if it wasn't specified previously // (needed for type declarations instanciated because of a variable of that type) if (inst.Super == null) { inst.Super = super; } return(inst); } catch (KeyNotFoundException) { var inst = (TypeDeclaration)Activator.CreateInstance(typeDeclarationClass, elem, super, context); TypeDeclaration.Instances[typeDeclarationName] = inst; // We add content after updating the dictionary to avoid cycles // when declarations refer to their ancestors if (inst is Container <Declaration> ) { ((Container <Declaration>)inst).AddContent(elem, context); } return(inst); } }
// Check if a given type name is declared somewhere in a given XML subtree, // and return the associated TypeDeclaration instance if it is, null otherwise private static TypeDeclaration New(string[] name, XElement root, Container <Declaration> super, TypeScriptDefContext context) { // We create a list of the elements we're going to inspect var elems = new List <XElement>(); // First we inspect the root itself (except if it is the global namespace) if (root.Name.LocalName != "start") { elems.Add(root); } // If there is no declaration directly in the root, we inspect its children IEnumerable <XElement> children; // We need to handle the special case of namespace elements, // which do not hold their declarations as direct children if (root.Name.LocalName == "namespace") { children = root.Element("namespacecontent").Elements(); } else { children = root.Elements(); } elems.AddRange(children); // Then for each element in the list foreach (XElement e in elems) { // First we make sure that it correponds either to a TypeDeclaration or a Container<TypeDeclaration> Type typeDeclarationClass = TypeDeclaration.GetClass(e); bool isTypeDeclarationContainer = TypeDeclaration.IsTypeDeclarationContainer(e); if (typeDeclarationClass != null || isTypeDeclarationContainer) { // The element identifier must be at most as long as the type name string[] ident = Tool.GetIdent(e).Split('.'); if (ident.Length <= name.Length) { // If the hole identifier matches the beginning of the name int match = ident.ToList().FirstMismatchIndex(name.ToList()); if (match == ident.Length) { // Either the beginning is actually the type (local) name... if (name.Length == 1) { // ...and if the element is associated with a TypeDeclaration class, // it means we have found a valid declaration, so we return an instance of said class if (typeDeclarationClass != null) { return(TypeDeclaration.GetInstance(e, super, context)); } } // Or the beginning is just the name of an ancestor container... else if (isTypeDeclarationContainer) { // ...and therefore we call the method recursively on the element var res = TypeDeclaration.New(name.Skip(match).ToArray(), e, super, context); // If we found a valid declaration during the recursive call, we return it if (res != null) { return(res); } // Otherwise there might be another container with the same name, so we keep searching. // For example it is possible that class a.b does not contain the declaration, // while namespace a.b, which is going to be merged with class a.b by the compiler, does contain it. } } } } } // If there is no element containing a declaration, we return null return(null); }