Esempio n. 1
0
        /*********
        ** Private methods
        *********/
        /// <summary>Parse a sequence of lexical character patterns into higher-level lexical tokens.</summary>
        /// <param name="input">The lexical character patterns to parse.</param>
        /// <param name="impliedBraces">Whether we're parsing a token context (so the outer '{{' and '}}' are implied); else parse as a tokenizable string which main contain a mix of literal and {{token}} values.</param>
        /// <param name="trim">Whether the value should be trimmed.</param>
        private IEnumerable <ILexToken> ParseBitQueue(Queue <LexBit> input, bool impliedBraces, bool trim)
        {
            // perform a raw parse
            IEnumerable <ILexToken> RawParse()
            {
                // 'Implied braces' means we're parsing inside a token. This necessarily starts with a token name,
                // optionally followed by input arguments.
                if (impliedBraces)
                {
                    while (input.Any())
                    {
                        // extract token
                        yield return(this.ExtractToken(input, impliedBraces: true));

                        if (!input.Any())
                        {
                            yield break;
                        }

                        // throw error if there's content after the token ends
                        var next = input.Peek();
                        throw new LexFormatException($"Unexpected {next.Type}, expected {LexBitType.Literal}");
                    }
                    yield break;
                }

                // Otherwise this is a tokenizable string which may contain a mix of literal and {{token}} values.
                while (input.Any())
                {
                    LexBit next = input.Peek();
                    switch (next.Type)
                    {
                    // start token
                    case LexBitType.StartToken:
                        yield return(this.ExtractToken(input, impliedBraces: false));

                        break;

                    // text/separator outside token
                    case LexBitType.Literal:
                    case LexBitType.PositionalInputArgSeparator:
                    case LexBitType.NamedInputArgSeparator:
                        input.Dequeue();
                        yield return(new LexTokenLiteral(next.Text));

                        break;

                    // anything else is invalid
                    default:
                        throw new LexFormatException($"Unexpected {next.Type}, expected {LexBitType.StartToken} or {LexBitType.Literal}");
                    }
                }
            }

            string rawInput = string.Join("", input.Select(p => p.Text));
            LinkedList <ILexToken> tokens;

            try
            {
                tokens = new LinkedList <ILexToken>(RawParse());
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException($"Error parsing '{rawInput}' as a tokenizable string", ex);
            }

            // normalize literal values
            ISet <LinkedListNode <ILexToken> > removeQueue = new HashSet <LinkedListNode <ILexToken> >(new ObjectReferenceComparer <LinkedListNode <ILexToken> >());

            for (LinkedListNode <ILexToken> node = tokens.First; node != null; node = node.Next)
            {
                // fetch info
                if (!(node.Value is LexTokenLiteral current))
                {
                    continue;
                }
                ILexToken previous = node.Previous?.Value;
                ILexToken next     = node.Next?.Value;
                string    newText  = current.Text;

                // collapse sequential literals
                if (previous is LexTokenLiteral prevLiteral)
                {
                    newText = prevLiteral.Text + newText;
                    removeQueue.Add(node.Previous);
                }

                // trim before/after separator
                if (next?.Type == LexTokenType.TokenInput)
                {
                    newText = newText.TrimEnd();
                }
                if (previous?.Type == LexTokenType.TokenInput)
                {
                    newText = newText.TrimStart();
                }

                // trim whole result
                if (trim && (previous == null || next == null))
                {
                    if (previous == null)
                    {
                        newText = newText.TrimStart();
                    }
                    if (next == null)
                    {
                        newText = newText.TrimEnd();
                    }

                    if (newText == "")
                    {
                        removeQueue.Add(node);
                    }
                }

                // replace value if needed
                if (current.Text != newText)
                {
                    current.MigrateTo(newText);
                }
            }
            foreach (LinkedListNode <ILexToken> entry in removeQueue)
            {
                tokens.Remove(entry);
            }

            // yield result
            return(tokens);
        }
Esempio n. 2
0
 private List <ILexToken> Next(ILexToken token, Match match, string line, int start, int end, List <ILexToken> ret)
 {
     Analize(line, start, match.Index, ret);
     ret.Add(token);
     return(Analize(line, match.Index + match.Length, end, ret));
 }
