private static bool TryConvertArg(object arg, Type type, out object result, Parser parser, IScriptExtent errorExtent) { // This code could be added to LanguagePrimitives.ConvertTo if (arg != null && arg.GetType() == type) { result = arg; return true; } if (!LanguagePrimitives.TryConvertTo(arg, type, out result)) { parser.ReportError(errorExtent, () => ParserStrings.CannotConvertValue, ToStringCodeMethods.Type(type)); return false; } return true; }
internal static void CheckArrayTypeNameDepth(ITypeName typeName, IScriptExtent extent, Parser parser) { int num = 0; for (ITypeName name = typeName; !(name is TypeName); name = ((ArrayTypeName) name).ElementType) { num++; if (num > 200) { parser.ReportError(extent, ParserStrings.ScriptTooComplicated, new object[0]); return; } if (!(name is ArrayTypeName)) { break; } } }
/// <summary> /// Check the script block to see if it uses any language constructs not allowed in restricted language mode. /// </summary> /// <param name="allowedCommands">The commands that are allowed.</param> /// <param name="allowedVariables"> /// The variables allowed in this scriptblock. If this is null, then the default variable set /// will be allowed. If it is an empty list, no variables will be allowed. If it is "*" then /// any variable will be allowed. /// </param> /// <param name="allowEnvironmentVariables">The environment variables that are allowed.</param> public void CheckRestrictedLanguage(IEnumerable<string> allowedCommands, IEnumerable<string> allowedVariables, bool allowEnvironmentVariables) { Parser parser = new Parser(); var ast = AstInternal; if (HasBeginBlock || HasProcessBlock || ast.Body.ParamBlock != null) { Ast errorAst = ast.Body.BeginBlock ?? (Ast)ast.Body.ProcessBlock ?? ast.Body.ParamBlock; parser.ReportError(errorAst.Extent, () => ParserStrings.InvalidScriptBlockInDataSection); } if (HasEndBlock) { RestrictedLanguageChecker rlc = new RestrictedLanguageChecker(parser, allowedCommands, allowedVariables, allowEnvironmentVariables); var endBlock = ast.Body.EndBlock; StatementBlockAst.InternalVisit(rlc, endBlock.Traps, endBlock.Statements, AstVisitAction.Continue); } if (parser.ErrorList.Any()) { throw new ParseException(parser.ErrorList.ToArray()); } }
internal void AddType(Parser parser, TypeDefinitionAst typeDefinitionAst) { TypeLookupResult result; if (_typeTable.TryGetValue(typeDefinitionAst.Name, out result)) { if (result.ExternalNamespaces != null) { // override external type by the type defined in the current namespace result.ExternalNamespaces = null; result.Type = typeDefinitionAst; } else { parser.ReportError(typeDefinitionAst.Extent, () => ParserStrings.MemberAlreadyDefined, typeDefinitionAst.Name); } } else { _typeTable.Add(typeDefinitionAst.Name, new TypeLookupResult(typeDefinitionAst)); } }
internal void AddTypeFromUsingModule(Parser parser, TypeDefinitionAst typeDefinitionAst, PSModuleInfo moduleInfo) { TypeLookupResult result; if (_typeTable.TryGetValue(typeDefinitionAst.Name, out result)) { if (result.ExternalNamespaces != null) { // override external type by the type defined in the current namespace result.ExternalNamespaces.Add(moduleInfo.Name); } } else { var newLookupEntry = new TypeLookupResult(typeDefinitionAst) { ExternalNamespaces = new List<string>() }; newLookupEntry.ExternalNamespaces.Add(moduleInfo.Name); _typeTable.Add(typeDefinitionAst.Name, newLookupEntry); } string fullName = SymbolResolver.GetModuleQualifiedName(moduleInfo.Name, typeDefinitionAst.Name); if (_typeTable.TryGetValue(fullName, out result)) { parser.ReportError(typeDefinitionAst.Extent, () => ParserStrings.MemberAlreadyDefined, fullName); } else { _typeTable.Add(fullName, new TypeLookupResult(typeDefinitionAst)); } }
public void CheckRestrictedLanguage(IEnumerable<string> allowedCommands, IEnumerable<string> allowedVariables, bool allowEnvironmentVariables) { Parser parser = new Parser(); if (this.HasBeginBlock || this.HasProcessBlock || this._ast.Body.ParamBlock != null) { NamedBlockAst beginBlock = this._ast.Body.BeginBlock; Ast paramBlock = beginBlock; if (beginBlock == null) { NamedBlockAst processBlock = this._ast.Body.ProcessBlock; paramBlock = processBlock; if (processBlock == null) { paramBlock = this._ast.Body.ParamBlock; } } Ast ast = paramBlock; parser.ReportError(ast.Extent, ParserStrings.InvalidScriptBlockInDataSection, new object[0]); } if (this.HasEndBlock) { RestrictedLanguageChecker restrictedLanguageChecker = new RestrictedLanguageChecker(parser, allowedCommands, allowedVariables, allowEnvironmentVariables); NamedBlockAst endBlock = this._ast.Body.EndBlock; StatementBlockAst.InternalVisit(restrictedLanguageChecker, endBlock.Traps, endBlock.Statements, AstVisitAction.Continue); } if (!parser.ErrorList.Any<ParseError>()) { return; } else { throw new ParseException(parser.ErrorList.ToArray()); } }
internal static void CheckArrayTypeNameDepth(ITypeName typeName, IScriptExtent extent, Parser parser) { int count = 0; ITypeName type = typeName; while ((type is TypeName) == false) { count++; if (count > 200) { parser.ReportError(extent, () => ParserStrings.ScriptTooComplicated); break; } if (type is ArrayTypeName) { type = ((ArrayTypeName)type).ElementType; } else { break; } } }
internal static void CheckDataStatementLanguageModeAtRuntime(DataStatementAst dataStatementAst, ExecutionContext executionContext) { // If we get here, we have already determined the data statement invokes commands, so // we only need to check the language mode. if (executionContext.LanguageMode == PSLanguageMode.ConstrainedLanguage) { var parser = new Parser(); parser.ReportError(dataStatementAst.CommandsAllowed[0].Extent, () => ParserStrings.DataSectionAllowedCommandDisallowed); throw new ParseException(parser.ErrorList.ToArray()); } }
/// <summary> /// True if it is a key property. /// </summary> /// <param name="parser"></param> /// <param name="propertyMemberAst">The property member AST</param> /// <param name="hasKey">True if it is a key property; otherwise, false.</param> private static void CheckKey(Parser parser, PropertyMemberAst propertyMemberAst, ref bool hasKey) { foreach (var attr in propertyMemberAst.Attributes) { if (attr.TypeName.GetReflectionAttributeType() == typeof(DscPropertyAttribute)) { foreach (var na in attr.NamedArguments) { if (na.ArgumentName.Equals("Key", StringComparison.OrdinalIgnoreCase)) { object attrArgValue; if (IsConstantValueVisitor.IsConstant(na.Argument, out attrArgValue, forAttribute: true, forRequires: false) && LanguagePrimitives.IsTrue(attrArgValue)) { hasKey = true; bool keyPropertyTypeAllowed = false; var propertyType = propertyMemberAst.PropertyType; if (propertyType != null) { TypeName typeName = propertyType.TypeName as TypeName; if (typeName != null) { var type = typeName.GetReflectionType(); if (type != null) { keyPropertyTypeAllowed = type == typeof(string) || type.IsInteger(); } else { var typeDefinitionAst = typeName._typeDefinitionAst; if (typeDefinitionAst != null) { keyPropertyTypeAllowed = typeDefinitionAst.IsEnum; } } } } if (!keyPropertyTypeAllowed) { parser.ReportError(propertyMemberAst.Extent, () => ParserStrings.DscResourceInvalidKeyProperty); } return; } } } } } }
/// <summary> /// Check if it is a Get method with correct return type and signature /// </summary> /// <param name="parser"></param> /// <param name="functionMemberAst">The function member AST</param> /// <param name="hasGet">True if it is a Get method with qualified return type and signature; otherwise, false. </param> private static void CheckGet(Parser parser, FunctionMemberAst functionMemberAst, ref bool hasGet) { if (hasGet) { return; } if (functionMemberAst.Name.Equals("Get", StringComparison.OrdinalIgnoreCase) && functionMemberAst.Parameters.Count == 0) { if (functionMemberAst.ReturnType != null) { // Return type is of the class we're defined in //it must return the class type, or array of the class type. var arrayTypeName = functionMemberAst.ReturnType.TypeName as ArrayTypeName; var typeName = (arrayTypeName != null ? arrayTypeName.ElementType : functionMemberAst.ReturnType.TypeName) as TypeName; if (typeName == null || typeName._typeDefinitionAst != functionMemberAst.Parent) { parser.ReportError(functionMemberAst.Extent, () => ParserStrings.DscResourceInvalidGetMethod, ((TypeDefinitionAst)functionMemberAst.Parent).Name); } } else { parser.ReportError(functionMemberAst.Extent, () => ParserStrings.DscResourceInvalidGetMethod, ((TypeDefinitionAst)functionMemberAst.Parent).Name); } //Set hasGet to true to stop look up; it may have invalid get hasGet = true; return; } }
/// <summary> /// Check if it is a qualified DSC resource type /// </summary> /// <param name="parser"></param> /// <param name="typeDefinitionAst"></param> /// <param name="dscResourceAttributeAst"></param> internal static void CheckType(Parser parser, TypeDefinitionAst typeDefinitionAst, AttributeAst dscResourceAttributeAst) { bool hasSet = false; bool hasTest = false; bool hasGet = false; bool hasDefaultCtor = false; bool hasNonDefaultCtor = false; bool hasKey = false; Diagnostics.Assert(dscResourceAttributeAst != null, "CheckType called only for DSC resources. dscResourceAttributeAst must be non-null."); foreach (var member in typeDefinitionAst.Members) { var functionMemberAst = member as FunctionMemberAst; if (functionMemberAst != null) { CheckSet(functionMemberAst, ref hasSet); CheckGet(parser, functionMemberAst, ref hasGet); CheckTest(functionMemberAst, ref hasTest); if (functionMemberAst.IsConstructor && !functionMemberAst.IsStatic) { if (functionMemberAst.Parameters.Count == 0) { hasDefaultCtor = true; } else { hasNonDefaultCtor = true; } } } else { var propertyMemberAst = (PropertyMemberAst)member; CheckKey(parser, propertyMemberAst, ref hasKey); } } if (typeDefinitionAst.BaseTypes != null && (!hasSet || !hasGet || !hasTest || !hasKey)) { LookupRequiredMembers(parser, typeDefinitionAst, ref hasSet, ref hasGet, ref hasTest, ref hasKey); } var name = typeDefinitionAst.Name; if (!hasSet) { parser.ReportError(dscResourceAttributeAst.Extent, () => ParserStrings.DscResourceMissingSetMethod, name); } if (!hasGet) { parser.ReportError(dscResourceAttributeAst.Extent, () => ParserStrings.DscResourceMissingGetMethod, name); } if (!hasTest) { parser.ReportError(dscResourceAttributeAst.Extent, () => ParserStrings.DscResourceMissingTestMethod, name); } if (!hasDefaultCtor && hasNonDefaultCtor) { parser.ReportError(dscResourceAttributeAst.Extent, () => ParserStrings.DscResourceMissingDefaultConstructor, name); } if (!hasKey) { parser.ReportError(dscResourceAttributeAst.Extent, () => ParserStrings.DscResourceMissingKeyProperty, name); } }
internal static List<DefineEnumHelper> Sort(List<DefineEnumHelper> defineEnumHelpers, Parser parser) { // This function does a topological sort of the enums to be defined. This is needed so we // can allow one enum member to use the value of another w/o needing to worry about the order // they are declared in. For example: // // enum E1 { e1 = [E2]::e2 } // enum E2 { e2 = 42 } // // We also want to report an error for recursive expressions, e.g. // // enum E1 { e1 = [E2]::e2 } // enum E2 { e2 = [E1]::e1 } // // Note that this code is not as permissive as it could be, e.g. we could (but do not) allow: // // enum E1 { e1 = [E2]::e2 } // enum E2 { // e2 = 42 // e2a = [E1]::e1 // } // // In this case, there is no cycle in the constant values despite E1 referencing E2 and vice versa. // // The basic algorithm is to create a graph where the edges represent a dependency, using this example: // // enum E1 { e1 = [E2]::e2 } // enum E2 { e2 = 42 } // // We have an edge E1->E2. E2 has no dependencies. if (defineEnumHelpers.Count == 1) { return defineEnumHelpers; } // There won't be many nodes in our graph, so we just use a dictionary with a list of edges instead // of something cleaner. var graph = new Dictionary<TypeDefinitionAst, Tuple<DefineEnumHelper, List<TypeDefinitionAst>>>(); // Add all of our nodes to the graph foreach (var helper in defineEnumHelpers) { graph.Add(helper._enumDefinitionAst, Tuple.Create(helper, new List<TypeDefinitionAst>())); } // Now find any edges. foreach (var helper in defineEnumHelpers) { foreach (var enumerator in helper._enumDefinitionAst.Members) { var initExpr = ((PropertyMemberAst)enumerator).InitialValue; if (initExpr == null) { // No initializer, so no dependency (this is incorrect assumption if // we wanted to be more general like C#.) continue; } // The expression may have multiple member expressions, e.g. [E]::e1 + [E]::e2 foreach (var memberExpr in initExpr.FindAll(ast => ast is MemberExpressionAst, false)) { var typeExpr = ((MemberExpressionAst)memberExpr).Expression as TypeExpressionAst; if (typeExpr != null) { // We only want to add edges for enums being defined in the current scope. // We detect this by seeing if the ast is in our graph or not. var typeName = typeExpr.TypeName as TypeName; if (typeName != null && typeName._typeDefinitionAst != null && typeName._typeDefinitionAst != helper._enumDefinitionAst // Don't add self edges && graph.ContainsKey(typeName._typeDefinitionAst)) { var edgeList = graph[helper._enumDefinitionAst].Item2; if (!edgeList.Contains(typeName._typeDefinitionAst)) // Only add 1 edge per enum { edgeList.Add(typeName._typeDefinitionAst); } } } } } } // Our graph is built. The ready list will hold nodes that don't depend on anything not already // in the result list. We start with a list of nodes with no edges (no dependencies). var result = new List<DefineEnumHelper>(defineEnumHelpers.Count); var readyList = new List<DefineEnumHelper>(defineEnumHelpers.Count); readyList.AddRange(from value in graph.Values where value.Item2.Count == 0 select value.Item1); while (readyList.Count > 0) { var node = readyList[readyList.Count - 1]; readyList.RemoveAt(readyList.Count - 1); result.Add(node); // Remove all edges to this node as it is in our result list now. foreach (var value in graph.Values) { value.Item2.Remove(node._enumDefinitionAst); // If we removed the last edge, we can put this node on the ready list (assuming it // wasn't already there or in our result list.) if (value.Item2.Count == 0 && !result.Contains(value.Item1) && !readyList.Contains(value.Item1)) { readyList.Add(value.Item1); } } } if (result.Count < defineEnumHelpers.Count) { // There was a cycle, report an error on each enum. foreach (var helper in defineEnumHelpers) { if (!result.Contains(helper)) { parser.ReportError(helper._enumDefinitionAst.Extent, () => ParserStrings.CycleInEnumInitializers); } } } else { Diagnostics.Assert(result.Count == defineEnumHelpers.Count, "Logic error if we have more outgoing results than incoming"); } return result; }
private static CustomAttributeBuilder GetAttributeBuilder(Parser parser, AttributeAst attributeAst, AttributeTargets attributeTargets) { var attributeType = attributeAst.TypeName.GetReflectionAttributeType(); Diagnostics.Assert(attributeType != null, "Semantic checks should have verified attribute type exists"); Diagnostics.Assert( attributeType.GetTypeInfo().GetCustomAttribute<AttributeUsageAttribute>(true) == null || (attributeType.GetTypeInfo().GetCustomAttribute<AttributeUsageAttribute>(true).ValidOn & attributeTargets) != 0, "Semantic checks should have verified attribute usage"); var positionalArgs = new object[attributeAst.PositionalArguments.Count]; var cvv = new ConstantValueVisitor { AttributeArgument = false }; for (var i = 0; i < attributeAst.PositionalArguments.Count; i++) { var posArg = attributeAst.PositionalArguments[i]; positionalArgs[i] = posArg.Accept(cvv); } var ctorInfos = attributeType.GetConstructors(); var newConstructors = DotNetAdapter.GetMethodInformationArray(ctorInfos); string errorId = null; string errorMsg = null; bool expandParamsOnBest; bool callNonVirtually; var positionalArgCount = positionalArgs.Length; var bestMethod = Adapter.FindBestMethod(newConstructors, null, positionalArgs, ref errorId, ref errorMsg, out expandParamsOnBest, out callNonVirtually); if (bestMethod == null) { parser.ReportError(new ParseError(attributeAst.Extent, errorId, string.Format(CultureInfo.InvariantCulture, errorMsg, attributeType.Name, attributeAst.PositionalArguments.Count))); return null; } var constructorInfo = (ConstructorInfo)bestMethod.method; var parameterInfo = constructorInfo.GetParameters(); var ctorArgs = new object[parameterInfo.Length]; object arg; for (var argIndex = 0; argIndex < parameterInfo.Length; ++argIndex) { var resultType = parameterInfo[argIndex].ParameterType; // The extension method 'CustomAttributeExtensions.GetCustomAttributes(ParameterInfo, Type, Boolean)' has inconsistent // behavior on its return value in both FullCLR and CoreCLR. According to MSDN, if the attribute cannot be found, it // should return an empty collection. However, it returns null in some rare cases [when the parameter isn't backed by // actual metadata]. // This inconsistent behavior affects OneCore powershell because we are using the extension method here when compiling // against CoreCLR. So we need to add a null check until this is fixed in CLR. var paramArrayAttrs = parameterInfo[argIndex].GetCustomAttributes(typeof(ParamArrayAttribute), true); if (paramArrayAttrs != null && paramArrayAttrs.Any() && expandParamsOnBest) { var elementType = parameterInfo[argIndex].ParameterType.GetElementType(); var paramsArray = Array.CreateInstance(elementType, positionalArgCount - argIndex); ctorArgs[argIndex] = paramsArray; for (var i = 0; i < paramsArray.Length; ++i, ++argIndex) { if (!TryConvertArg(positionalArgs[argIndex], elementType, out arg, parser, attributeAst.PositionalArguments[argIndex].Extent)) { return null; } paramsArray.SetValue(arg, i); } break; } if (!TryConvertArg(positionalArgs[argIndex], resultType, out arg, parser, attributeAst.PositionalArguments[argIndex].Extent)) { return null; } ctorArgs[argIndex] = arg; } if (attributeAst.NamedArguments.Count == 0) { return new CustomAttributeBuilder(constructorInfo, ctorArgs); } var propertyInfoList = new List<PropertyInfo>(); var propertyArgs = new List<object>(); var fieldInfoList = new List<FieldInfo>(); var fieldArgs = new List<object>(); foreach (var namedArg in attributeAst.NamedArguments) { var name = namedArg.ArgumentName; var members = attributeType.GetMember(name, MemberTypes.Field | MemberTypes.Property, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy); Diagnostics.Assert(members.Length == 1 && (members[0] is PropertyInfo || members[0] is FieldInfo), "Semantic checks should have ensured names attribute argument exists"); arg = namedArg.Argument.Accept(cvv); var propertyInfo = members[0] as PropertyInfo; if (propertyInfo != null) { Diagnostics.Assert(propertyInfo.GetSetMethod() != null, "Semantic checks ensures property is settable"); if (!TryConvertArg(arg, propertyInfo.PropertyType, out arg, parser, namedArg.Argument.Extent)) { return null; } propertyInfoList.Add(propertyInfo); propertyArgs.Add(arg); continue; } var fieldInfo = (FieldInfo)members[0]; Diagnostics.Assert(!fieldInfo.IsInitOnly && !fieldInfo.IsLiteral, "Semantic checks ensures field is settable"); if (!TryConvertArg(arg, fieldInfo.FieldType, out arg, parser, namedArg.Argument.Extent)) { return null; } fieldInfoList.Add(fieldInfo); fieldArgs.Add(arg); } return new CustomAttributeBuilder(constructorInfo, ctorArgs, propertyInfoList.ToArray(), propertyArgs.ToArray(), fieldInfoList.ToArray(), fieldArgs.ToArray()); }
/// <summary> /// Return base class type, never return null. /// </summary> /// <param name="parser"></param> /// <param name="typeDefinitionAst"></param> /// <param name="interfaces">return declared interfaces</param> /// <returns></returns> private Type GetBaseTypes(Parser parser, TypeDefinitionAst typeDefinitionAst, out List<Type> interfaces) { // Define base types and report errors. Type baseClass = null; interfaces = new List<Type>(); // Default base class is System.Object and it has a default ctor. _baseClassHasDefaultCtor = true; if (typeDefinitionAst.BaseTypes.Any()) { // base class var baseTypeAsts = typeDefinitionAst.BaseTypes; var firstBaseTypeAst = baseTypeAsts[0]; if (firstBaseTypeAst.TypeName.IsArray) { parser.ReportError(firstBaseTypeAst.Extent, () => ParserStrings.SubtypeArray, firstBaseTypeAst.TypeName.FullName); // fall to the default base type } else { baseClass = firstBaseTypeAst.TypeName.GetReflectionType(); if (baseClass == null) { parser.ReportError(firstBaseTypeAst.Extent, () => ParserStrings.TypeNotFound, firstBaseTypeAst.TypeName.FullName); // fall to the default base type } else { if (baseClass.GetTypeInfo().IsSealed) { parser.ReportError(firstBaseTypeAst.Extent, () => ParserStrings.SealedBaseClass, baseClass.Name); // ignore base type if it's sealed. baseClass = null; } else if (baseClass.GetTypeInfo().IsGenericType && !baseClass.IsConstructedGenericType) { parser.ReportError(firstBaseTypeAst.Extent, () => ParserStrings.SubtypeUnclosedGeneric, baseClass.Name); // ignore base type, we cannot inherit from unclosed generic. baseClass = null; } else if (baseClass.GetTypeInfo().IsInterface) { // First Ast can represent interface as well as BaseClass. interfaces.Add(baseClass); baseClass = null; } } } if (baseClass != null) { // All PS classes are TypeName instances. // For PS classes we cannot use reflection API, because type is not created yet. var baseTypeName = firstBaseTypeAst.TypeName as TypeName; if (baseTypeName != null) { _baseClassHasDefaultCtor = baseTypeName.HasDefaultCtor(); } else { _baseClassHasDefaultCtor = baseClass.HasDefaultCtor(); } } for (int i = 0; i < baseTypeAsts.Count; i++) { if (baseTypeAsts[i].TypeName.IsArray) { parser.ReportError(baseTypeAsts[i].Extent, () => ParserStrings.SubtypeArray, baseTypeAsts[i].TypeName.FullName); this.HasFatalErrors = true; } } for (int i = 1; i < baseTypeAsts.Count; i++) { if (baseTypeAsts[i].TypeName.IsArray) { parser.ReportError(baseTypeAsts[i].Extent, () => ParserStrings.SubtypeArray, baseTypeAsts[i].TypeName.FullName); } else { Type interfaceType = baseTypeAsts[i].TypeName.GetReflectionType(); if (interfaceType == null) { parser.ReportError(baseTypeAsts[i].Extent, () => ParserStrings.TypeNotFound, baseTypeAsts[i].TypeName.FullName); } else { if (interfaceType.GetTypeInfo().IsInterface) { interfaces.Add(interfaceType); } else { parser.ReportError(baseTypeAsts[i].Extent, () => ParserStrings.InterfaceNameExpected, interfaceType.Name); } } } } } return baseClass ?? typeof(object); }
internal static Assembly DefineTypes(Parser parser, Ast rootAst, TypeDefinitionAst[] typeDefinitions) { Diagnostics.Assert(rootAst.Parent == null, "Caller should only define types from the root ast"); var definedTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase); // First character is a special mark that allows us to cheaply ignore dynamic generated assemblies in ClrFacede.GetAssemblies() // Two replaces at the end are for not-allowed characters. They are replaced by similar-looking chars. string assemblyName = ClrFacade.FIRST_CHAR_PSASSEMBLY_MARK + (string.IsNullOrWhiteSpace(rootAst.Extent.File) ? "powershell" : rootAst.Extent.File .Replace('\\', (char)0x29f9) .Replace('/', (char)0x29f9) .Replace(':', (char)0x0589)); var assembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(assemblyName), AssemblyBuilderAccess.RunAndCollect, GetAssemblyAttributeBuilders()); var module = assembly.DefineDynamicModule(assemblyName); var defineTypeHelpers = new List<DefineTypeHelper>(); var defineEnumHelpers = new List<DefineEnumHelper>(); foreach (var typeDefinitionAst in typeDefinitions) { var typeName = GetClassNameInAssembly(typeDefinitionAst); if (!definedTypes.Contains(typeName)) { definedTypes.Add(typeName); if ((typeDefinitionAst.TypeAttributes & TypeAttributes.Class) == TypeAttributes.Class) { defineTypeHelpers.Add(new DefineTypeHelper(parser, module, typeDefinitionAst, typeName)); } else if ((typeDefinitionAst.TypeAttributes & TypeAttributes.Enum) == TypeAttributes.Enum) { defineEnumHelpers.Add(new DefineEnumHelper(parser, module, typeDefinitionAst, typeName)); } } } // Define enums before classes so members of classes can use these enum types. defineEnumHelpers = DefineEnumHelper.Sort(defineEnumHelpers, parser); foreach (var helper in defineEnumHelpers) { helper.DefineEnum(); } foreach (var helper in defineTypeHelpers) { helper.DefineMembers(); } foreach (var helper in defineTypeHelpers) { Diagnostics.Assert(helper._typeDefinitionAst.Type.GetTypeInfo() is TypeBuilder, "Type should be the TypeBuilder"); bool runtimeTypeAssigned = false; if (!helper.HasFatalErrors) { try { var type = helper._typeBuilder.CreateTypeInfo().AsType(); helper._typeDefinitionAst.Type = type; runtimeTypeAssigned = true; var helperType = helper._staticHelpersTypeBuilder.CreateTypeInfo().AsType(); if (helper._fieldsToInitForMemberFunctions != null) { foreach (var tuple in helper._fieldsToInitForMemberFunctions) { helperType.GetField(tuple.Item1, BindingFlags.NonPublic | BindingFlags.Static) .SetValue(null, tuple.Item2); } } helperType.GetField(s_sessionStateKeeperFieldName, BindingFlags.NonPublic | BindingFlags.Static).SetValue(null, new SessionStateKeeper()); } catch (TypeLoadException e) { // This is a cheap way to get error messages about non-implemented abstract/interface methods (and maybe some other errors). // We use .NET API to perform this check during type creation. // // Presumably this catch could go away when we will not create Type at parse time. // Error checking should be moved/added to semantic checks. parser.ReportError(helper._typeDefinitionAst.Extent, () => ParserStrings.TypeCreationError, helper._typeBuilder.Name, e.Message); } } if (!runtimeTypeAssigned) { // Clean up ast helper._typeDefinitionAst.Type = null; } } return assembly; }