Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
SourceStream.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 SourceStream : ISourceStream {
20  ScannerData _scannerData;
21  public const int DefaultTabWidth = 8;
22  private int _nextNewLinePosition = -1; //private field to cache position of next \n character
23 
24  public SourceStream(ScannerData scannerData, int tabWidth) {
25  _scannerData = scannerData;
26  TabWidth = tabWidth;
27  }
28 
29  public void SetText(string text, int offset, bool keepLineNumbering) {
30  Text = text;
31  //For line-by-line input, automatically increment line# for every new line
32  var line = keepLineNumbering ? _location.Line + 1 : 0;
33  Location = new SourceLocation(offset, line, 0);
34  _nextNewLinePosition = text.IndexOfAny(_scannerData.LineTerminatorsArray, offset);
35  }
36 
37  #region ISourceStream Members
38  public string Text {get; internal set;}
39 
40  public SourceLocation Location {
41  [System.Diagnostics.DebuggerStepThrough]
42  get { return _location; }
43  set {
44  _location = value;
45  PreviewPosition = _location.Position;
46  }
47  } SourceLocation _location;
48 
49  public int PreviewPosition {get; set; }
50 
51  public int TabWidth { get; set; }
52 
53  public char PreviewChar {
54  [System.Diagnostics.DebuggerStepThrough]
55  get {
56  if (PreviewPosition >= Text.Length) return '\0';
57  return Text[PreviewPosition];
58  }
59  }
60 
61  public char NextPreviewChar {
62  [System.Diagnostics.DebuggerStepThrough]
63  get {
64  if (PreviewPosition + 1 >= Text.Length) return '\0';
65  return Text[PreviewPosition + 1];
66  }
67  }
68 
69  public void ResetPreviewPosition() {
70  PreviewPosition = Location.Position;
71  }
72 
73  public bool MatchSymbol(string symbol, bool ignoreCase) {
74  try {
75  var compType = ignoreCase ? StringComparison.InvariantCultureIgnoreCase : StringComparison.InvariantCulture;
76  int cmp = string.Compare(Text, PreviewPosition, symbol, 0, symbol.Length, compType);
77  return cmp == 0;
78  } catch {
79  //exception may be thrown if Position + symbol.length > text.Length;
80  // this happens not often, only at the very end of the file, so we don't check this explicitly
81  //but simply catch the exception and return false. Again, try/catch block has no overhead
82  // if exception is not thrown.
83  return false;
84  }
85  }
86 
87  public Token CreateToken(Terminal terminal) {
88  var tokenText = GetPreviewText();
89  return new Token(terminal, this.Location, tokenText, tokenText);
90  }
91  public Token CreateToken(Terminal terminal, object value) {
92  var tokenText = GetPreviewText();
93  return new Token(terminal, this.Location, tokenText, value);
94  }
95  public Token CreateErrorToken(string message, params object[] args) {
96  if (args != null && args.Length > 0)
97  message = string.Format(message, args);
98  return new Token(_scannerData.Language.Grammar.SyntaxError, Location, GetPreviewText(), message);
99  }
100 
101 
102  [System.Diagnostics.DebuggerStepThrough]
103  public bool EOF() {
104  return PreviewPosition >= Text.Length;
105  }
106  #endregion
107 
108  //returns substring from Location.Position till (PreviewPosition - 1)
109  private string GetPreviewText() {
110  var until = PreviewPosition;
111 
112  if (until > Text.Length) until = Text.Length;
113  string text = Text.Substring(_location.Position, until - _location.Position);
114  return text;
115  }
116 
117  public override string ToString() {
118  string result;
119  try {
120  //show just 20 chars from current position
121  if (Location.Position + 20 < Text.Length)
122  result = Text.Substring(Location.Position, 20) + Resources.LabelSrcHaveMore;// " ..."
123  else
124  result = Text.Substring(Location.Position) + Resources.LabelEofMark; //"(EOF)"
125  } catch (Exception) {
126  result = PreviewChar + Resources.LabelSrcHaveMore;
127  }
128  return string.Format(Resources.MsgSrcPosToString , result, Location); //"[{0}], at {1}"
129  }
130 
131  #region Location calculations
132  private static char[] _tab_arr = { '\t' };
133  //Calculates Location (row/column/position) to PreviewPosition.
135  if (_location.Position == PreviewPosition) return;
136  if (PreviewPosition > Text.Length)
137  PreviewPosition = Text.Length;
138  // First, check if preview position is in the same line; if so, just adjust column and return
139  // Note that this case is not line start, so we do not need to check tab chars (and adjust column)
140  if (PreviewPosition <= _nextNewLinePosition || _nextNewLinePosition < 0) {
141  _location.Column += PreviewPosition - _location.Position;
142  _location.Position = PreviewPosition;
143  return;
144  }
145  //So new position is on new line (beyond _nextNewLinePosition)
146  //First count \n chars in the string fragment
147  int lineStart = _nextNewLinePosition;
148  int nlCount = 1; //we start after old _nextNewLinePosition, so we count one NewLine char
149  CountCharsInText(Text, _scannerData.LineTerminatorsArray, lineStart + 1, PreviewPosition - 1, ref nlCount, ref lineStart);
150  _location.Line += nlCount;
151  //at this moment lineStart is at start of line where newPosition is located
152  //Calc # of tab chars from lineStart to newPosition to adjust column#
153  int tabCount = 0;
154  int dummy = 0;
155  if (TabWidth > 1)
156  CountCharsInText(Text, _tab_arr, lineStart, PreviewPosition - 1, ref tabCount, ref dummy);
157 
158  //adjust TokenStart with calculated information
159  _location.Position = PreviewPosition;
160  _location.Column = PreviewPosition - lineStart - 1;
161  if (tabCount > 0)
162  _location.Column += (TabWidth - 1) * tabCount; // "-1" to count for tab char itself
163 
164  //finally cache new line and assign TokenStart
165  _nextNewLinePosition = Text.IndexOfAny(_scannerData.LineTerminatorsArray, PreviewPosition);
166  }
167 
168  private static void CountCharsInText(string text, char[] chars, int from, int until, ref int count, ref int lastCharOccurrencePosition) {
169 // if (from >= until) return;
170  if (from > until) return;
171  if (until >= text.Length) until = text.Length - 1;
172  while (true) {
173  int next = text.IndexOfAny(chars, from, until - from + 1);
174  if (next < 0) return;
175  //CR followed by LF is one line terminator, not two; we put it here, just to cover for special case; it wouldn't break
176  // the case when this function is called to count tabs
177  bool isCRLF = (text[next] == '\n' && next > 0 && text[next - 1] == '\r');
178  if (!isCRLF)
179  count++; //count
180  lastCharOccurrencePosition = next;
181  from = next + 1;
182  }
183 
184  }
185  #endregion
186 
187 
188 
189 
190  }//class
191 
192 }//namespace
static string LabelSrcHaveMore
Looks up a localized string similar to ....
static string LabelEofMark
Looks up a localized string similar to (EOF).
A strongly-typed resource class, for looking up localized strings, etc.
override string ToString()
Token CreateToken(Terminal terminal)
Creates a new token based on current preview position.
Definition: SourceStream.cs:87
void SetText(string text, int offset, bool keepLineNumbering)
Definition: SourceStream.cs:29
Token CreateErrorToken(string message, params object[] args)
Creates error token with custom error message as its Value.
Definition: SourceStream.cs:95
SourceStream(ScannerData scannerData, int tabWidth)
Definition: SourceStream.cs:24
Token CreateToken(Terminal terminal, object value)
Creates a new token based on current preview position and sets its Value field.
Definition: SourceStream.cs:91
Interface for Terminals to access the source stream and produce tokens.
_In_ size_t count
Definition: DirectXTexP.h:174
bool MatchSymbol(string symbol, bool ignoreCase)
Tries to match the symbol with the text at current preview position.
Definition: SourceStream.cs:73
Tokens are produced by scanner and fed to parser, optionally passing through Token filters in between...
Definition: Token.cs:74
static string MsgSrcPosToString
Looks up a localized string similar to "[{0}], at {1}.