Beispiel #1
0
 public override AstVisitAction VisitDynamicKeywordStatement(DynamicKeywordStatementAst dynamicKeywordStatementAst)
 {
     // SKIP
     // Apparently one can add keywords with [System.Management.Automation.Language.DynamicKeyword]::AddKeyword.
     // This won't work in static analysis.
     // I've never seen a dynamic keyword in the wild yet anyway.
     // Update: it appears in DSC, dynamic keywords are used:
     // Example to test: Configuration cnf { Import-DscResource -Module nx; Node 'lx.a.com' { nxFile ExampleFile { DestinationPath = '/tmp/example'; Contents = "hello world `n"; Ensure = 'Present'; Type = 'File'; } } }; cnf -OutputPath:'C:\temp'
     AstExplainer(dynamicKeywordStatementAst);
     return(base.VisitDynamicKeywordStatement(dynamicKeywordStatementAst));
 }
 public override AstVisitAction VisitDynamicKeywordStatement(DynamicKeywordStatementAst dynamicKeywordStatementAst)
 {
     return(this.VisitDslExpression(dynamicKeywordStatementAst.CommandElements, dynamicKeywordStatementAst.Parent, dynamicKeywordStatementAst.Extent));
 }
Beispiel #3
0
 /// <summary/>
 public virtual object VisitDynamicKeywordStatement(DynamicKeywordStatementAst dynamicKeywordAst) { return null; }
Beispiel #4
0
 public object VisitDynamicKeywordStatement(DynamicKeywordStatementAst dynamicKeywordAst)
 {
     return(false);
 }
Beispiel #5
0
 public override AstVisitAction VisitDynamicKeywordStatement(DynamicKeywordStatementAst ast)
 {
     return(Check(ast));
 }
Beispiel #6
0
 public object VisitDynamicKeywordStatement(DynamicKeywordStatementAst dynamicKeywordAst)
 {
     throw PSTraceSource.NewArgumentException(nameof(dynamicKeywordAst));
 }
Beispiel #7
0
 /// <summary/>
 public virtual AstVisitAction VisitDynamicKeywordStatement(DynamicKeywordStatementAst dynamicKeywordStatementAst) => DefaultVisit(dynamicKeywordStatementAst);
        /// <summary>
        /// Generate auto complete results for identifier within configuration.
        /// Results are generated based on DynamicKeywords matches given identifier.
        /// For example, following "Fi" matches "File", and "Us" matches "User"
        /// 
        ///     Configuration
        ///     {
        ///         Fi^
        ///         Node("TargetMachine")
        ///         {
        ///             Us^
        ///         }
        ///     }
        /// 
        /// </summary>
        /// <param name="completionContext"></param>
        /// <param name="configureAst"></param>
        /// <param name="keywordAst"></param>
        /// <param name="matched"></param>
        /// <returns></returns>
        private List<CompletionResult> GetResultForIdentifierInConfiguration(
            CompletionContext completionContext,
            ConfigurationDefinitionAst configureAst,
            DynamicKeywordStatementAst keywordAst,
            out bool matched)
        {
            List<CompletionResult> results = null;
            matched = false;

#if CORECLR // Microsoft.PowerShell.DesiredStateConfiguration is not in CORE CLR
            results = new List<CompletionResult>();
#else
            IEnumerable<DynamicKeyword> keywords = configureAst.DefinedKeywords.Where(
                k => // Node is special case, legal in both Resource and Meta configuration
                    String.Compare(k.Keyword, @"Node", StringComparison.OrdinalIgnoreCase) == 0 ||
                    (
                        // Check compatibility between Resource and Configuration Type
                        k.IsCompatibleWithConfigurationType(configureAst.ConfigurationType) &&
                        !DynamicKeyword.IsHiddenKeyword(k.Keyword) &&
                        !k.IsReservedKeyword
                    )
            );

            if (keywordAst != null && completionContext.CursorPosition.Offset < keywordAst.Extent.EndOffset)
                keywords = keywordAst.Keyword.GetAllowedKeywords(keywords);

            if (keywords != null && keywords.Any())
            {
                string commandName = (completionContext.WordToComplete ?? String.Empty) + "*";
                var wildcardPattern = WildcardPattern.Get(commandName, WildcardOptions.IgnoreCase | WildcardOptions.CultureInvariant);

                // Filter by name
                var matchedResults = keywords.Where(k => wildcardPattern.IsMatch(k.Keyword));
                if (matchedResults == null || !matchedResults.Any())
                {
                    // Fallback to all legal keywords in the configuration statement
                    matchedResults = keywords;
                }
                else
                {
                    matched = true;
                }

                foreach (var keyword in matchedResults)
                {
                    string usageString = Microsoft.PowerShell.DesiredStateConfiguration.Internal.DscClassCache.GetDSCResourceUsageString(keyword);
                    if (results == null)
                    {
                        results = new List<CompletionResult>();
                    }
                    results.Add(new CompletionResult(
                        keyword.Keyword,
                        keyword.Keyword,
                        CompletionResultType.DynamicKeyword,
                        usageString));
                }
            }
#endif

            return results;
        }
 object ICustomAstVisitor2.VisitDynamicKeywordStatement(DynamicKeywordStatementAst dynamicKeywordAst)
 => ProcessRewriter(VisitDynamicKeywordStatement, dynamicKeywordAst);
 public virtual StatementAst VisitDynamicKeywordStatement(DynamicKeywordStatementAst dynamicKeywordAst)
 {
     return(new DynamicKeywordStatementAst(
                dynamicKeywordAst.Extent,
                dynamicKeywordAst.CommandElements?.RewriteAll(this, SyntaxKind.CommandElement)));
 }
 public override AstVisitAction VisitDynamicKeywordStatement(DynamicKeywordStatementAst dynamicKeywordStatementAst)
 {
     return this.VisitDslExpression(dynamicKeywordStatementAst.CommandElements, dynamicKeywordStatementAst.Parent, dynamicKeywordStatementAst.Extent);
 }
 public override AstVisitAction VisitDynamicKeywordStatement(DynamicKeywordStatementAst dynamicKeywordStatementAst)
 {
     return(Visit(dynamicKeywordStatementAst));
 }
