Exemple #1
0
        static TriggerState GetTriggerState(string expression, out int triggerLength, out ExpressionNode triggerExpression)
        {
            triggerLength = 0;

            if (expression.Length == 0)
            {
                triggerExpression = new ExpressionText(0, "", true);
                return(TriggerState.Value);
            }

            if (expression.Length == 1)
            {
                triggerExpression = new ExpressionText(0, expression, true);
                triggerLength     = 1;
                return(TriggerState.Value);
            }

            const ExpressionOptions options = ExpressionOptions.ItemsMetadataAndLists | ExpressionOptions.CommaLists;

            triggerExpression = ExpressionParser.Parse(expression, options);

            if (triggerExpression is ExpressionList el)
            {
                //the last list entry is the thing that triggered it
                triggerExpression = el.Nodes.Last();
                if (triggerExpression is ExpressionError e && e.Kind == ExpressionErrorKind.EmptyListEntry)
                {
                    return(LastChar() == ',' ? TriggerState.CommaValue : TriggerState.SemicolonValue);
                }
                if (triggerExpression is ExpressionText l)
                {
                    if (l.Length == 1)
                    {
                        triggerLength = 1;
                        return(PenultimateChar() == ',' ? TriggerState.CommaValue : TriggerState.SemicolonValue);
                    }
                }
            }

            //find the deepest node that touches the end
            var lastNode = triggerExpression.Find(expression.Length);

            if (lastNode == null)
            {
                return(TriggerState.None);
            }

            if (lastNode is ExpressionText lit)
            {
                if (LastChar() == '\\')
                {
                    return(TriggerState.DirectorySeparator);
                }

                if (lit.Value.Length >= 2 && PenultimateChar() == '\\' && IsPossiblePathSegment(LastChar()))
                {
                    triggerLength = 1;
                    return(TriggerState.DirectorySeparator);
                }
            }

            //find the deepest error
            var            error  = lastNode as ExpressionError;
            ExpressionNode parent = lastNode.Parent;

            while (parent != null && error == null)
            {
                error  = parent as ExpressionError;
                parent = parent.Parent;
            }

            if (error is IncompleteExpressionError iee && iee.WasEOF)
            {
                switch (lastNode)
                {
                case ExpressionItem i:
                    if (iee.Kind == ExpressionErrorKind.ExpectingMethodOrTransform)
                    {
                        return(TriggerState.ItemFunctionName);
                    }
                    break;

                case ExpressionItemName ein:
                    if (iee.Kind == ExpressionErrorKind.ExpectingRightParenOrDash)
                    {
                        triggerLength = ein.Name.Length;
                        return(TriggerState.Item);
                    }
                    break;

                case ExpressionPropertyName pn:
                    if (iee.Kind == ExpressionErrorKind.ExpectingRightParenOrPeriod)
                    {
                        triggerLength = pn.Name.Length;
                        return(TriggerState.Property);
                    }
                    break;

                case ExpressionFunctionName fn:
                    if (iee.Kind == ExpressionErrorKind.IncompleteProperty)
                    {
                        triggerLength = fn.Name.Length;
                        return(TriggerState.PropertyFunctionName);
                    }
                    if (iee.Kind == ExpressionErrorKind.ExpectingLeftParen)
                    {
                        triggerLength = fn.Name.Length;
                        return(TriggerState.ItemFunctionName);
                    }
                    break;

                case ExpressionPropertyFunctionInvocation pfi:
                    if (iee.Kind == ExpressionErrorKind.ExpectingMethodName)
                    {
                        return(TriggerState.PropertyFunctionName);
                    }
                    if (iee.Kind == ExpressionErrorKind.ExpectingClassName)
                    {
                        return(TriggerState.PropertyFunctionClassName);
                    }
                    break;

                case ExpressionClassReference cr:
                    if (iee.Kind == ExpressionErrorKind.ExpectingBracketColonColon)
                    {
                        triggerLength = cr.Name.Length;
                        return(TriggerState.PropertyFunctionClassName);
                    }
                    break;

                case ExpressionMetadata m:
                    if (iee.Kind == ExpressionErrorKind.ExpectingMetadataName)
                    {
                        return(TriggerState.Metadata);
                    }
                    if (iee.Kind == ExpressionErrorKind.ExpectingRightParenOrPeriod)
                    {
                        triggerLength = m.ItemName.Length;
                        return(TriggerState.MetadataOrItem);
                    }
                    if (iee.Kind == ExpressionErrorKind.ExpectingRightParen)
                    {
                        triggerLength = m.MetadataName.Length;
                        return(TriggerState.Metadata);
                    }
                    break;
                }
                return(TriggerState.None);
            }

            if (error != null)
            {
                switch (error.Kind)
                {
                case ExpressionErrorKind.ExpectingPropertyName:
                    return(TriggerState.Property);

                case ExpressionErrorKind.ExpectingItemName:
                    return(TriggerState.Item);

                case ExpressionErrorKind.ExpectingMetadataOrItemName:
                    return(TriggerState.MetadataOrItem);
                }
                return(TriggerState.None);
            }

            return(TriggerState.None);

            char LastChar() => expression[expression.Length - 1];
            char PenultimateChar() => expression[expression.Length - 2];
            bool IsPossiblePathSegment(char c) => c == '_' || char.IsLetterOrDigit(c) || c == '.';
        }
