Ejemplo n.º 1
0
        /// <summary>
        /// Returns text representation for tag from <paramref name="expression"/>.
        /// </summary>
        /// <remarks>
        /// Getting text representation of a tag is widely used operation that could appear on the hot path.
        /// To avoid performance and memory problems this function should be used instead of more generic function of getting text
        /// representation, like <see cref="ReformatterHelper.GetFormattedText"/>.
        /// </remarks>
        public static string GetTagText(this ITaggedTemplateExpression expression)
        {
            Contract.Requires(expression != null);

            // There is two common cases for tagged expression in the system:
            // 1) custom factory, like p``, d``, f`` or
            // 2) string interpolation, like ``
            // This implementation is optimized for them.
            if (expression.Tag == null)
            {
                // Second case: this is ``
                return(string.Empty);
            }

            var identifier = expression.Tag as IIdentifier;

            if (identifier != null)
            {
                // First case: tag is just a function.
                return(identifier.Text);
            }

            // Falling back to generic implementation.
            return(expression.Tag.GetFormattedText());
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Method that converts tagged ast node into <see cref="Expression"/>.
        /// </summary>
        public Expression ConvertInterpolation(ITaggedTemplateExpression source, FunctionScope escapes, QualifierSpaceId currentQualifierSpaceId)
        {
            (var interpolationKind, ILiteralExpression literal, ITemplateLiteralFragment head, INodeArray <ITemplateSpan> templateSpans) = source;
            var tagTemplate = new ProcessedTagTemplateExpression(source, interpolationKind, literal, head, templateSpans);

            switch (interpolationKind)
            {
            case InterpolationKind.PathInterpolation:
                return(ConvertPathInterpolation(ref tagTemplate, escapes, currentQualifierSpaceId));

            case InterpolationKind.FileInterpolation:
                return(ConvertFileInterpolation(ref tagTemplate, escapes, currentQualifierSpaceId));

            case InterpolationKind.DirectoryInterpolation:
                return(ConvertDirectoryInterpolation(ref tagTemplate, escapes, currentQualifierSpaceId));

            case InterpolationKind.PathAtomInterpolation:
                return(ConvertPathAtomInterpolation(ref tagTemplate, escapes, currentQualifierSpaceId));

            case InterpolationKind.RelativePathInterpolation:
                return(ConvertRelativePathInterpolation(ref tagTemplate, escapes, currentQualifierSpaceId));

            default:
                throw Contract.AssertFailure(I($"Unknown interpolation kind '{interpolationKind}'."));
            }
        }
Ejemplo n.º 3
0
        private static int FitsOnOneLine(ITaggedTemplateExpression expression, int remainingSpace)
        {
            var space = FitsOnOneLine(expression.Tag, remainingSpace);

            if (space >= 0)
            {
                // This is a recursion on the pretty printer which is not nice, but it is the simplest for now
                space -= expression.GetFormattedText().Length;
            }

            return(space);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Returns true if a given node is a special template expression like p``, d``, f``, a`` etc.
        /// </summary>
        public static bool IsWellKnownTemplateExpression(this ITaggedTemplateExpression node, out string name)
        {
            Contract.Requires(node != null);

            if (node.Tag.Kind == SyntaxKind.Identifier)
            {
                name = node.Tag.Cast <IIdentifier>().Text;
                return(Scanner.IsPathLikeInterpolationFactory(name));
            }

            name = null;
            return(false);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Checks if this tagged template is a path interpolation such that it can contains path separators
        /// </summary>
        public static bool IsPathInterpolation(this ITaggedTemplateExpression taggedTemplateExpression)
        {
            switch (taggedTemplateExpression.GetInterpolationKind())
            {
            case InterpolationKind.FileInterpolation:
            case InterpolationKind.DirectoryInterpolation:
            case InterpolationKind.PathInterpolation:
            case InterpolationKind.RelativePathInterpolation:
                return(true);

            default:
                return(false);
            }
        }
Ejemplo n.º 6
0
            public ProcessedTagTemplateExpression(
                ITaggedTemplateExpression taggedTemplate,
                InterpolationKind kind,
                ILiteralExpression literal,
                ITemplateLiteralFragment head,
                INodeArray <ITemplateSpan> templateSpans)
            {
                Contract.Requires(taggedTemplate != null);
                Contract.Requires(
                    kind == InterpolationKind.Unknown || (literal != null || (head != null && templateSpans != null)),
                    "If interpolation is a well-known factory method, then Literal or Head+Templates should be valid.");

                TaggedTemplate = taggedTemplate;
                Kind           = kind;
                Literal        = literal;
                Head           = head;
                TemplateSpans  = templateSpans;
            }
Ejemplo n.º 7
0
        /// <summary>
        /// Returns kind of interpolated string.
        /// </summary>
        public static InterpolationKind GetInterpolationKind(this ITaggedTemplateExpression taggedTemplateExpression)
        {
            Contract.Requires(taggedTemplateExpression != null);

            string tag = taggedTemplateExpression.GetTagText();

            if (string.IsNullOrEmpty(tag))
            {
                return(InterpolationKind.StringInterpolation);
            }

            if (tag.Length != 1)
            {
                return(InterpolationKind.Unknown);
            }

            switch (tag[0])
            {
            case Names.PathInterpolationFactory:
                return(InterpolationKind.PathInterpolation);

            case Names.FileInterpolationFactory:
                return(InterpolationKind.FileInterpolation);

            case Names.DirectoryInterpolationFactory:
                return(InterpolationKind.DirectoryInterpolation);

            case Names.RelativePathInterpolationFactory:
                return(InterpolationKind.RelativePathInterpolation);

            case Names.PathAtomInterpolationFactory:
                return(InterpolationKind.PathAtomInterpolation);

            default:
                return(InterpolationKind.Unknown);
            }
        }
Ejemplo n.º 8
0
        private static int CompareTaggedTemplateExpression(ITaggedTemplateExpression left, ITaggedTemplateExpression right)
        {
            // Standard left,right and null checks
            if (left == null && right == null)
            {
                return(0);
            }
            if (left == null)
            {
                return(1);
            }
            if (right == null)
            {
                return(-1);
            }

            // Compare tag
            var result = CompareNodeAsText(left.Tag, right.Tag);

            if (result != 0)
            {
                return(result);
            }

            // Special case check for path literal.
            var  interpolationKind       = left.GetInterpolationKind();
            bool usePathCompareSemantics = false;

            switch (interpolationKind)
            {
            case InterpolationKind.PathInterpolation:
            case InterpolationKind.FileInterpolation:
            case InterpolationKind.DirectoryInterpolation:
            case InterpolationKind.RelativePathInterpolation:
                usePathCompareSemantics = true;
                break;
            }

            var leftIsLiteral  = IsTemplateLiteral(left.TemplateExpression);
            var rightIsLiteral = IsTemplateLiteral(right.TemplateExpression);

            ITemplateExpression leftTemplate;
            ITemplateExpression rightTemplate;

            if (leftIsLiteral)
            {
                if (rightIsLiteral)
                {
                    return(CompareStringLiteralExpression(left.TemplateExpression.Cast <ILiteralExpression>(), right.TemplateExpression.Cast <ILiteralExpression>(), usePathCompareSemantics));
                }

                leftTemplate = new TemplateExpression()
                {
                    Head = new TemplateLiteralFragment()
                    {
                        Text = left.TemplateExpression.GetTemplateText()
                    }, TemplateSpans = NodeArray <ITemplateSpan> .Empty
                };
                rightTemplate = right.TemplateExpression.Cast <ITemplateExpression>();
            }
            else if (rightIsLiteral)
            {
                leftTemplate  = left.TemplateExpression.Cast <ITemplateExpression>();
                rightTemplate = new TemplateExpression()
                {
                    Head = new TemplateLiteralFragment()
                    {
                        Text = right.TemplateExpression.GetTemplateText()
                    }, TemplateSpans = NodeArray <ITemplateSpan> .Empty
                };
            }
            else
            {
                leftTemplate  = left.TemplateExpression.Cast <ITemplateExpression>();
                rightTemplate = right.TemplateExpression.Cast <ITemplateExpression>();
            }

            return(CompareTemplateExpression(leftTemplate, rightTemplate, usePathCompareSemantics));
        }
Ejemplo n.º 9
0
 /// <summary>
 /// Checks if this tagged template is a path interpolation such that it can contains path separators
 /// </summary>
 public static bool IsPathInterpolation(this ITaggedTemplateExpression taggedTemplateExpression)
 {
     return(InterpolationUtilities.IsPathInterpolation(taggedTemplateExpression));
 }
Ejemplo n.º 10
0
        /// <summary>
        /// Deconstructs a template expression.
        /// </summary>
        /// <remarks>
        /// "pattern matches" a tagged template expression into two cases:
        /// 1. Literal case like <code>p`string literal`</code> (in this case <paramref name="literal"/> would not be null).
        /// 2. Template expression case like <code>p`{foo}</code> (in this case <paramref name="head"/> and <paramref name="templateSpans"/> are not null).
        /// </remarks>
        public static void Deconstruct(
            [CanBeNull] this ITaggedTemplateExpression node,
            out InterpolationKind kind,
            out ILiteralExpression literal,
            out ITemplateLiteralFragment head,
            out INodeArray <ITemplateSpan> templateSpans)
        {
            kind          = InterpolationKind.Unknown;
            literal       = null;
            head          = null;
            templateSpans = null;

            if (node == null)
            {
                return;
            }

            if (node.Tag.Kind != SyntaxKind.Identifier)
            {
                // Looks like the tagged expression is invalid.
                return;
            }

            var text = node.Tag.Cast <IIdentifier>().Text;

            kind = GetInterpolationKind(text);

            if (kind == InterpolationKind.Unknown)
            {
                return;
            }

            literal = node.TemplateExpression.As <ILiteralExpression>();
            if (literal == null)
            {
                // This is another case: tagged template actually has template expressions.
                var template = node.TemplateExpression.Cast <ITemplateExpression>();
                head          = template.Head;
                templateSpans = template?.TemplateSpans;

                Contract.Assert(head != null);
                Contract.Assert(templateSpans != null);
            }

            InterpolationKind GetInterpolationKind(string factoryName)
            {
                if (factoryName.Length == 0)
                {
                    return(InterpolationKind.StringInterpolation);
                }

                var c = factoryName[0];

                switch (c)
                {
                case Names.PathInterpolationFactory:
                    return(InterpolationKind.PathInterpolation);

                case Names.DirectoryInterpolationFactory:
                    return(InterpolationKind.DirectoryInterpolation);

                case Names.FileInterpolationFactory:
                    return(InterpolationKind.FileInterpolation);

                case Names.RelativePathInterpolationFactory:
                    return(InterpolationKind.RelativePathInterpolation);

                case Names.PathAtomInterpolationFactory:
                    return(InterpolationKind.PathAtomInterpolation);

                default:
                    return(InterpolationKind.Unknown);
                }
            }
        }