Beispiel #13
0
 public override AstVisitAction VisitDynamicKeywordStatement(DynamicKeywordStatementAst dynamicKeywordStatementAst) => VisitAst(dynamicKeywordStatementAst);
Beispiel #14
0
        /// <summary>
        /// Parse a dynamic keyword statement which will be either of the form
        ///     keyword [parameters] [name] { a=1; b=2; } # constructor with properties
        /// or
        ///     keyword [parameters] [name] { ... }  # constructor with a simple body.
        /// or keywordcommand parameters 
        /// This custom keyword does not introduce a new AST node type. Instead it generates a
        /// CommandAst that calls a PowerShell command to implement the keyword's logic.
        /// This command has one of two signatures:
        ///     keywordImplCommand
        /// </summary>
        /// <param name="functionName">The name of the function to invoke</param>
        /// <param name="keywordData">The data for this keyword definition</param>
        /// <returns></returns>
        private StatementAst DynamicKeywordStatementRule(Token functionName, DynamicKeyword keywordData)
        {
            //////////////////////////////////////////////////////////////////////////////////
            // If a custom action was provided. then invoke it
            //////////////////////////////////////////////////////////////////////////////////
            if (keywordData.PreParse != null)
            {
                try
                {
                    ParseError[] errors = keywordData.PreParse(keywordData);
                    if (errors != null && errors.Length > 0)
                    {
                        foreach (var e in errors)
                        {
                            ReportError(e);
                        }
                    }
                }
                catch (Exception e)
                {
                    ReportError(functionName.Extent, () => ParserStrings.DynamicKeywordPreParseException, keywordData.ResourceName, e.ToString());
                    return null;
                }
            }

            if (keywordData.IsReservedKeyword)
            {
                // ErrorRecovery: eat the token
                ReportError(functionName.Extent, () => ParserStrings.UnsupportedReservedKeyword, keywordData.Keyword);
                return null;
            }

            if (keywordData.HasReservedProperties)
            {
                // ErrorRecovery: eat the token
                ReportError(functionName.Extent, () => ParserStrings.UnsupportedReservedProperty, "'Require', 'Trigger', 'Notify', 'Before', 'After' and 'Subscribe'");
                return null;
            }

            string elementName = string.Empty;

            DynamicKeywordStatementAst dynamicKeywordAst;
            if (keywordData.BodyMode == DynamicKeywordBodyMode.Command)
            {
                UngetToken(functionName);
                dynamicKeywordAst = (DynamicKeywordStatementAst)CommandRule(forDynamicKeyword: true);
                dynamicKeywordAst.Keyword = keywordData;
                dynamicKeywordAst.FunctionName = functionName;
            }
            else
            {
                SkipNewlines();

                // The expression that returns the resource name or names.
                ExpressionAst instanceName = null;

                Token nameToken = NextToken();
                if (nameToken.Kind == TokenKind.EndOfInput)
                {
                    UngetToken(nameToken);

                    if (keywordData.NameMode == DynamicKeywordNameMode.NameRequired || keywordData.NameMode == DynamicKeywordNameMode.SimpleNameRequired)
                    {
                        ReportIncompleteInput(After(functionName), () => ParserStrings.RequiredNameOrExpressionMissing);
                    }
                    else
                    {
                        // Name not required so report missing brace
                        ReportIncompleteInput(After(functionName.Extent), () => ParserStrings.MissingBraceInObjectDefinition);
                    }
                    return null;
                }

                // If it's an lcurly, then no name was provided, and we skip to the body processing
                Token lCurly = null;
                if (nameToken.Kind == TokenKind.LCurly)
                {
                    lCurly = nameToken;
                    if (keywordData.NameMode == DynamicKeywordNameMode.NameRequired || keywordData.NameMode == DynamicKeywordNameMode.SimpleNameRequired)
                    {
                        ReportError(After(functionName), () => ParserStrings.RequiredNameOrExpressionMissing);
                        UngetToken(nameToken);
                        return null;
                    }
                }
                else if (nameToken.Kind == TokenKind.Identifier || nameToken.Kind == TokenKind.DynamicKeyword)
                {
                    if (keywordData.NameMode == DynamicKeywordNameMode.NoName)
                    {
                        ReportError(After(functionName), () => ParserStrings.UnexpectedNameForType, functionName.Text, nameToken.Text);
                        UngetToken(nameToken);
                        return null;
                    }

                    // If it's an identifier then this is the name for the data object
                    elementName = nameToken.Text;

                    // If only a simple name is allowed, then the string must be non-null.
                    if ((keywordData.NameMode == DynamicKeywordNameMode.SimpleNameRequired || keywordData.NameMode == DynamicKeywordNameMode.SimpleOptionalName) && string.IsNullOrEmpty(elementName))
                    {
                        ReportIncompleteInput(After(functionName), () => ParserStrings.RequiredNameOrExpressionMissing);
                        UngetToken(nameToken);
                        return null;
                    }
                }
                else
                {
                    // see if an expression was provided instead of a bare word...
                    UngetToken(nameToken);
                    instanceName = GetSingleCommandArgument(CommandArgumentContext.CommandName);

                    if (instanceName == null)
                    {
                        if (keywordData.NameMode == DynamicKeywordNameMode.SimpleNameRequired || keywordData.NameMode == DynamicKeywordNameMode.SimpleOptionalName)
                        {
                            ReportError(After(functionName), () => ParserStrings.RequiredNameOrExpressionMissing);
                        }
                        else
                        {
                            // It wasn't an '{' and it wasn't a name expression so it's a unexpected token.
                            ReportError(After(functionName), () => ParserStrings.UnexpectedToken, nameToken.Text);
                        }
                        return null;
                    }

                    // Ok, we got a name expression, but we're expecting no name, so it's and error.
                    if (keywordData.NameMode == DynamicKeywordNameMode.NoName)
                    {
                        ReportError(After(functionName), () => ParserStrings.UnexpectedNameForType, functionName.Text, instanceName.ToString());
                        return null;
                    }

                    // We were expecting a simple name so report an error
                    if (keywordData.NameMode == DynamicKeywordNameMode.SimpleNameRequired || keywordData.NameMode == DynamicKeywordNameMode.SimpleOptionalName)
                    {
                        // If no match, then this is an incomplete token BUGBUG fix message
                        ReportError(nameToken.Extent, () => ParserStrings.UnexpectedToken, nameToken.Text);
                        return null;
                    }
                }

                // If we didn't get a resource expression AST, then we need to build one out of the
                // name that was specified. It may be the case that we don't have
                // a resource name in which case it will be the empty string. Even in the cases were
                // we aren't expecting a name, we still do this so that the signature of the implementing function remains
                // the same.
                ExpressionAst originalInstanceName = instanceName;
                if (instanceName == null)
                {
                    instanceName = new StringConstantExpressionAst(nameToken.Extent, elementName, StringConstantType.BareWord);
                }

                SkipNewlines();

                //
                // Now look for the body of the data statement.
                //
                if (lCurly == null)
                {
                    lCurly = NextToken();

                    if (lCurly.Kind == TokenKind.EndOfInput)
                    {
                        UngetToken(lCurly);
                        ReportIncompleteInput(After(functionName.Extent), () => ParserStrings.MissingBraceInObjectDefinition);

                        // Preserve the name expression for tab completion
                        return originalInstanceName == null
                                   ? null
                                   : new ErrorStatementAst(ExtentOf(functionName, originalInstanceName),
                                                           GetNestedErrorAsts(originalInstanceName));
                    }

                    if (lCurly.Kind != TokenKind.LCurly)
                    {
                        // We need to generate a reasonable error message for this case:
                        //
                        // Configuration C {
                        //   node $AllNode.NodeName{ # There is no space before curly, and we are converting scriptblock to and argument to call 'NodeName'
                        //     ...
                        //   }
                        // } # we don't want to simple report an unexpected token here, it would be super-confusing.

                        InvokeMemberExpressionAst instanceInvokeMemberExpressionAst = instanceName as InvokeMemberExpressionAst;

                        if (instanceInvokeMemberExpressionAst != null &&
                            instanceInvokeMemberExpressionAst.Arguments.Count == 1 &&
                            instanceInvokeMemberExpressionAst.Arguments[0] is ScriptBlockExpressionAst &&
                            // the last condition checks that there is no space between "method" name and '{'
                            instanceInvokeMemberExpressionAst.Member.Extent.EndOffset == instanceInvokeMemberExpressionAst.Arguments[0].Extent.StartOffset)
                        {
                            ReportError(LastCharacterOf(instanceInvokeMemberExpressionAst.Member.Extent), () => ParserStrings.UnexpectedTokenInDynamicKeyword, functionName.Text);
                        }
                        else
                        {
                            ReportError(lCurly.Extent, () => ParserStrings.UnexpectedToken, lCurly.Text);
                        }

                        if (lCurly.Kind == TokenKind.Dot && originalInstanceName != null && lCurly.Extent.StartOffset == originalInstanceName.Extent.EndOffset)
                        {
                            // Generate more useful ast for tab-completing extension methods on special DSC collection variables
                            // e.g. configuration foo { node $AllNodes.<tab>

                            IScriptExtent errorExtent = ExtentOf(originalInstanceName, lCurly);
                            var errorExpr = new ErrorExpressionAst(errorExtent);
                            var memberExpr = new MemberExpressionAst(originalInstanceName.Extent, originalInstanceName, errorExpr, @static: false);

                            return new ErrorStatementAst(errorExtent, new[] { memberExpr });
                        }

                        UngetToken(lCurly);
                        // Preserve the name expression for tab completion
                        return originalInstanceName == null
                                   ? null
                                   : new ErrorStatementAst(ExtentOf(functionName, originalInstanceName),
                                                           GetNestedErrorAsts(originalInstanceName));
                    }
                }

                //
                // The keyword data is used to see
                // if a scriptblock or a hashtable is expected.
                //
                ExpressionAst body = null;
                if (keywordData.BodyMode == DynamicKeywordBodyMode.ScriptBlock)
                {
                    var oldInConfiguraiton = _inConfiguration;
                    try
                    {
                        _inConfiguration = false;
                        body = ScriptBlockExpressionRule(lCurly);
                    }
                    finally
                    {
                        _inConfiguration = oldInConfiguraiton;
                    }
                }
                else if (keywordData.BodyMode == DynamicKeywordBodyMode.Hashtable)
                {
                    // Resource property value could be set to nested DSC resources except Script resource
                    bool isScriptResource = String.Compare(functionName.Text, @"Script", StringComparison.OrdinalIgnoreCase) == 0;
                    try
                    {
                        if (isScriptResource)
                            DynamicKeyword.Push();
                        body = HashExpressionRule(lCurly, true /* parsingSchemaElement */);
                    }
                    finally
                    {
                        if (isScriptResource)
                            DynamicKeyword.Pop();
                    }
                }
                // commandast
                // elements: instancename/dynamickeyword/hashtable or scripblockexpress
                if (body == null)
                {
                    // Failed to read the statement body
                    ReportIncompleteInput(After(lCurly), () => ParserStrings.MissingStatementAfterKeyword, keywordData.Keyword);

                    // Preserve the name expression for tab completion
                    return originalInstanceName == null
                               ? null
                               : new ErrorStatementAst(ExtentOf(functionName, originalInstanceName),
                                                       GetNestedErrorAsts(originalInstanceName));
                }

                //////////////////////////////////////////////////////////////////////////
                // The statement is now fully parsed
                //////////////////////////////////////////////////////////////////////////

                //
                // Create DynamicKeywordStatementAst
                //
                Collection<CommandElementAst> commandElements = new Collection<CommandElementAst>
                {
                    new StringConstantExpressionAst(functionName.Extent, functionName.Text, StringConstantType.BareWord),
                    (ExpressionAst)instanceName.Copy(),
                    (ExpressionAst)body.Copy()
                };
                Token nextToken = NextToken();
                IScriptExtent dynamicKeywordExtent = ExtentOf(functionName, Before(nextToken));
                UngetToken(nextToken);
                dynamicKeywordAst = new DynamicKeywordStatementAst(dynamicKeywordExtent, commandElements)
                {
                    Keyword = keywordData,
                    LCurly = lCurly,
                    FunctionName = functionName,
                    InstanceName = instanceName,
                    OriginalInstanceName = originalInstanceName,
                    BodyExpression = body,
                    ElementName = elementName,
                };
            }

            //////////////////////////////////////////////////////////////////////////////////
            // If a custom action was provided. then invoke it
            //////////////////////////////////////////////////////////////////////////////////
            if (keywordData.PostParse != null)
            {
                try
                {
                    ParseError[] errors = keywordData.PostParse(dynamicKeywordAst);
                    if (errors != null && errors.Length > 0)
                    {
                        foreach (var e in errors)
                        {
                            ReportError(e);
                        }
                    }
                }
                catch (Exception e)
                {
                    ReportError(functionName.Extent, () => ParserStrings.DynamicKeywordPostParseException, keywordData.Keyword, e.ToString());
                    return null;
                }
            }

            return dynamicKeywordAst;
        }
