public Compiler(DocProject project, DocModelView[] views, DocExchangeDefinition exchange, bool psets) { this.m_project = project; this.m_views = views; this.m_exchange = exchange; this.m_psets = psets; // version needs to be included for extracting XML namespace (Major.Minor.Addendum.Corrigendum) string version = project.GetSchemaVersion(); ConstructorInfo conContract = (typeof(AssemblyVersionAttribute).GetConstructor(new Type[] { typeof(string) })); CustomAttributeBuilder cabAssemblyVersion = new CustomAttributeBuilder(conContract, new object[] { version }); string schemaid = project.GetSchemaIdentifier(); string assembly = "buildingSmart." + schemaid; string module = assembly + ".dll"; this.m_rootnamespace = assembly + "."; this.m_assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(assembly), AssemblyBuilderAccess.RunAndSave, new CustomAttributeBuilder[] { cabAssemblyVersion }); this.m_module = this.m_assembly.DefineDynamicModule(module, module); this.m_definitions = new Dictionary <string, DocObject>(); this.m_types = new Dictionary <string, Type>(); this.m_fields = new Dictionary <Type, Dictionary <string, FieldInfo> >(); this.m_templates = new Dictionary <DocTemplateDefinition, MethodInfo>(); this.m_namespaces = new Dictionary <string, string>(); Dictionary <DocObject, bool> included = null; if (this.m_views != null) { included = new Dictionary <DocObject, bool>(); foreach (DocModelView docView in this.m_views) { this.m_project.RegisterObjectsInScope(docView, included); } } if (psets) { foreach (DocPropertyEnumeration docPropEnum in project.PropertyEnumerations) { DocEnumeration docType = docPropEnum.ToEnumeration(); if (!this.m_definitions.ContainsKey(docType.Name)) { this.m_definitions.Add(docType.Name, docType); } } } foreach (DocSection docSection in project.Sections) { foreach (DocSchema docSchema in docSection.Schemas) { foreach (DocEntity docEntity in docSchema.Entities) { if (included == null || included.ContainsKey(docEntity)) { if (!this.m_definitions.ContainsKey(docEntity.Name)) { this.m_definitions.Add(docEntity.Name, docEntity); this.m_namespaces.Add(docEntity.Name, docSchema.Name); } } } foreach (DocType docType in docSchema.Types) { if (included == null || included.ContainsKey(docType)) { if (!this.m_definitions.ContainsKey(docType.Name)) { this.m_definitions.Add(docType.Name, docType); this.m_namespaces.Add(docType.Name, docSchema.Name); } } } } } // second pass: if (psets) { foreach (DocSection docSection in project.Sections) { foreach (DocSchema docSchema in docSection.Schemas) { foreach (DocPropertySet docPset in docSchema.PropertySets) { DocEntity docType = docPset.ToEntity(this.m_definitions); if (!this.m_definitions.ContainsKey(docType.Name)) { this.m_definitions.Add(docType.Name, docType); this.m_namespaces.Add(docType.Name, docSchema.Name); } } foreach (DocQuantitySet docQset in docSchema.QuantitySets) { DocEntity docType = docQset.ToEntity(this.m_definitions); if (!this.m_definitions.ContainsKey(docType.Name)) { this.m_definitions.Add(docType.Name, docType); this.m_namespaces.Add(docType.Name, docSchema.Name); } } } } } // first register types and fields foreach (string key in this.m_definitions.Keys) { Type typereg = RegisterType(key); // localization -- use custom attributes for now -- ideal way would be to use assembly resources, though has bugs in .net 4.0 if (typereg is TypeBuilder) { TypeBuilder tb = (TypeBuilder)typereg; DocObject docObj = this.m_definitions[key]; foreach (DocLocalization docLocal in docObj.Localization) { CustomAttributeBuilder cab = docLocal.ToCustomAttributeBuilder(); if (cab != null) { tb.SetCustomAttribute(cab); } } } } // now register template functions (may depend on fields existing) // find associated ConceptRoot for model view, define validation function if (this.m_views != null) { foreach (DocModelView view in this.m_views) { string viewname = view.Code; foreach (DocConceptRoot root in view.ConceptRoots) { Type tOpen = null; if (this.m_types.TryGetValue(root.ApplicableEntity.Name, out tOpen) && tOpen is TypeBuilder) { TypeBuilder tb = (TypeBuilder)tOpen; // new: generate type for concept root //if (view.Name != null && root.Name != null) { /* * string typename = this.m_rootnamespace + "." + view.Name.Replace(" ", "_") + "." + root.Name.Replace(" ", "_"); * //Type tbConceptRoot = RegisterType(typename); * TypeBuilder tbRoot = this.m_module.DefineType(typename, attr, typebase); */ // add typebuilder to map temporarily in case referenced by an attribute within same class or base class //this.m_types.Add(typename, tb); foreach (DocTemplateUsage concept in root.Concepts) { CompileConcept(concept, view, tb); } } } } } } //Dictionary<string, Stream> mapResStreams = new Dictionary<string, Stream>(); //Dictionary<string, ResXResourceWriter> mapResources = new Dictionary<string, ResXResourceWriter>(); // seal types once all are built List <TypeBuilder> listBase = new List <TypeBuilder>(); foreach (string key in this.m_definitions.Keys) { Type tOpen = this.m_types[key]; while (tOpen is TypeBuilder) { listBase.Add((TypeBuilder)tOpen); tOpen = tOpen.BaseType; } // seal in base class order for (int i = listBase.Count - 1; i >= 0; i--) { Type tClosed = listBase[i].CreateType(); this.m_types[tClosed.Name] = tClosed; } listBase.Clear(); // record bindings DocDefinition docDef = this.m_definitions[key] as DocDefinition; if (docDef != null) { docDef.RuntimeType = this.m_types[key]; if (docDef is DocEntity) { DocEntity docEnt = (DocEntity)docDef; foreach (DocAttribute docAttr in docEnt.Attributes) { docAttr.RuntimeField = docDef.RuntimeType.GetProperty(docAttr.Name); } } #if false // bug in .net framework 4.0+ -- can't read resources dynamically defined // capture localization foreach (DocLocalization docLocal in docDef.Localization) { if (!String.IsNullOrEmpty(docLocal.Locale)) { string major = docLocal.Locale.Substring(0, 2).ToLower(); ResXResourceWriter reswriter = null; if (!mapResources.TryGetValue(major, out reswriter)) { MemoryStream stream = new MemoryStream(); mapResStreams.Add(major, stream); reswriter = new ResXResourceWriter(stream); mapResources.Add(major, reswriter); } ResXDataNode node = new ResXDataNode(docDef.Name, docLocal.Name); node.Comment = docLocal.Documentation; reswriter.AddResource(node); } } #endif } } #if false foreach (string locale in mapResStreams.Keys) { ResXResourceWriter writer = mapResources[locale]; writer.Generate(); Stream stream = mapResStreams[locale]; stream.Seek(0, SeekOrigin.Begin); m_module.DefineManifestResource("Resources." + locale + ".resx", stream, ResourceAttributes.Public); } #endif }
public Compiler(DocProject project, DocModelView[] views, DocExchangeDefinition exchange) { this.m_project = project; this.m_views = views; this.m_exchange = exchange; // version needs to be included for extracting XML namespace (Major.Minor.Addendum.Corrigendum) string version = project.GetSchemaVersion(); ConstructorInfo conContract = (typeof(AssemblyVersionAttribute).GetConstructor(new Type[] { typeof(string) })); CustomAttributeBuilder cabAssemblyVersion = new CustomAttributeBuilder(conContract, new object[] { version }); string schemaid = project.GetSchemaIdentifier(); string assembly = "BuildingSmart." + schemaid; string module = assembly + ".dll"; this.m_assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(assembly), AssemblyBuilderAccess.RunAndSave, new CustomAttributeBuilder[] { cabAssemblyVersion }); this.m_module = this.m_assembly.DefineDynamicModule(module, module); this.m_definitions = new Dictionary <string, DocObject>(); this.m_types = new Dictionary <string, Type>(); this.m_fields = new Dictionary <Type, Dictionary <string, FieldInfo> >(); this.m_templates = new Dictionary <DocTemplateDefinition, MethodInfo>(); this.m_namespaces = new Dictionary <string, string>(); Dictionary <DocObject, bool> included = null; if (this.m_views != null) { included = new Dictionary <DocObject, bool>(); foreach (DocModelView docView in this.m_views) { this.m_project.RegisterObjectsInScope(docView, included); } } foreach (DocSection docSection in project.Sections) { foreach (DocSchema docSchema in docSection.Schemas) { foreach (DocEntity docEntity in docSchema.Entities) { if (included == null || included.ContainsKey(docEntity)) { if (!this.m_definitions.ContainsKey(docEntity.Name)) { this.m_definitions.Add(docEntity.Name, docEntity); this.m_namespaces.Add(docEntity.Name, docSchema.Name); } } } foreach (DocType docType in docSchema.Types) { if (included == null || included.ContainsKey(docType)) { if (!this.m_definitions.ContainsKey(docType.Name)) { this.m_definitions.Add(docType.Name, docType); this.m_namespaces.Add(docType.Name, docSchema.Name); } } } } } // first register types and fields foreach (string key in this.m_definitions.Keys) { RegisterType(key); } // now register template functions (may depend on fields existing) // find associated ConceptRoot for model view, define validation function if (this.m_views != null) { foreach (DocModelView view in this.m_views) { string viewname = view.Code; foreach (DocConceptRoot root in view.ConceptRoots) { Type tOpen = null; if (this.m_types.TryGetValue(root.ApplicableEntity.Name, out tOpen) && tOpen is TypeBuilder) { TypeBuilder tb = (TypeBuilder)tOpen; foreach (DocTemplateUsage concept in root.Concepts) { CompileConcept(concept, view, tb); } } } } } // seal types once all are built List <TypeBuilder> listBase = new List <TypeBuilder>(); foreach (string key in this.m_definitions.Keys) { Type tOpen = this.m_types[key]; while (tOpen is TypeBuilder) { listBase.Add((TypeBuilder)tOpen); tOpen = tOpen.BaseType; } // seal in base class order for (int i = listBase.Count - 1; i >= 0; i--) { Type tClosed = listBase[i].CreateType(); this.m_types[tClosed.Name] = tClosed; } listBase.Clear(); // record bindings DocDefinition docDef = this.m_definitions[key] as DocDefinition; if (docDef != null) { docDef.RuntimeType = this.m_types[key]; if (docDef is DocEntity) { DocEntity docEnt = (DocEntity)docDef; foreach (DocAttribute docAttr in docEnt.Attributes) { docAttr.RuntimeField = docDef.RuntimeType.GetField(docAttr.Name); } } } } }