예제 #1
0
        public IEnumerable <Token <R> > ReadToScopeClose(R open, R close, Delimiters bracketPairs)
        {
            SkipSpace();
            _stack.Clear();
            Token <R> token = null;

            while (!End)
            {
                token = ReadToken();
                bool literalCheck = !bracketPairs.Contains(token.ID, token.ID) ||
                                    (_stack.Any()
                    ? _stack.Peek().ID == token.ID
                    : open == token.ID);

                if (literalCheck && (bracketPairs.ContainsClosing(token.ID) || token.ID == close)) // Allows nesting
                {
                    // Since this method assumes that the first opening bracket was already read, an empty _stack indicates main scope closure.
                    if (!_stack.Any() && token.ID == close)
                    {
                        yield break;
                    }

                    var lastOpening = _stack.Pop();

                    if (!bracketPairs.Contains(lastOpening.ID, token.ID))
                    {
                        throw new RantException(_source, token,
                                                "Invalid closure '"
                                                + lastOpening.Value
                                                + " ... "
                                                + token.Value
                                                + "' - expected '"
                                                + RantLexer.Rules.GetSymbolForId(bracketPairs.GetClosing(lastOpening.ID))
                                                + "'");
                    }
                }
                else if (bracketPairs.ContainsOpening(token.ID) || open == token.ID) // Allows nesting
                {
                    _stack.Push(token);
                }
                yield return(token);
            }
            throw new RantException(_source, null, "Unexpected end of file; expected '" + RantLexer.Rules.GetSymbolForId(close) + "'.");
        }
예제 #2
0
        public IEnumerable <Token <R> > ReadToTokenInParentScope(R tokenType, Delimiters bracketPairs)
        {
            SkipSpace();
            _stack.Clear();
            Token <R> token = null;

            while (!End)
            {
                token = ReadToken();
                if (token.ID == tokenType && !_stack.Any())
                {
                    yield break;
                }
                if (bracketPairs.ContainsOpening(token.ID)) // Allows nesting
                {
                    _stack.Push(token);
                }
                else if (bracketPairs.ContainsClosing(token.ID)) // Allows nesting
                {
                    // Since this method assumes that the first opening bracket was already read, an empty _stack indicates main scope closure.
                    if (!_stack.Any())
                    {
                        throw new RantException(_source, token, "Unexpected token '\{token.Value}'");
                    }

                    var lastOpening = _stack.Pop();

                    if (!bracketPairs.Contains(lastOpening.ID, token.ID))
                    {
                        throw new RantException(_source, token,
                                                "Invalid closure '"
                                                + lastOpening.Value
                                                + " ... "
                                                + token.Value
                                                + "' - expected '"
                                                + RantLexer.Rules.GetSymbolForId(bracketPairs.GetClosing(lastOpening.ID))
                                                + "'");
                    }
                }
                yield return(token);
            }
            throw new RantException(_source, null, "Unexpected end of file; expected '\{RantLexer.Rules.GetSymbolForId(_stack.Any() ? bracketPairs.GetClosing(_stack.Peek().ID) : tokenType)}'.");
        }
예제 #3
0
        public IEnumerable <IEnumerable <Token <R> > > ReadMultiItemScope(R open, R close, R separator, Delimiters bracketPairs)
        {
            SkipSpace();
            _stack.Clear();

            // Assumes first bracket was already read.
            _stack.Push(new Token <R>(open, RantLexer.Rules.GetSymbolForId(open)));

            int       start = _pos;
            Token <R> token = null;

            while (!End)
            {
                // Peek but don't consume - this saves some calculations later on.
                token = PeekToken();

                bool literalCheck = !bracketPairs.Contains(token.ID, token.ID) || _stack.Peek().ID == token.ID;

                // Closing bracket
                if (literalCheck && (bracketPairs.ContainsClosing(token.ID) || close == token.ID)) // Previous bracket allows nesting
                {
                    var lastOpening = _stack.Pop();

                    // Handle invalid closures
                    if (!bracketPairs.Contains(lastOpening.ID, token.ID)) // Not in main pair
                    {
                        throw new RantException(_source, token,
                                                "Invalid closure '"
                                                + lastOpening.Value
                                                + " ... "
                                                + token.Value
                                                + "' - expected '"
                                                + RantLexer.Rules.GetSymbolForId(bracketPairs.GetClosing(lastOpening.ID))
                                                + "'");
                    }

                    // If the _stack is empty, this is the last item. Stop the iterator.
                    if (!_stack.Any())
                    {
                        yield return(_tokens
                                     .SkipWhile((t, i) => i < start)        // Cut to start of section
                                     .TakeWhile((t, i) => i < _pos - start) // Cut to end of section
                                     .SkipWhile(t => t.ID == R.Whitespace)  // Remove leading whitespace
                                     .Reverse()                             // Reverse to trim end
                                     .SkipWhile(t => t.ID == R.Whitespace)  // Remove trailing whitespace
                                     .Reverse()                             // Reverse back
                                     .ToArray());

                        _pos++;
                        yield break;
                    }
                }

                // Opening bracket
                else if (bracketPairs.ContainsOpening(token.ID) || open == token.ID) // Previous bracket allows nesting
                {
                    _stack.Push(token);
                }

                // Separator
                else if (token.ID == separator && _stack.Count == 1)
                {
                    yield return(_tokens
                                 .SkipWhile((t, i) => i < start)        // Cut to start of section
                                 .TakeWhile((t, i) => i < _pos - start) // Cut to end of section
                                 .SkipWhile(t => t.ID == R.Whitespace)  // Remove leading whitespace
                                 .Reverse()                             // Reverse to trim end
                                 .SkipWhile(t => t.ID == R.Whitespace)  // Remove trailing whitespace
                                 .Reverse()                             // Reverse back
                                 .ToArray());

                    _pos++;
                    start = _pos;
                    continue;
                }

                // Move to next position
                _pos++;
            }
            throw new RantException(_source, null, "Unexpected end of file - expected '" + RantLexer.Rules.GetSymbolForId(close) + "'.");
        }