Beispiel #15
0
        public object VisitDynamicKeywordStatement(DynamicKeywordStatementAst dynamicKeywordAst)
        {
            if (dynamicKeywordAst.Keyword.MetaStatement)
            {
                return Expression.Empty();
            }

            return this.VisitPipeline(dynamicKeywordAst.GenerateCommandCallPipelineAst());
        }
Beispiel #16
0
 /// <summary>
 /// Find the configuration statement contains current cursor
 /// </summary>
 /// <param name="cursorPosition"></param>
 /// <param name="ast"></param>
 /// <param name="keywordAst"></param>
 /// <returns></returns>
 private ConfigurationDefinitionAst GetAncestorConfigurationAstAndKeywordAst(
     IScriptPosition cursorPosition,
     Ast ast,
     out DynamicKeywordStatementAst keywordAst)
 {
     ConfigurationDefinitionAst configureAst = Ast.GetAncestorConfigurationDefinitionAstAndDynamicKeywordStatementAst(ast, out keywordAst);
     // Find the configuration statement contains current cursor
     // Note: cursorPosition.Offset < configureAst.Extent.EndOffset means cursor locates inside the configuration
     //       cursorPosition.Offset = configureAst.Extent.EndOffset means cursor locates at the end of the configuration
     while (configureAst != null && cursorPosition.Offset > configureAst.Extent.EndOffset)
     {
         configureAst = Ast.GetAncestorAst<ConfigurationDefinitionAst>(configureAst.Parent);
     }
     return configureAst;
 }