Esempio n. 3
0
 /*********
 ** Public methods
 *********/
 /// <summary>Construct an instance.</summary>
 /// <param name="lexToken">The underlying lex token.</param>
 /// <param name="input">The parsed version of <see cref="Input"/>.</param>
 public TokenStringPart(ILexToken lexToken, TokenString input)
 {
     this.LexToken  = lexToken;
     this.Input     = input;
     this.InputArgs = new InputArguments(input);
 }
Esempio n. 4
0
        /*********
        ** Private methods
        *********/
        /// <summary>Parse a sequence of lexical character patterns into higher-level lexical tokens.</summary>
        /// <param name="input">The lexical character patterns to parse.</param>
        /// <param name="impliedBraces">Whether we're parsing a token context (so the outer '{{' and '}}' are implied); else parse as a tokenisable string which main contain a mix of literal and {{token}} values.</param>
        /// <param name="trim">Whether the value should be trimmed.</param>
        private IEnumerable <ILexToken> ParseBitQueue(Queue <LexBit> input, bool impliedBraces, bool trim)
        {
            // perform a raw parse
            IEnumerable <ILexToken> RawParse()
            {
                // 'Implied braces' means we're parsing inside a token. This necessarily starts with a token name,
                // optionally followed by an input argument and token pipes.
                if (impliedBraces)
                {
                    while (input.Any())
                    {
                        yield return(this.ExtractToken(input, impliedBraces: true));

                        if (!input.Any())
                        {
                            yield break;
                        }

                        var next = input.Peek();
                        switch (next.Type)
                        {
                        case LexBitType.TokenPipe:
                            yield return(new LexTokenPipe(input.Dequeue().Text));

                            break;

                        default:
                            throw new InvalidOperationException($"Unexpected {next.Type}, expected {LexBitType.Literal} or {LexBitType.TokenPipe}");
                        }
                    }
                    yield break;
                }

                // Otherwise this is a tokenisable string which may contain a mix of literal and {{token}} values.
                while (input.Any())
                {
                    LexBit next = input.Peek();
                    switch (next.Type)
                    {
                    // start token
                    case LexBitType.StartToken:
                        yield return(this.ExtractToken(input, impliedBraces: false));

                        break;

                    // pipe/separator outside token
                    case LexBitType.Literal:
                    case LexBitType.TokenPipe:
                    case LexBitType.InputArgSeparator:
                        input.Dequeue();
                        yield return(new LexTokenLiteral(next.Text));

                        break;

                    // anything else is invalid
                    default:
                        throw new InvalidOperationException($"Unexpected {next.Type}, expected {LexBitType.StartToken} or {LexBitType.Literal}");
                    }
                }
            }

            // normalise literal values
            LinkedList <ILexToken> tokens = new LinkedList <ILexToken>(RawParse());
            IList <LinkedListNode <ILexToken> > removeQueue = new List <LinkedListNode <ILexToken> >();

            for (LinkedListNode <ILexToken> node = tokens.First; node != null; node = node.Next)
            {
                if (node.Value.Type != LexTokenType.Literal)
                {
                    continue;
                }

                // fetch info
                ILexToken current  = node.Value;
                ILexToken previous = node.Previous?.Value;
                ILexToken next     = node.Next?.Value;
                string    newText  = node.Value.Text;

                // collapse sequential literals
                if (previous?.Type == LexTokenType.Literal)
                {
                    newText = previous.Text + newText;
                    removeQueue.Add(node.Previous);
                }

                // trim before/after separator
                if (next?.Type == LexTokenType.TokenInput || next?.Type == LexTokenType.TokenPipe)
                {
                    newText = newText.TrimEnd();
                }
                if (previous?.Type == LexTokenType.TokenInput || previous?.Type == LexTokenType.TokenPipe)
                {
                    newText = newText.TrimStart();
                }

                // trim whole result
                if (trim && (previous == null || next == null))
                {
                    if (previous == null)
                    {
                        newText = newText.TrimStart();
                    }
                    if (next == null)
                    {
                        newText = newText.TrimEnd();
                    }

                    if (newText == "")
                    {
                        removeQueue.Add(node);
                    }
                }

                // replace value if needed
                if (newText != current.Text)
                {
                    node.Value = new LexTokenLiteral(newText);
                }
            }
            foreach (LinkedListNode <ILexToken> entry in removeQueue)
            {
                tokens.Remove(entry);
            }

            // yield result
            return(tokens);
        }