Exemple #2
0
        static TriggerState GetTriggerState(string expression, out int triggerLength, out ExpressionNode triggerExpression)
        {
            triggerLength = 0;

            if (expression.Length == 0)
            {
                triggerExpression = new ExpressionText(0, "", true);
                return(TriggerState.Value);
            }

            if (expression.Length == 1)
            {
                triggerExpression = new ExpressionText(0, expression, true);
                triggerLength     = 1;
                return(TriggerState.Value);
            }

            const ExpressionOptions options = ExpressionOptions.ItemsMetadataAndLists | ExpressionOptions.CommaLists;

            triggerExpression = ExpressionParser.Parse(expression, options);

            if (triggerExpression is ExpressionList el)
            {
                //the last list entry is the thing that triggered it
                triggerExpression = el.Nodes.Last();
                if (triggerExpression is ExpressionError e && e.Kind == ExpressionErrorKind.EmptyListEntry)
                {
                    return(LastChar() == ',' ? TriggerState.CommaValue : TriggerState.SemicolonValue);
                }
                if (triggerExpression is ExpressionText l)
                {
                    if (l.Length == 1)
                    {
                        triggerLength = 1;
                        return(PenultimateChar() == ',' ? TriggerState.CommaValue : TriggerState.SemicolonValue);
                    }
                }
            }

            var lastNode = triggerExpression;

            if (lastNode is Expression expr)
            {
                lastNode = expr.Nodes.Last();
            }

            if (lastNode is ExpressionText lit)
            {
                if (LastChar() == '\\')
                {
                    return(TriggerState.DirectorySeparator);
                }

                if (lit.Value.Length >= 2 && PenultimateChar() == '\\' && IsPossiblePathSegment(LastChar()))
                {
                    triggerLength = 1;
                    return(TriggerState.DirectorySeparator);
                }
            }

            if (lastNode is IncompleteExpressionError iee && iee.WasEOF)
            {
                switch (iee.IncompleteNode)
                {
                case ExpressionItem i:
                    if (iee.Kind == ExpressionErrorKind.ExpectingRightParenOrDash && i.Name.Length == 1)
                    {
                        triggerLength = 1;
                        return(TriggerState.Item);
                    }
                    break;

                case ExpressionProperty p:
                    if (iee.Kind == ExpressionErrorKind.ExpectingRightParenOrPeriod && p.Name.Length == 1)
                    {
                        triggerLength = 1;
                        return(TriggerState.Property);
                    }
                    if (iee.Kind == ExpressionErrorKind.ExpectingMethodName)
                    {
                        return(TriggerState.MethodName);
                    }
                    if (iee.Kind == ExpressionErrorKind.ExpectingLeftParen)
                    {
                        var inv = p.Find(iee.Offset - 1) as ExpressionPropertyFunctionInvocation;
                        if (inv != null && inv.MethodName != null && inv.MethodName.Length == 1)
                        {
                            triggerLength = 1;
                            return(TriggerState.MethodName);
                        }
                    }
                    break;

                case ExpressionMetadata m:
                    if (iee.Kind == ExpressionErrorKind.ExpectingMetadataName)
                    {
                        return(TriggerState.Metadata);
                    }
                    if (iee.Kind == ExpressionErrorKind.ExpectingRightParenOrPeriod && m.ItemName.Length == 1)
                    {
                        triggerLength = 1;
                        return(TriggerState.MetadataOrItem);
                    }
                    if (iee.Kind == ExpressionErrorKind.ExpectingRightParen && m.MetadataName.Length == 1)
                    {
                        triggerLength = 1;
                        return(TriggerState.Metadata);
                    }
                    break;
                }
                return(TriggerState.None);
            }

            if (lastNode is ExpressionError err)
            {
                switch (err.Kind)
                {
                case ExpressionErrorKind.ExpectingPropertyName:
                    return(TriggerState.Property);

                case ExpressionErrorKind.ExpectingItemName:
                    return(TriggerState.Item);

                case ExpressionErrorKind.ExpectingMetadataOrItemName:
                    return(TriggerState.MetadataOrItem);
                }
                return(TriggerState.None);
            }

            return(TriggerState.None);

            char LastChar() => expression[expression.Length - 1];
            char PenultimateChar() => expression[expression.Length - 2];
            bool IsPossiblePathSegment(char c) => c == '_' || char.IsLetterOrDigit(c) || c == '.';
        }
        void ExtractReferences(MSBuildValueKind kind, string value, int startOffset)
        {
            try {
                var expression = ExpressionParser.Parse(value, ExpressionOptions.ItemsMetadataAndLists, startOffset);
                foreach (var node in expression.WithAllDescendants())
                {
                    switch (node)
                    {
                    case ExpressionProperty prop:
                        if (prop.IsSimpleProperty)
                        {
                            CollectProperty(prop.Name);
                        }
                        break;

                    case ExpressionItem item:
                        CollectItem(item.Name);
                        break;

                    case ExpressionMetadata meta:
                        var itemName = meta.GetItemName();
                        if (itemName != null)
                        {
                            CollectMetadata(itemName, meta.MetadataName);
                        }
                        break;

                    case ExpressionText literal:
                        if (literal.IsPure)
                        {
                            value = literal.GetUnescapedValue().Trim();
                            switch (kind.GetScalarType())
                            {
                            case MSBuildValueKind.ItemName:
                                CollectItem(value);
                                break;

                            case MSBuildValueKind.TargetName:
                                CollectTarget(value);
                                break;

                            case MSBuildValueKind.PropertyName:
                                CollectProperty(value);
                                break;

                            case MSBuildValueKind.Configuration:
                                Document.Configurations.Add(value);
                                break;

                            case MSBuildValueKind.Platform:
                                Document.Platforms.Add(value);
                                break;
                            }
                        }
                        break;
                    }
                }
            } catch (Exception ex) {
                LoggingService.LogError($"Error parsing MSBuild expression '{value}' in file {Filename} at {startOffset}", ex);
            }
        }