Beispiel #17
0
        // This function is called after parsing the Import-DscResource keyword and it's arguments, but before parsing
        // anything else.
        //
        //
        private static ParseError[] ImportResourcePostParse(DynamicKeywordStatementAst kwAst)
        {
            var elements = Ast.CopyElements(kwAst.CommandElements);

            Diagnostics.Assert(elements[0] is StringConstantExpressionAst &&
                               ((StringConstantExpressionAst)elements[0]).Value.Equals("Import-DscResource", StringComparison.OrdinalIgnoreCase),
                               "Incorrect ast for expected keyword");
            var commandAst = new CommandAst(kwAst.Extent, elements, TokenKind.Unknown, null);

            const string nameParam = "Name";
            const string moduleNameParam = "ModuleName";
            const string moduleVersionParam = "ModuleVersion";

            StaticBindingResult bindingResult = StaticParameterBinder.BindCommand(commandAst, false);

            var errorList = new List<ParseError>();
            foreach (var bindingException in bindingResult.BindingExceptions.Values)
            {
                errorList.Add(new ParseError(bindingException.CommandElement.Extent,
                                             "ParameterBindingException",
                                             bindingException.BindingException.Message));
            }

            ParameterBindingResult moduleNameBindingResult = null;
            ParameterBindingResult resourceNameBindingResult = null;
            ParameterBindingResult moduleVersionBindingResult = null;

            foreach (var binding in bindingResult.BoundParameters)
            {
                // Error case when positional parameter values are specified
                var boundParameterName = binding.Key;
                var parameterBindingResult = binding.Value;
                if (boundParameterName.All(char.IsDigit))
                {
                    errorList.Add(new ParseError(parameterBindingResult.Value.Extent,
                                                 "ImportDscResourcePositionalParamsNotSupported",
                                                 string.Format(CultureInfo.CurrentCulture, ParserStrings.ImportDscResourcePositionalParamsNotSupported)));
                    continue;
                }

                if (nameParam.StartsWith(boundParameterName, StringComparison.OrdinalIgnoreCase))
                {
                    resourceNameBindingResult = parameterBindingResult;
                }
                else if (moduleNameParam.StartsWith(boundParameterName, StringComparison.OrdinalIgnoreCase))
                {
                    moduleNameBindingResult = parameterBindingResult;
                }
                else if (moduleVersionParam.StartsWith(boundParameterName, StringComparison.OrdinalIgnoreCase))
                {
                    moduleVersionBindingResult = parameterBindingResult;
                }
                else
                {
                    errorList.Add(new ParseError(parameterBindingResult.Value.Extent,
                                                 "ImportDscResourceNeedParams",
                                                 string.Format(CultureInfo.CurrentCulture, ParserStrings.ImportDscResourceNeedParams)));
                }
            }

            if (errorList.Count == 0 && moduleNameBindingResult == null && resourceNameBindingResult == null)
            {
                errorList.Add(new ParseError(kwAst.Extent,
                                             "ImportDscResourceNeedParams",
                                             string.Format(CultureInfo.CurrentCulture, ParserStrings.ImportDscResourceNeedParams)));
            }

            // Check here if Version is specified but modulename is not specified 
            if (moduleVersionBindingResult != null && moduleNameBindingResult == null)
            {
                // only add this error again to the error list if resources is not null
                // if resources and modules are both null we have already added this error in collection
                // we do not want to do this twice. since we are giving same error ImportDscResourceNeedParams in both cases
                // once we have different error messages for 2 scenarios we can remove this check 
                if (resourceNameBindingResult != null)
                {
                    errorList.Add(new ParseError(kwAst.Extent,
                                                 "ImportDscResourceNeedModuleNameWithModuleVersion",
                                                 string.Format(CultureInfo.CurrentCulture, ParserStrings.ImportDscResourceNeedParams)));
                }
            }

            string[] resourceNames = null;
            if (resourceNameBindingResult != null)
            {
                object resourceName = null;
                if (!IsConstantValueVisitor.IsConstant(resourceNameBindingResult.Value, out resourceName, true, true) ||
                    !LanguagePrimitives.TryConvertTo(resourceName, out resourceNames))
                {
                    errorList.Add(new ParseError(resourceNameBindingResult.Value.Extent,
                                                 "RequiresInvalidStringArgument",
                                                 string.Format(CultureInfo.CurrentCulture, ParserStrings.RequiresInvalidStringArgument, nameParam)));
                }
            }

            System.Version moduleVersion = null;
            if (moduleVersionBindingResult != null)
            {
                object moduleVer = null;
                if (!IsConstantValueVisitor.IsConstant(moduleVersionBindingResult.Value, out moduleVer, true, true))
                {
                    errorList.Add(new ParseError(moduleVersionBindingResult.Value.Extent,
                                                 "RequiresArgumentMustBeConstant",
                                                 ParserStrings.RequiresArgumentMustBeConstant));
                }

                if (moduleVer is double)
                {
                    // this happens in case -ModuleVersion 1.0, then use extent text for that.
                    // The better way to do it would be define static binding API against CommandInfo, that holds information about parameter types.
                    // This way, we can avoid this ugly special-casing and say that -ModuleVersion has type [System.Version].
                    moduleVer = moduleVersionBindingResult.Value.Extent.Text;
                }

                if (!LanguagePrimitives.TryConvertTo(moduleVer, out moduleVersion))
                {
                    errorList.Add(new ParseError(moduleVersionBindingResult.Value.Extent,
                                                 "RequiresVersionInvalid",
                                                 ParserStrings.RequiresVersionInvalid));
                }
            }

            ModuleSpecification[] moduleSpecifications = null;
            if (moduleNameBindingResult != null)
            {
                object moduleName = null;
                if (!IsConstantValueVisitor.IsConstant(moduleNameBindingResult.Value, out moduleName, true, true))
                {
                    errorList.Add(new ParseError(moduleNameBindingResult.Value.Extent,
                                                 "RequiresArgumentMustBeConstant",
                                                 ParserStrings.RequiresArgumentMustBeConstant));
                }

                if (LanguagePrimitives.TryConvertTo(moduleName, out moduleSpecifications))
                {
                    // if resourceNames are specified then we can not specify multiple modules name 
                    if (moduleSpecifications != null && moduleSpecifications.Length > 1 && resourceNames != null)
                    {
                        errorList.Add(new ParseError(moduleNameBindingResult.Value.Extent,
                                                     "ImportDscResourceMultipleModulesNotSupportedWithName",
                                                     string.Format(CultureInfo.CurrentCulture, ParserStrings.ImportDscResourceMultipleModulesNotSupportedWithName)));
                    }

                    // if moduleversion is specified then we can not specify multiple modules name 
                    if (moduleSpecifications != null && moduleSpecifications.Length > 1 && moduleVersion != null)
                    {
                        errorList.Add(new ParseError(moduleNameBindingResult.Value.Extent,
                                                     "ImportDscResourceMultipleModulesNotSupportedWithVersion",
                                                     string.Format(CultureInfo.CurrentCulture, ParserStrings.ImportDscResourceNeedParams)));
                    }

                    // if moduleversion is specified then we can not specify another version in modulespecification object of ModuleName  
                    if (moduleSpecifications != null && (moduleSpecifications[0].Version != null || moduleSpecifications[0].MaximumVersion != null) && moduleVersion != null)
                    {
                        errorList.Add(new ParseError(moduleNameBindingResult.Value.Extent,
                                                     "ImportDscResourceMultipleModuleVersionsNotSupported",
                                                     string.Format(CultureInfo.CurrentCulture, ParserStrings.ImportDscResourceNeedParams)));
                    }

                    // If moduleVersion is specified we have only one module Name in valid scenario
                    // So update it's version property in module specification object that will be used to load modules 
                    if (moduleSpecifications != null && moduleSpecifications[0].Version == null && moduleSpecifications[0].MaximumVersion == null && moduleVersion != null)
                    {
                        moduleSpecifications[0].Version = moduleVersion;
                    }
                }
                else
                {
                    errorList.Add(new ParseError(moduleNameBindingResult.Value.Extent,
                                                 "RequiresInvalidStringArgument",
                                                 string.Format(CultureInfo.CurrentCulture, ParserStrings.RequiresInvalidStringArgument, moduleNameParam)));
                }
            }

            if (errorList.Count == 0)
            {
                // No errors, try to load the resources
                LoadResourcesFromModule(kwAst.Extent, moduleSpecifications, resourceNames, errorList);
            }

            return errorList.ToArray();
        }
