public IEnumerable <Token <R> > ReadToScopeClose(R open, R close, Brackets bracketPairs) { SkipSpace(); _stack.Clear(); Token <R> token = null; while (!End) { token = ReadToken(); if (bracketPairs.ContainsOpening(token.ID) || open == token.ID) // Allows nesting { _stack.Push(token); } else if (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)) + "'"); } } yield return(token); } throw new RantException(_source, null, "Unexpected end of file - expected '" + RantLexer.Rules.GetSymbolForId(close) + "'."); }
public IEnumerable <IEnumerable <Token <R> > > ReadMultiItemScope(R open, R close, R separator, Brackets 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(); // Opening bracket if (bracketPairs.ContainsOpening(token.ID) || open == token.ID) // Previous bracket allows nesting { _stack.Push(token); } // Closing bracket else if (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; } } // 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) + "'."); }