Beispiel #1
0
 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;
 }
Beispiel #2
0
 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;
         }
     }
 }
Beispiel #3
0
        /// <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());
            }
        }
Beispiel #4
0
 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));
     }
 }
Beispiel #5
0
        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));
            }
        }
Beispiel #6
0
 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());
     }
 }
Beispiel #7
0
 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;
         }
     }
 }
Beispiel #8
0
 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());
     }
 }
Beispiel #9
0
        /// <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;
                            }
                        }
                    }
                }
            }
        }
Beispiel #10
0
 /// <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;
     }
 }
Beispiel #11
0
        /// <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);
            }
        }
Beispiel #12
0
            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;
            }
Beispiel #13
0
        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());
        }
Beispiel #14
0
            /// <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);
            }
Beispiel #15
0
        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;
        }