Beispiel #18
0
 public override StatementAst VisitDynamicKeywordStatement(DynamicKeywordStatementAst dynamicKeywordAst)
 => VisitStatement(base.VisitDynamicKeywordStatement(dynamicKeywordAst));
Beispiel #19
0
        // This function performs semantic checks for Import-DscResource
        private static ParseError[] ImportResourceCheckSemantics(DynamicKeywordStatementAst kwAst)
        {
            List<ParseError> errorList = null;

            var keywordAst = Ast.GetAncestorAst<DynamicKeywordStatementAst>(kwAst.Parent);
            while (keywordAst != null)
            {
                if (keywordAst.Keyword.Keyword.Equals("Node"))
                {
                    if (errorList == null)
                    {
                        errorList = new List<ParseError>();
                    }

                    errorList.Add(new ParseError(kwAst.Extent,
                                         "ImportDscResourceInsideNode",
                                         string.Format(CultureInfo.CurrentCulture, ParserStrings.ImportDscResourceInsideNode)));
                    break;
                }
                keywordAst = Ast.GetAncestorAst<DynamicKeywordStatementAst>(keywordAst.Parent);
            }

            if (errorList != null)
            {
                return errorList.ToArray();
            }
            else
            {
                return null;
            }
        }
 public object VisitDynamicKeywordStatement(DynamicKeywordStatementAst dynamicKeywordAst)
 {
     throw new System.NotImplementedException();
 }
