Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
CommentTerminal.cs
Go to the documentation of this file.
1 #region License
2 /* **********************************************************************************
3  * Copyright (c) Roman Ivantsov
4  * This source code is subject to terms and conditions of the MIT License
5  * for Irony. A copy of the license can be found in the License.txt file
6  * at the root of this distribution.
7  * By using this source code in any fashion, you are agreeing to be bound by the terms of the
8  * MIT License.
9  * You must not remove this notice from this software.
10  * **********************************************************************************/
11 #endregion
12 
13 using System;
14 using System.Collections.Generic;
15 using System.Text;
16 
17 namespace Irony.Parsing {
18 
19  public class CommentTerminal : Terminal {
20  public CommentTerminal(string name, string startSymbol, params string[] endSymbols) : base(name, TokenCategory.Comment) {
21  this.StartSymbol = startSymbol;
22  this.EndSymbols = new StringList();
23  EndSymbols.AddRange(endSymbols);
24  Priority = Terminal.HighestPriority; //assign max priority
25  }
26 
27  public string StartSymbol;
29  private char[] _endSymbolsFirsts;
30  private bool _isLineComment; //true if NewLine is one of EndSymbols; if yes, EOF is also considered a valid end symbol
31 
32 
33  #region overrides
34  public override void Init(GrammarData grammarData) {
35  base.Init(grammarData);
36  //_endSymbolsFirsts char array is used for fast search for end symbols using String's method IndexOfAny(...)
37  _endSymbolsFirsts = new char[EndSymbols.Count];
38  for (int i = 0; i < EndSymbols.Count; i++) {
39  string sym = EndSymbols[i];
40  _endSymbolsFirsts[i] = sym[0];
41  _isLineComment |= sym.Contains("\n");
42  if (!_isLineComment)
43  SetFlag(TermFlags.IsMultiline);
44  }
45  if (this.EditorInfo == null) {
46  TokenType ttype = _isLineComment ? TokenType.LineComment : TokenType.Comment;
47  this.EditorInfo = new TokenEditorInfo(ttype, TokenColor.Comment, TokenTriggers.None);
48  }
49  }
50 
51  public override Token TryMatch(ParsingContext context, ISourceStream source) {
52  Token result;
53  if (context.VsLineScanState.Value != 0) {
54  // we are continuing in line mode - restore internal env (none in this case)
55  context.VsLineScanState.Value = 0;
56  } else {
57  //we are starting from scratch
58  if (!BeginMatch(context, source)) return null;
59  }
60  result = CompleteMatch(context, source);
61  if (result != null) return result;
62  //if it is LineComment, it is ok to hit EOF without final line-break; just return all until end.
63  if (_isLineComment)
64  return source.CreateToken(this.OutputTerminal);
65  if (context.Mode == ParseMode.VsLineScan)
66  return CreateIncompleteToken(context, source);
67  return source.CreateErrorToken(Resources.ErrUnclosedComment);
68  }
69 
70  private Token CreateIncompleteToken(ParsingContext context, ISourceStream source) {
71  source.PreviewPosition = source.Text.Length;
72  Token result = source.CreateToken(this.OutputTerminal);
73  result.Flags |= TokenFlags.IsIncomplete;
74  context.VsLineScanState.TerminalIndex = this.MultilineIndex;
75  return result;
76  }
77 
78  private bool BeginMatch(ParsingContext context, ISourceStream source) {
79  //Check starting symbol
80  if (!source.MatchSymbol(StartSymbol, !Grammar.CaseSensitive)) return false;
81  source.PreviewPosition += StartSymbol.Length;
82  return true;
83  }
84  private Token CompleteMatch(ParsingContext context, ISourceStream source) {
85  //Find end symbol
86  while (!source.EOF()) {
87  int firstCharPos;
88  if (EndSymbols.Count == 1)
89  firstCharPos = source.Text.IndexOf(EndSymbols[0], source.PreviewPosition);
90  else
91  firstCharPos = source.Text.IndexOfAny(_endSymbolsFirsts, source.PreviewPosition);
92  if (firstCharPos < 0) {
93  source.PreviewPosition = source.Text.Length;
94  return null; //indicating error
95  }
96  //We found a character that might start an end symbol; let's see if it is true.
97  source.PreviewPosition = firstCharPos;
98  foreach (string endSymbol in EndSymbols) {
99  if (source.MatchSymbol(endSymbol, !Grammar.CaseSensitive)) {
100  //We found end symbol; eat end symbol only if it is not line comment.
101  // For line comment, leave LF symbol there, it might be important to have a separate LF token
102  if (!_isLineComment)
103  source.PreviewPosition += endSymbol.Length;
104  return source.CreateToken(this.OutputTerminal);
105  }//if
106  }//foreach endSymbol
107  source.PreviewPosition++; //move to the next char and try again
108  }//while
109  return null; //might happen if we found a start char of end symbol, but not the full endSymbol
110  }//method
111 
112  public override IList<string> GetFirsts() {
113  return new string[] { StartSymbol };
114  }
115  #endregion
116  }//CommentTerminal class
117 
118 
119 }
TokenCategory
Token category.
Definition: Token.cs:29
override void Init(GrammarData grammarData)
override Token TryMatch(ParsingContext context, ISourceStream source)
CommentTerminal(string name, string startSymbol, params string[] endSymbols)
Interface for Terminals to access the source stream and produce tokens.
static string ErrUnclosedComment
Looks up a localized string similar to Unclosed comment block.
override IList< string > GetFirsts()
VsScannerStateMap VsLineScanState
Comment category.
Tokens are produced by scanner and fed to parser, optionally passing through Token filters in between...
Definition: Token.cs:74