Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
CodeOutlineFilter.cs
Go to the documentation of this file.
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 
6 namespace Irony.Parsing {
7  [Flags]
8  public enum OutlineOptions {
9  None = 0,
10  ProduceIndents = 0x01,
11  CheckBraces = 0x02,
12  CheckOperator = 0x04, //to implement, auto line joining if line ends with operator
13  }
14 
15  public class CodeOutlineFilter : TokenFilter {
16 
17  public readonly OutlineOptions Options;
18  public readonly KeyTerm ContinuationTerminal; //Terminal
19 
20  GrammarData _grammarData;
21  Grammar _grammar;
22  ParsingContext _context;
23  bool _produceIndents;
24  bool _checkBraces, _checkOperator;
25 
26  public Stack<int> Indents = new Stack<int>();
30  public TokenStack OutputTokens = new TokenStack();
31  bool _isContinuation, _prevIsContinuation;
32  bool _isOperator, _prevIsOperator;
33  bool _doubleEof;
34 
35  #region constructor
36  public CodeOutlineFilter(GrammarData grammarData, OutlineOptions options, KeyTerm continuationTerminal) {
37  _grammarData = grammarData;
38  _grammar = grammarData.Grammar;
39  _grammar.LanguageFlags |= LanguageFlags.EmitLineStartToken;
40  Options = options;
41  ContinuationTerminal = continuationTerminal;
42  if (ContinuationTerminal != null)
43  if (!_grammar.NonGrammarTerminals.Contains(ContinuationTerminal))
44  _grammarData.Language.Errors.Add(GrammarErrorLevel.Warning, null, Resources.ErrOutlineFilterContSymbol, ContinuationTerminal.Name);
45  //"CodeOutlineFilter: line continuation symbol '{0}' should be added to Grammar.NonGrammarTerminals list.",
46  _produceIndents = OptionIsSet(OutlineOptions.ProduceIndents);
47  _checkBraces = OptionIsSet(OutlineOptions.CheckBraces);
48  _checkOperator = OptionIsSet(OutlineOptions.CheckOperator);
49  Reset();
50  }
51  #endregion
52 
53  public override void Reset() {
54  base.Reset();
55  Indents.Clear();
56  Indents.Push(0);
57  OutputTokens.Clear();
58  PreviousToken = null;
59  CurrentToken = null;
60  PreviousTokenLocation = new SourceLocation();
61  }
62 
63  public bool OptionIsSet(OutlineOptions option) {
64  return (Options & option) != 0;
65  }
66 
68  _context = context;
69  foreach (Token token in tokens) {
70  ProcessToken(token);
71  while (OutputTokens.Count > 0)
72  yield return OutputTokens.Pop();
73  }//foreach
74  }//method
75 
76  public void ProcessToken(Token token) {
77  SetCurrentToken(token);
78  //Quick checks
79  if (_isContinuation)
80  return;
81  var tokenTerm = token.Terminal;
82 
83  //check EOF
84  if (tokenTerm == _grammar.Eof) {
85  ProcessEofToken();
86  return;
87  }
88 
89  if (tokenTerm != _grammar.LineStartTerminal) return;
90  //if we are here, we have LineStart token on new line; first remove it from stream, it should not go to parser
91  OutputTokens.Pop();
92 
93  if (PreviousToken == null) return;
94 
95 
96  // first check if there was continuation symbol before
97  // or - if checkBraces flag is set - check if there were open braces
98  if (_prevIsContinuation || _checkBraces && _context.OpenBraces.Count > 0)
99  return; //no Eos token in this case
100  if (_prevIsOperator && _checkOperator)
101  return; //no Eos token in this case
102 
103  //We need to produce Eos token and indents (if _produceIndents is set).
104  // First check indents - they go first into OutputTokens stack, so they will be popped out last
105  if (_produceIndents) {
106  var currIndent = token.Location.Column;
107  var prevIndent = Indents.Peek();
108  if (currIndent > prevIndent) {
109  Indents.Push(currIndent);
110  PushOutlineToken(_grammar.Indent, token.Location);
111  } else if (currIndent < prevIndent) {
112  PushDedents(currIndent);
113  //check that current indent exactly matches the previous indent
114  if (Indents.Peek() != currIndent) {
115  //fire error
116  OutputTokens.Push(new Token(_grammar.SyntaxError, token.Location, string.Empty, Resources.ErrInvDedent));
117  // "Invalid dedent level, no previous matching indent found."
118  }
119  }
120  }//if _produceIndents
121  //Finally produce Eos token, but not in command line mode. In command line mode the Eos was already produced
122  // when we encountered Eof on previous line
123  if (_context.Mode != ParseMode.CommandLine) {
124  var eosLocation = ComputeEosLocation();
125  PushOutlineToken(_grammar.Eos, eosLocation);
126  }
127 
128  }//method
129 
130  private void SetCurrentToken(Token token) {
131  _doubleEof = CurrentToken != null && CurrentToken.Terminal == _grammar.Eof
132  && token.Terminal == _grammar.Eof;
133  //Copy CurrentToken to PreviousToken
134  if (CurrentToken != null && CurrentToken.Category == TokenCategory.Content) { //remember only content tokens
135  PreviousToken = CurrentToken;
136  _prevIsContinuation = _isContinuation;
137  _prevIsOperator = _isOperator;
138  if (PreviousToken != null)
139  PreviousTokenLocation = PreviousToken.Location;
140  }
141  CurrentToken = token;
142  _isContinuation = (token.Terminal == ContinuationTerminal && ContinuationTerminal != null);
143  _isOperator = token.Terminal.FlagIsSet(TermFlags.IsOperator);
144  if (!_isContinuation)
145  OutputTokens.Push(token); //by default input token goes to output, except continuation symbol
146  }
147 
148  //Processes Eof token. We should take into account the special case of processing command line input.
149  // In this case we should not automatically dedent all stacked indents if we get EOF.
150  // Note that tokens will be popped from the OutputTokens stack and sent to parser in the reverse order compared to
151  // the order we pushed them into OutputTokens stack. We have Eof already in stack; we first push dedents, then Eos
152  // They will come out to parser in the following order: Eos, Dedents, Eof.
153  private void ProcessEofToken() {
154  //First decide whether we need to produce dedents and Eos symbol
155  bool pushDedents = false;
156  bool pushEos = true;
157  switch (_context.Mode) {
158  case ParseMode.File:
159  pushDedents = _produceIndents; //Do dedents if token filter tracks indents
160  break;
161  case ParseMode.CommandLine:
162  //only if user entered empty line, we dedent all
163  pushDedents = _produceIndents && _doubleEof;
164  pushEos = !_prevIsContinuation && !_doubleEof; //if previous symbol is continuation symbol then don't push Eos
165  break;
166  case ParseMode.VsLineScan:
167  pushDedents = false; //Do not dedent at all on every line end
168  break;
169  }
170  //unindent all buffered indents;
171  if (pushDedents) PushDedents(0);
172  //now push Eos token - it will be popped first, then dedents, then EOF token
173  if (pushEos) {
174  var eosLocation = ComputeEosLocation();
175  PushOutlineToken(_grammar.Eos, eosLocation);
176  }
177  }
178 
179  private void PushDedents(int untilPosition) {
180  while (Indents.Peek() > untilPosition) {
181  Indents.Pop();
182  PushOutlineToken(_grammar.Dedent, CurrentToken.Location);
183  }
184  }
185 
186  private SourceLocation ComputeEosLocation() {
187  if (PreviousToken == null)
188  return new SourceLocation();
189  //Return position at the end of previous token
190  var loc = PreviousToken.Location;
191  var len = PreviousToken.Length;
192  return new SourceLocation(loc.Position + len, loc.Line, loc.Column + len);
193  }
194 
195  private void PushOutlineToken(Terminal term, SourceLocation location) {
196  OutputTokens.Push(new Token(term, location, string.Empty, null));
197  }
198 
199  }//class
200 }//namespace
TokenCategory
Token category.
Definition: Token.cs:29
A strongly-typed resource class, for looking up localized strings, etc.
static string ErrOutlineFilterContSymbol
Looks up a localized string similar to CodeOutlineFilter: line continuation symbol '{0}' should be ad...
static string ErrInvDedent
Looks up a localized string similar to Invalid dedent level, no previous matching indent found...
override IEnumerable< Token > BeginFiltering(ParsingContext context, IEnumerable< Token > tokens)
A Stack of tokens.
Definition: Token.cs:67
Flags
Enumeration of the new Assimp's flags.
bool OptionIsSet(OutlineOptions option)
readonly SourceLocation Location
Location in the source code.
Definition: Token.cs:116
static SourceLocation Empty
CodeOutlineFilter(GrammarData grammarData, OutlineOptions options, KeyTerm continuationTerminal)
Tokens are produced by scanner and fed to parser, optionally passing through Token filters in between...
Definition: Token.cs:74
readonly OutlineOptions Options