Beispiel #21
0
        // This function performs semantic checks for all DSC Resources keywords.
        private static ParseError[] CheckMandatoryPropertiesPresent(DynamicKeywordStatementAst kwAst)
        {
            HashSet<string> mandatoryPropertiesNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
            foreach (var pair in kwAst.Keyword.Properties)
            {
                if (pair.Value.Mandatory)
                {
                    mandatoryPropertiesNames.Add(pair.Key);
                }
            }

            // by design mandatoryPropertiesNames are not empty at this point:
            // every resource must have at least one Key property.

            HashtableAst hashtableAst = null;
            foreach (var ast in kwAst.CommandElements)
            {
                hashtableAst = ast as HashtableAst;
                if (hashtableAst != null)
                {
                    break;
                }
            }

            if (hashtableAst == null)
            {
                // nothing to validate
                return null;
            }

            foreach (var pair in hashtableAst.KeyValuePairs)
            {
                object evalResultObject;
                if (IsConstantValueVisitor.IsConstant(pair.Item1, out evalResultObject, forAttribute: false, forRequires: false))
                {
                    var presentName = evalResultObject as string;
                    if (presentName != null)
                    {
                        if (mandatoryPropertiesNames.Remove(presentName) && mandatoryPropertiesNames.Count == 0)
                        {
                            // optimization, once all mandatory properties are specified, we can safely exit.
                            return null;
                        }
                    }
                }
            }

            if (mandatoryPropertiesNames.Count > 0)
            {
                ParseError[] errors = new ParseError[mandatoryPropertiesNames.Count];
                var extent = kwAst.CommandElements[0].Extent;
                int i = 0;
                foreach (string name in mandatoryPropertiesNames)
                {
                    errors[i] = new ParseError(extent, "MissingValueForMandatoryProperty",
                        string.Format(CultureInfo.CurrentCulture, ParserStrings.MissingValueForMandatoryProperty,
                                    kwAst.Keyword.Keyword, kwAst.Keyword.Properties.First(
                                        p => StringComparer.OrdinalIgnoreCase.Equals(p.Value.Name, name)).Value.TypeConstraint, name));
                    i++;
                }

                return errors;
            }

            return null;
        }
