/// <nodoc /> public static int FitsOnOneLine(INodeArray <INode> nodes, int separatorSize, int remainingSpace) { if (nodes.IsNullOrEmpty()) { return(remainingSpace); } if (nodes.Count > 5) { // Always print more than 5 nodes on separate lines. return(-1); } int space = remainingSpace; foreach (var node in nodes.AsStructEnumerable()) { if (space != remainingSpace) { // Subtract space for separators on subsequent nodes space -= separatorSize; } space = FitsOnOneLine(node, space); if (space < 0) { // if it already doesn't fit, the rest won't fit either return(space); } } return(space); }
/// <nodoc/> public NodeOrNodesOrNull([NotNull] INode node) { Contract.Requires(node != null); Node = node; Nodes = null; }
private static int CompareNodeArrays <T>(INodeArray <T> left, INodeArray <T> right, Comparison <T> comparer) { var leftCount = left.Count; var rightCount = right.Count; for (int i = 0; i < leftCount; i++) { if (i >= rightCount) { return(1); // right is smaller } var result = comparer(left[i], right[i]); if (result != 0) { return(result); } } if (rightCount > leftCount) { return(-1); // left is smaller; } return(0); }
public static AccessorDeclarations GetAllAccessorDeclarations(INodeArray <IDeclaration> declarations, IAccessorDeclaration accessor) { IAccessorDeclaration firstAccessor = null; IAccessorDeclaration secondAccessor = null; IAccessorDeclaration getAccessor = null; IAccessorDeclaration setAccessor = null; if (HasDynamicName(accessor)) { firstAccessor = accessor; if (accessor.Kind == SyntaxKind.GetAccessor) { getAccessor = accessor; } else if (accessor.Kind == SyntaxKind.SetAccessor) { setAccessor = accessor; } else { Contract.Assert(false, "Accessor has wrong kind"); } } else { NodeArrayExtensions.ForEach(declarations, member => { if ((member.Kind == SyntaxKind.GetAccessor || member.Kind == SyntaxKind.SetAccessor) && (member.Flags & NodeFlags.Static) == (accessor.Flags & NodeFlags.Static)) { var memberName = GetPropertyNameForPropertyNameNode(member.Name); var accessorName = GetPropertyNameForPropertyNameNode(accessor.Name); if (memberName == accessorName) { if (firstAccessor == null) { firstAccessor = member.Cast <IAccessorDeclaration>(); } else if (secondAccessor == null) { secondAccessor = member.Cast <IAccessorDeclaration>(); } if (member.Kind == SyntaxKind.GetAccessor && getAccessor == null) { getAccessor = member.Cast <IAccessorDeclaration>(); } if (member.Kind == SyntaxKind.SetAccessor && setAccessor == null) { setAccessor = member.Cast <IAccessorDeclaration>(); } } } }); } return(new AccessorDeclarations(firstAccessor, secondAccessor, getAccessor, setAccessor)); }
public static T First <T>(this INodeArray <T> @this) { if (@this.Count == 0) { throw new InvalidOperationException("The sequence contains no elements"); } return(@this[0]); }
/// <nodoc /> public static T ElementAtOrDefault <T>(this INodeArray <T> @this, int index) { if (index < @this.Count) { return(@this[index]); } return(default(T)); }
private static T VisitNodeArray <T>(Func <NodeOrNodesOrNull, T> cbNodes, INodeArray <INode> nodes) { if (nodes != null) { return(cbNodes(new NodeOrNodesOrNull(nodes))); } return(default(T)); }
/// <summary> /// Calls a given callback for every element in a <paramref name="sequence"/>. /// </summary> public static void ForEach <TElement, TState>([CanBeNull] INodeArray <TElement> sequence, TState state, Action <TElement, TState> callback) { if (sequence == null) { return; } for (int i = 0; i < sequence.Count; i++) { callback(sequence[i], state); } }
private List <Expression> EnumerateTaggedExpressionsForPathAtomInterpolation( ITemplateLiteralFragment headNode, INodeArray <ITemplateSpan> templateSpans, FunctionScope escapes, QualifierSpaceId currentQualifierSpaceId) { // Creating a list that will hold all potential expressions List <Expression> result = new List <Expression>((templateSpans.Length * 2) + 1); string head = headNode.Text; if (!string.IsNullOrEmpty(head)) { var convertedPathAtomLiteral = m_literalConverter.ConvertPathAtomLiteral(head, Location(headNode)); if (convertedPathAtomLiteral == null) { // Error has been reported. return(null); } result.Add(convertedPathAtomLiteral); } foreach (var span in templateSpans.AsStructEnumerable()) { if (span.Expression != null) { var convertedExpression = m_converter.ConvertExpression(span.Expression, escapes, currentQualifierSpaceId); if (convertedExpression != null) { result.Add(convertedExpression); } } var fragment = span.Literal.Text; if (!string.IsNullOrEmpty(fragment)) { var convertedPathAtomLiteral = m_literalConverter.ConvertPathAtomLiteral(fragment, Location(span.Literal)); if (convertedPathAtomLiteral == null) { // Error has been reported. return(null); } result.Add(convertedPathAtomLiteral); } } return(result); }
private static T VisitEachNode <T>(Func <NodeOrNodesOrNull, T> cbNode, INodeArray <INode> nodes) where T : class { if (nodes != null) { foreach (var node in nodes.AsStructEnumerable()) { var result = cbNode(new NodeOrNodesOrNull(node)); if (result != null) { return(result); } } } return(default(T)); }
/// <summary> /// Iterates through <paramref name="array"/> and performs the callback on each element of array until the callback /// returns a truthy value, then returns that value. /// If no such value is found, the callback is applied to each element of array and default(T) is returned. /// </summary> public static TResult ForEachUntil <TElement, TResult>([CanBeNull] INodeArray <TElement> array, Func <TElement, TResult> callback) { if (array != null) { for (int i = 0; i < array.Count; i++) { var result = callback(array[i]); if (result != null) { return(result); } } } return(default(TResult)); }
/// <summary> /// Custom implementation for 'Any' LINQ-like method that accepts <code>null</code> as a collection value /// and avoid allocations during collection enumeration. /// </summary> public static bool Any <TElement>([CanBeNull] INodeArray <TElement> sequence, Func <TElement, bool> callback) { if (sequence == null) { return(false); } for (int i = 0; i < sequence.Count; i++) { var result = callback(sequence[i]); if (result) { return(true); } } return(false); }
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; }
/// <summary> /// Returns the first /// </summary> public static T First <T>(this INodeArray <T> array) { return(NodeArrayExtensions.First(array)); }
public Enumerator(Switch sw) { this.sw = sw; nextArray = sw.NextArray; index = sw.curIndex; sw.curIndex++; position = 0; }
private List <Expression> EnumerateTemplateSpans( ITemplateLiteralFragment headNode, INodeArray <ITemplateSpan> templateSpans, FunctionScope escapes, QualifierSpaceId currentQualifierSpaceId, bool isRelativePath) { Contract.Requires(headNode != null); Contract.Requires(templateSpans != null); // Creating a list that will hold all potential expressions List <Expression> result = new List <Expression>((templateSpans.Length * 2) + 1); // Example: 'path/to/{x}/abc/{y}'. // - Head is 'path/to/' // - Spans: // 1. '{x}/abc/': expr 'x', literal '/abc/' // 2. '{y}': expr 'y', no literal. // For instance in this case: p`foo/${x}/${y}` the result equals p`foo`.combine(x).combine(y); // and for this case: p`${x}` the result equals x. // Note that p`path/to/abc` equals as p`./path/to/abc`. Thus for p`${x}/path/to/abc`, x should evaluate to an absolute path, // and such a construct equals x.combine("path").combine("to"). combine("abc"). string head = headNode.Text; if (!string.IsNullOrEmpty(head)) { // Example: 'path/to/' if (!HasTailingPathSeparator(head)) { string message = I($"Path fragment '{head}' does not have a tailing path separator."); RuntimeModelContext.Logger.ReportInvalidPathInterpolationExpression( RuntimeModelContext.LoggingContext, Location(headNode).AsLoggingLocation(), message); return(null); } if (!isRelativePath) { // Tagged expression is expected to be an absolute path. var convertedPathLiteral = m_literalConverter.ConvertPathLiteral( RemoveLeadingAndTailingPathSeparatorIfNeeded(head, isAbsolutePath: true), Location(headNode)); if (convertedPathLiteral == null) { // Error has been reported. return(null); } result.Add(convertedPathLiteral); } else { // Tagged expression is expected to be a relative path. var convertedRelativePathLiteral = m_literalConverter.ConvertRelativePathLiteral( RemoveLeadingAndTailingPathSeparatorIfNeeded(head, isAbsolutePath: false), Location(headNode)); if (convertedRelativePathLiteral == null) { // Error has been reported. return(null); } result.Add(convertedRelativePathLiteral); } } for (int i = 0; i < templateSpans.Length; i++) { //// TODO: Currently fragment is string literal. This somehow defeats the purpose of paths. //// TODO: We need to find a syntactic representation of relative path that differs from string. var span = templateSpans[i]; // Example: span is '{x}/abc/'. if (span.Expression != null) { // Grab 'x' from '{x}/abc/'. var convertedExpression = m_converter.ConvertExpression(span.Expression, escapes, currentQualifierSpaceId); if (convertedExpression != null) { result.Add(convertedExpression); } } // Fragment is '/abc/'. var fragment = span.Literal.Text; // For every expression (except last one), interpolated path should have a separator if (string.IsNullOrEmpty(fragment) && span.Expression != null) { // Fragment is empty or consists only of whitespaces, but expression is present, e.g., span (2) -- '{y}'. if (i == templateSpans.Length - 1) { // Last template span, nothing to do, separator could be empty. continue; } // Not the last template span, thus needs a path separator. string message = "Each path fragment in interpolated path literal should have a path separator between expressions."; RuntimeModelContext.Logger.ReportInvalidPathInterpolationExpression( RuntimeModelContext.LoggingContext, Location(span.Literal).AsLoggingLocation(), message); return(null); } // Skip if fragment is only a separator, e.g., '{w}/{z}'. if (IsPathSeparator(fragment)) { continue; } // Fragments should start with path separator, e.g., '/abc/'. if (!HasLeadingPathSeparator(fragment)) { string message = I($"Path fragment '{fragment}' does not have a leading path separator."); RuntimeModelContext.Logger.ReportInvalidPathInterpolationExpression( RuntimeModelContext.LoggingContext, Location(span.Literal).AsLoggingLocation(), message); return(null); } // All fragments except last one must have a trailing separator, e.g., '/abc/'. if (i != templateSpans.Length - 1 && !HasTailingPathSeparator(fragment)) { string message = I($"Path fragment '{fragment}' does not have a trailing path separator."); RuntimeModelContext.Logger.ReportInvalidPathInterpolationExpression( RuntimeModelContext.LoggingContext, Location(span.Literal).AsLoggingLocation(), message); return(null); } // Remove '/' from '/abc/'. var textFragment = RemoveLeadingAndTailingPathSeparatorIfNeeded(fragment, isAbsolutePath: false); string literal = textFragment.Length == fragment.Length ? fragment : textFragment.ToString(); result.Add(new StringLiteral(literal, LineInfo(span.Literal))); } return(result); }
/// <nodoc/> public NodeOrNodesOrNull([NotNull] INodeArray <INode> nodes) { Contract.Requires(nodes != null); Node = null; Nodes = nodes; }
/// <nodoc /> public static NodeArray.NodeArraySelectorEnumerable <TSource, TResult> Select <TSource, TResult>(this INodeArray <TSource> sequence, Func <TSource, TResult> selector) { return(new NodeArray.NodeArraySelectorEnumerable <TSource, TResult>(sequence, selector)); }
/// <nodoc /> public NodeOrNodeArray(INodeArray <INode> nodes) : this() { Nodes = nodes; }
private static NodeOrNodeArray Nodes([NotNull] INodeArray <INode> nodes) { return(new NodeOrNodeArray(nodes)); }
/// <summary> /// Returns true when <paramref name="array"/> is null or empty. /// </summary> public static bool IsNullOrEmpty <T>([CanBeNull] this INodeArray <T> array) { return(array == null || array.Count == 0); }
/// <summary> /// Returns true when <paramref name="array"/> is null or empty. /// </summary> public static bool IsNullOrEmpty <T>(this INodeArray <T> array) { return(NodeArrayExtensions.IsNullOrEmpty(array)); }
/// <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); } } }
/// <nodoc /> public static T FirstOrDefault <T>(this INodeArray <T> @this) { return(@this.Count == 0 ? default(T) : @this[0]); }