14 using System.Collections.Generic;
16 using System.Diagnostics;
40 public string StartTag =
"#{";
41 public string EndTag =
"}";
53 internal readonly
string Start, End;
55 internal readonly byte Index;
63 internal static int LongerStartFirst(StringSubType x, StringSubType
y) {
65 if (x.Start.Length > y.Start.Length)
return -1;
70 class StringSubTypeList :
List<StringSubType> {
72 base.Add(
new StringSubType(start, end, flags, (byte) this.Count));
77 #region constructors and initialization
79 base.SetFlag(TermFlags.IsLiteral);
80 base.AstNodeType = typeof(Irony.Interpreter.Ast.LiteralValueNode);
84 _subtypes.Add(startEndSymbol, startEndSymbol, options);
90 : this(name, startEndSymbol, options) {
91 base.AstNodeType = astNodeType;
94 : this(name, startEndSymbol, options) {
95 base.AstNodeCreator = astNodeCreator;
99 AddStartEnd(startEndSymbol, startEndSymbol, stringOptions);
102 _subtypes.Add(startSymbol, endSymbol, stringOptions);
105 base.AddPrefixFlag(prefix, (short)flags);
110 #region Properties/Fields
111 private readonly StringSubTypeList _subtypes =
new StringSubTypeList();
112 string _startSymbolsFirsts;
115 #region overrides: Init, GetFirsts, ReadBody, etc...
117 base.Init(grammarData);
118 _startSymbolsFirsts = string.Empty;
119 if (_subtypes.Count == 0) {
125 _subtypes.Sort(StringSubType.LongerStartFirst);
126 bool isTemplate =
false;
127 foreach (StringSubType subType
in _subtypes) {
128 if (allStartSymbols.Contains(subType.Start))
131 allStartSymbols.Add(subType.Start);
132 _startSymbolsFirsts += subType.Start[0].ToString();
133 if ((subType.Flags &
StringOptions.IsTemplate) != 0) isTemplate =
true;
136 _startSymbolsFirsts = _startSymbolsFirsts.ToLower() + _startSymbolsFirsts.ToUpper();
138 foreach (StringSubType info
in _subtypes) {
148 if(templateSettings == null)
150 else if (templateSettings.ExpressionRoot == null)
156 if (this.EditorInfo == null)
162 result.AddRange(Prefixes);
164 foreach (
char ch
in _startSymbolsFirsts)
165 result.Add(ch.ToString());
171 if (!ReadStartSymbol(source, details))
return false;
173 return CompleteReadBody(source, details);
176 private bool CompleteReadBody(
ISourceStream source, CompoundTokenDetails details) {
177 bool escapeEnabled = !details.IsSet((short)
StringOptions.NoEscapes);
178 int start = source.PreviewPosition;
179 string endQuoteSymbol = details.EndSymbol;
180 string endQuoteDoubled = endQuoteSymbol + endQuoteSymbol;
181 bool lineBreakAllowed = details.IsSet((short)
StringOptions.AllowsLineBreak);
185 int nlPos = lineBreakAllowed ? -1 : source.Text.IndexOf(
'\n', source.PreviewPosition);
188 int endPos = source.Text.IndexOf(endQuoteSymbol, source.PreviewPosition);
190 if (endPos < 0 && details.PartialOk && lineBreakAllowed) {
191 ProcessPartialBody(source, details);
195 bool malformed = endPos < 0 || nlPos >= 0 && nlPos < endPos;
198 if (nlPos > 0) endPos = nlPos;
199 if (endPos > 0) source.PreviewPosition = endPos + 1;
208 if (escapeEnabled && IsEndQuoteEscaped(source.Text, endPos)) {
209 source.PreviewPosition = endPos + endQuoteSymbol.Length;
214 source.PreviewPosition = endPos;
215 if (details.IsSet((
short)
StringOptions.AllowsDoubledQuote) && source.MatchSymbol(endQuoteDoubled, !CaseSensitive)) {
216 source.PreviewPosition = endPos + endQuoteDoubled.Length;
222 details.Body = source.Text.Substring(start, endPos - start);
223 source.PreviewPosition = endPos + endQuoteSymbol.Length;
227 private void ProcessPartialBody(ISourceStream source, CompoundTokenDetails details) {
228 int from = source.PreviewPosition;
229 source.PreviewPosition = source.Text.Length;
230 details.Body = source.Text.Substring(from, source.PreviewPosition - from);
231 details.IsPartial =
true;
235 base.InitDetails(context, details);
236 if (context.VsLineScanState.Value != 0) {
238 details.Flags = context.VsLineScanState.TerminalFlags;
239 details.SubTypeIndex = context.VsLineScanState.TokenSubType;
240 var stringInfo = _subtypes[context.VsLineScanState.TokenSubType];
241 details.StartSymbol = stringInfo.Start;
242 details.EndSymbol = stringInfo.End;
247 base.ReadSuffix(source, details);
250 if (details.TypeCodes != null && details.TypeCodes[0] == TypeCode.Char)
256 details.TypeCodes =
new TypeCode[] { TypeCode.Char };
259 private bool IsEndQuoteEscaped(
string text,
int quotePosition) {
260 bool escaped =
false;
261 int p = quotePosition - 1;
262 while (p > 0 && text[p] == EscapeChar) {
269 private bool ReadStartSymbol(ISourceStream source, CompoundTokenDetails details) {
270 if (_startSymbolsFirsts.IndexOf(source.PreviewChar) < 0)
272 foreach (StringSubType subType
in _subtypes) {
273 if (!source.MatchSymbol(subType.Start, !CaseSensitive))
276 details.StartSymbol = subType.Start;
277 details.EndSymbol = subType.End;
278 details.Flags |= (short) subType.Flags;
279 details.SubTypeIndex = subType.Index;
280 source.PreviewPosition += subType.Start.Length;
289 string value = details.Body;
290 bool escapeEnabled = !details.IsSet((short)
StringOptions.NoEscapes);
292 if (escapeEnabled && value.IndexOf(EscapeChar) >= 0) {
294 string[] arr = value.Split(EscapeChar);
295 bool ignoreNext =
false;
297 for (
int i = 1; i < arr.Length; i++) {
303 if (
string.IsNullOrEmpty(s)) {
312 if (Escapes.TryGetValue(first, out newFirst))
313 arr[i] = newFirst + s.Substring(1);
315 arr[i] = HandleSpecialEscape(arr[i], details);
318 value = string.Join(string.Empty, arr);
322 string endSymbol = details.EndSymbol;
323 if (details.
IsSet((
short)
StringOptions.AllowsDoubledQuote) && value.IndexOf(endSymbol) >= 0)
324 value = value.Replace(endSymbol + endSymbol, endSymbol);
327 if (value.Length != 1) {
331 details.Value = value[0];
333 details.TypeCodes =
new TypeCode[] { TypeCode.String };
334 details.Value = value;
341 if (
string.IsNullOrEmpty(segment))
return string.Empty;
342 int len, p;
string digits;
char ch;
string result;
343 char first = segment[0];
348 len = (first ==
'u' ? 4 : 8);
349 if (segment.Length < len + 1) {
353 digits = segment.Substring(1, len);
354 ch = (char)
Convert.ToUInt32(digits, 16);
355 result = ch + segment.Substring(len + 1);
363 while (p < 5 && p < segment.Length) {
372 digits = segment.Substring(1, p - 1);
373 ch = (char)
Convert.ToUInt32(digits, 16);
374 result = ch + segment.Substring(p);
378 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
382 while (p < 3 && p < segment.Length) {
387 digits = segment.Substring(0, p);
388 ch = (char)
Convert.ToUInt32(digits, 8);
389 result = ch + segment.Substring(p);
override void Init(GrammarData grammarData)
static string ErrInvStrDef
Looks up a localized string similar to Error in string literal [{0}]: No start/end symbols specified...
StringLiteral(string name)
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ DXGI_FORMAT _In_ DWORD flags
A strongly-typed resource class, for looking up localized strings, etc.
override void ReadSuffix(ISourceStream source, CompoundTerminalBase.CompoundTokenDetails details)
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ float size_t y
StringLiteral(string name, string startEndSymbol, StringOptions options)
static string ErrTemplMissingExprRoot
Looks up a localized string similar to Expression root is not specified in template settings (AstNode...
Interface for Terminals to access the source stream and produce tokens.
static string ErrBadUnEscape
Looks up a localized string similar to Invalid unicode escape ({0}), expected {1} hex digits...
void AddPrefix(string prefix, StringOptions flags)
Flags
Enumeration of the new Assimp's flags.
static string ErrInvEscape
Looks up a localized string similar to Invalid escape sequence:0}..
delegate void AstNodeCreator(ParsingContext context, ParseTreeNode parseNode)
virtual string HandleSpecialEscape(string segment, CompoundTokenDetails details)
void AddStartEnd(string startSymbol, string endSymbol, StringOptions stringOptions)
StringLiteral(string name, string startEndSymbol, StringOptions options, AstNodeCreator astNodeCreator)
static string ErrTemplExprNotRoot
Looks up a localized string similar to Expression root non-terminal in template settings (AstNodeConf...
static string ErrBadStrLiteral
Looks up a localized string similar to Mal-formed string literal - cannot find termination symbol...
HRESULT Convert(_In_ const Image &srcImage, _In_ DXGI_FORMAT format, _In_ DWORD filter, _In_ float threshold, _Out_ ScratchImage &image)
StringLiteral(string name, string startEndSymbol)
override bool ReadBody(ISourceStream source, CompoundTokenDetails details)
static string ErrBadXEscape
Looks up a localized string similar to Invalid escape, at least one digit expected..
StringLiteral(string name, string startEndSymbol, StringOptions options, Type astNodeType)
override bool ConvertValue(CompoundTokenDetails details)
static string ErrTemplNoSettings
Looks up a localized string similar to Error in string literal [{0}]: IsTemplate flag is set...
override IList< string > GetFirsts()
static string ErrDupStartSymbolStr
Looks up a localized string similar to Duplicate start symbol {0} in string literal [{1}]...
override void InitDetails(ParsingContext context, CompoundTerminalBase.CompoundTokenDetails details)
NonTerminalSet SnippetRoots
NonTerminal ExpressionRoot
void AddStartEnd(string startEndSymbol, StringOptions stringOptions)
static string ErrBadChar
Looks up a localized string similar to Invalid length of char literal - should be a single character...