Beispiel #22
0
 /// <summary/>
 public virtual object VisitDynamicKeywordStatement(DynamicKeywordStatementAst dynamicKeywordAst)
 {
     return(null);
 }
Beispiel #23
0
        public override AstVisitAction VisitDynamicKeywordStatement(DynamicKeywordStatementAst dynamicKeywordStatementAst)
        {
            //////////////////////////////////////////////////////////////////////////////////
            // If a custom action was provided. then invoke it
            //////////////////////////////////////////////////////////////////////////////////
            if (dynamicKeywordStatementAst.Keyword.SemanticCheck != null)
            {
                try
                {
                    ParseError[] errors = dynamicKeywordStatementAst.Keyword.SemanticCheck(dynamicKeywordStatementAst);
                    if (errors != null && errors.Length > 0)
                        errors.ToList().ForEach(e => _parser.ReportError(e));
                }
                catch (Exception e)
                {
                    _parser.ReportError(dynamicKeywordStatementAst.Extent, () => ParserStrings.DynamicKeywordSemanticCheckException, dynamicKeywordStatementAst.Keyword.ResourceName, e.ToString());
                }
            }
            DynamicKeyword keyword = dynamicKeywordStatementAst.Keyword;
            HashtableAst hashtable = dynamicKeywordStatementAst.BodyExpression as HashtableAst;
            if (hashtable != null)
            {
                //
                // If it's a hash table, validate that only valid members have been specified.
                //
                foreach (var keyValueTuple in hashtable.KeyValuePairs)
                {
                    var propName = keyValueTuple.Item1 as StringConstantExpressionAst;
                    if (propName == null)
                    {
                        _parser.ReportError(keyValueTuple.Item1.Extent,
                            () => ParserStrings.ConfigurationInvalidPropertyName,
                            dynamicKeywordStatementAst.FunctionName.Extent, keyValueTuple.Item1.Extent);
                    }
                    else if (!keyword.Properties.ContainsKey(propName.Value))
                    {
                        _parser.ReportError(propName.Extent,
                            () => ParserStrings.InvalidInstanceProperty,
                            propName.Value,
                            string.Join("', '", keyword.Properties.Keys.OrderBy(key => key, StringComparer.OrdinalIgnoreCase)));
                    }
                }
            }

            //
            // Check compatibility between DSC Resource and Configuration
            //
            ConfigurationDefinitionAst configAst = Ast.GetAncestorAst<ConfigurationDefinitionAst>(dynamicKeywordStatementAst);
            if (configAst != null)
            {
                StringConstantExpressionAst nameAst = dynamicKeywordStatementAst.CommandElements[0] as StringConstantExpressionAst;
                Diagnostics.Assert(nameAst != null, "nameAst should never be null");
                if (!DscClassCache.SystemResourceNames.Contains(nameAst.Extent.Text.Trim()))
                {
                    if (configAst.ConfigurationType == ConfigurationType.Meta && !dynamicKeywordStatementAst.Keyword.IsMetaDSCResource())
                    {
                        _parser.ReportError(nameAst.Extent,
                            () => ParserStrings.RegularResourceUsedInMetaConfig,
                            nameAst.Extent.Text);
                    }
                    else if (configAst.ConfigurationType != ConfigurationType.Meta && dynamicKeywordStatementAst.Keyword.IsMetaDSCResource())
                    {
                        _parser.ReportError(nameAst.Extent,
                            () => ParserStrings.MetaConfigurationUsedInRegularConfig,
                            nameAst.Extent.Text);
                    }
                }
            }

            return AstVisitAction.Continue;
        }
Beispiel #24
0
 /// <summary/>
 public virtual AstVisitAction VisitDynamicKeywordStatement(DynamicKeywordStatementAst dynamicKeywordStatementAst)
 {
     return(AstVisitAction.Continue);
 }
Beispiel #25
0
 /// <summary/>
 public virtual AstVisitAction VisitDynamicKeywordStatement(DynamicKeywordStatementAst dynamicKeywordStatementAst) { return AstVisitAction.Continue; }
Beispiel #26
0
 public object VisitDynamicKeywordStatement(DynamicKeywordStatementAst dynamicKeywordAst)
 {
     return(AutomationNull.Value);
 }
Beispiel #27
0
 public override AstVisitAction VisitDynamicKeywordStatement(DynamicKeywordStatementAst ast) { return Check(ast); }