Ejemplo n.º 1
0
        private bool ReadStartSymbol(ISourceStream source, CompoundTokenDetails details)
        {
            if (!_startSymbolsFirsts.Contains(source.PreviewChar))
            {
                return(false);
            }

            foreach (var subType in _subTypes)
            {
                if (!source.MatchSymbol(subType.Start))
                {
                    continue;
                }

                var previewPos = source.PreviewPosition;
                source.PreviewPosition += subType.Start.Length;
                Grammar.SkipWhitespace(source, true);

                string quote = null;
                // Search if there should be a quote.
                if (subType.Quotes.Count > 0)
                {
                    // Must be quoted.
                    var quoteMatchSuccessful = false;
                    foreach (var q in subType.Quotes)
                    {
                        // TODO: what if not case sensitive?
                        if (!source.MatchSymbol(q))
                        {
                            continue;
                        }
                        quoteMatchSuccessful = true;
                        quote = q;
                    }
                    if (!quoteMatchSuccessful)
                    {
                        // Revert, revert!
                        source.PreviewPosition = previewPos;
                        continue;
                    }
                }

                // Now the preview position is at the beginning of quotes, or the name.
                var sb          = new StringBuilder();
                var previewChar = source.PreviewChar;
                while (previewChar != '\r' && previewChar != '\n')
                {
                    sb.Append(previewChar);
                    ++source.PreviewPosition;
                    previewChar = source.PreviewChar;
                }

                var endLiteral = sb.ToString();
                if (quote != null)
                {
                    var comparisonType = QuoteCaseSensitive ? StringComparison.InvariantCulture : StringComparison.InvariantCultureIgnoreCase;
                    // Check the quotes.
                    if (!(endLiteral.StartsWith(quote, comparisonType) && endLiteral.EndsWith(quote, comparisonType)))
                    {
                        // Malformed end literal.
                        return(false);
                    }
                    else
                    {
                        endLiteral = endLiteral.Substring(quote.Length, endLiteral.Length - quote.Length * 2);
                    }
                }

                int elStart = 0, elEnd = endLiteral.Length - 1;
                // Trim
                while (elStart < endLiteral.Length && Grammar.IsWhitespace(endLiteral[elStart]))
                {
                    elStart++;
                }
                while (elEnd >= 0 && Grammar.IsWhitespace(endLiteral[elEnd]))
                {
                    elStart--;
                }
                if (elEnd <= elStart)
                {
                    // Malformed end literal.
                    return(false);
                }

                if (elStart != 0 || elEnd != endLiteral.Length - 1)
                {
                    endLiteral = endLiteral.Substring(elStart, elEnd - elStart + 1);
                }

                //We found start symbol
                details.StartSymbol  = subType.Start;
                details.Flags       |= (short)subType.Flags;
                details.TokenName    = endLiteral;
                details.TokenQuote   = quote;
                details.SubTypeIndex = subType.Index;
                // No need to set source.PreviewPosition, we've done it.
                return(true);
            }
            return(false);
        }
Ejemplo n.º 2
0
        private bool CompleteReadBody(ISourceStream source, CompoundTokenDetails details)
        {
            var escapeEnabled  = !details.IsSet((short)HereDocOptions.NoEscapes);
            var start          = source.PreviewPosition;
            var endQuoteSymbol = details.TokenName;

            //1. Find the string end
            // first get the position of the next line break; we are interested in it to detect malformed string,
            //  therefore do it only if linebreak is NOT allowed; if linebreak is allowed, set it to -1 (we don't care).
            // MIC: in heredoc, multiline is always allowed.

            //fix by ashmind for EOF right after opening symbol
            while (true)
            {
                var endPos = source.Text.IndexOf(endQuoteSymbol, source.PreviewPosition, StringComparison.InvariantCulture);
                //Check for partial token in line-scanning mode
                if (endPos < 0 && details.PartialOk)
                {
                    ProcessPartialBody(source, details);
                    return(true);
                }
                //Check for malformed string: either EndSymbol not found, or LineBreak is found before EndSymbol
                var malformed = endPos < 0;
                if (malformed)
                {
                    if (endPos > 0)
                    {
                        source.PreviewPosition = endPos + 1;
                    }
                    details.Error = Resources.ErrBadStrLiteral; //    "Mal-formed  string literal - cannot find termination symbol.";
                    return(true);                               //we did find start symbol, so it is definitely string, only malformed
                }

                if (source.EOF)
                {
                    return(true);
                }

                //We found EndSymbol - check if it is escaped; if yes, skip it and continue search
                if (escapeEnabled && IsEndQuoteEscaped(source.Text, endPos))
                {
                    source.PreviewPosition = endPos + endQuoteSymbol.Length;
                    continue; //searching for end symbol
                }

                // Check if not correctly indented.
                if (source.Text[endPos - 1] != '\n' && !details.IsSet((short)HereDocOptions.AllowIndentedEndToken))
                {
                    return(false);
                }

                //Ok, this is normal endSymbol that terminates the string.
                // Advance source position and get out from the loop
                source.PreviewPosition = endPos + endQuoteSymbol.Length;


                var indent = 0;
                // Remove the last newline.
                while (source.Text[endPos] != '\n')
                {
                    // Remove the indentations.
                    --endPos;
                    ++indent;
                }
                // Compensation for the extra '\n'.
                --indent;
                // Text[endPos] is now always \n.
                if (source.Text[endPos - 1] == '\r')
                {
                    --endPos;
                }

                if (details.IsSet((short)HereDocOptions.RemoveBeginningNewLine))
                {
                    if (source.Text[start] == '\r')
                    {
                        start += 2;
                    }
                    else
                    {
                        start += 1;
                    }
                }

                var body = source.Text.Substring(start, endPos - start);
                if (details.IsSet((short)HereDocOptions.AllowIndentedEndToken) && details.IsSet((short)HereDocOptions.RemoveIndents) && indent > 0)
                {
                    // Remove indentations.
                    var undented = false;
                    var lines    = body.Split('\n');
                    for (var i = 0; i < lines.Length; ++i)
                    {
                        var line = lines[i];
                        if (line.Length == 0 || !Grammar.IsWhitespace(line[0]))
                        {
                            continue;
                        }
                        var n = 0;
                        while (n < indent && n < line.Length && Grammar.IsWhitespace(line[n]))
                        {
                            ++n;
                        }
                        if (n != 0)
                        {
                            line     = n == line.Length ? string.Empty : line.Substring(n, line.Length - n);
                            lines[i] = line;
                            undented = true;
                        }
                    }
                    if (undented)
                    {
                        body = string.Join("\n", lines);
                    }
                }

                details.Body = body;
                //if we come here it means we're done - we found string end.
                return(true);
            }
        }