/
IParseExpressionItemContext.cs
197 lines (181 loc) · 13.2 KB
/
IParseExpressionItemContext.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
// Copyright (c) UniversalExpressionParser Project. All rights reserved.
// Licensed under the MIT License. See LICENSE in the solution root for license information.
using JetBrains.Annotations;
using TextParser;
using UniversalExpressionParser.ExpressionItems;
namespace UniversalExpressionParser
{
/// <summary>
/// Parser context data.
/// </summary>
public interface IParseExpressionItemContext
{
/// <summary>
/// Event that is raised when new error is added by parser.
/// </summary>
event ParseErrorAddedDelegate ParseErrorAddedEvent;
/// <summary>
/// An instance of <see cref="IExpressionLanguageProviderWrapper"/> currently used by parser.
/// </summary>
[NotNull]
IExpressionLanguageProviderWrapper ExpressionLanguageProviderWrapper { get; }
/// <summary>
/// Pare expression result.
/// </summary>
[NotNull]
IParseExpressionResult ParseExpressionResult { get; }
/// <summary>
/// Error data. Use <see cref="ParseExpressionItemContext.AddParseErrorItem"/> to add errors.
/// Default implementation of <see cref="IParseErrorItem"/> is <see cref="ParseErrorItem"/>.
/// </summary>
[NotNull]
IParseErrorData ParseErrorData { get; }
/// <summary>
/// Text symbols parser that can be used to parse the symbols at current position.
/// </summary>
[NotNull]
ITextSymbolsParser TextSymbolsParser { get; }
/// <summary>
/// Returns true, if parsing was completed before reaching end of text due to some condition met, and not due to critical error encountered.
/// </summary>
bool IsEarlyParseStopEncountered { get; }
/// <summary>
/// Tries to parse braces if the text at current position starts with either '(' or '['.
/// If parsing is successful, the position after parsing will be after ')' or ']'
/// </summary>
/// <param name="literalExpressionItem">If the parameter is not null, the braces expression item will have a
/// value <see cref="IBracesExpressionItem.NameLiteral"/> equal to <paramref name="literalExpressionItem"/>.
/// </param>
/// <exception cref="ParseTextException">Throws this exception if the text at current position <see cref="ITextSymbolsParserState.PositionInText"/> in
/// of property <see cref="TextSymbolsParser"/> is not '(' or '['
/// </exception>
[NotNull]
IBracesExpressionItem ParseBracesExpression([CanBeNull] ILiteralExpressionItem literalExpressionItem);
/// <summary>
/// Tries to parse an expression at current position to <see cref="ICodeBlockExpressionItem"/>, if text at current position starts with
/// <see cref="IExpressionLanguageProvider.CodeBlockStartMarker"/>.
/// If parsing is successful, the position after parsing will be after the code block end marker <see cref="IExpressionLanguageProvider.CodeBlockEndMarker"/>
/// </summary>
/// <exception cref="ParseTextException">Throws this exception if the text at current position at current position <see cref="ITextSymbolsParserState.PositionInText"/> in
/// of property <see cref="TextSymbolsParser"/> is not block start marker <see cref="IExpressionLanguageProvider.CodeBlockStartMarker"/>.
/// </exception>
[NotNull]
ICodeBlockExpressionItem ParseCodeBlockExpression();
/// <summary>
/// Skips comments and spaces. Comments will be added to <see cref="IParseExpressionResult.SortedCommentedTextData"/>.
/// </summary>
/// <returns>Returns true, if text end is not reached (i.e. the value of <see cref="ITextSymbolsParserState.PositionInText"/> of <see cref="TextSymbolsParser"/> is not past the
/// parsed text end). Returns false otherwise.</returns>
bool SkipSpacesAndComments();
/// <summary>
/// Tries to parse a symbol at current position. For example if parsed text is "var var1=8;", and the value
/// of <see cref="ITextSymbolsParserState.PositionInText"/> of <see cref="TextSymbolsParser"/> is 4 (index of "var1"), then
/// this method will return true, and the value of <paramref name="parsedLiteral"/> will be set to "var1".
/// </summary>
/// <param name="parsedLiteral">Parsed symbol. The value is null, if the returned value is false. Otherwise the value is not null.</param>
/// <returns>Returns true if valid literal was parsed. Returns false otherwise.</returns>
bool TryParseSymbol(out string parsedLiteral);
/// <summary>
/// Adds an error data.
/// </summary>
/// <param name="parseErrorItem">Code item error data.</param>
void AddParseErrorItem([NotNull] IParseErrorItem parseErrorItem);
}
/// <summary>
/// Extension methods for <see cref="IParseExpressionItemContext"/>
/// </summary>
public static class ParseExpressionItemContextExtensionMethods
{
/// <summary>
/// Returns true if parsed text in property <see cref="ITextSymbolsParserState.TextToParse"/> in <see cref="IParseExpressionItemContext.TextSymbolsParser"/>
/// starts with symbol <paramref name="symbolToMatch"/>.
/// For example if parsed text is "f(x) begin++x;end;" and <paramref name="symbolToMatch"/> is "begin" and property
/// <see cref="ITextSymbolsParserState.PositionInText"/> in <see cref="IParseExpressionItemContext.TextSymbolsParser"/>
/// is 5 (index of "begin"), then this method will return true. On the other hand if we change the parsed text is "f(x) beginy+x;end;", with all the other
/// values being the same, the returned value will be false.
/// </summary>
/// <param name="parseExpressionItemContext">Pare expression context data.</param>
/// <param name="symbolToMatch">Symbol to match.</param>
public static bool StartsWithSymbol([NotNull] this IParseExpressionItemContext parseExpressionItemContext, string symbolToMatch)
{
var textSymbolsParser = parseExpressionItemContext.TextSymbolsParser;
return Helpers.StartsWithSymbol(textSymbolsParser.TextToParse, symbolToMatch, textSymbolsParser.PositionInText, textSymbolsParser.ParsedTextEnd,
parseExpressionItemContext.ExpressionLanguageProviderWrapper.ExpressionLanguageProvider);
}
/// <summary>
/// Returns true if parsed text in property <see cref="ITextSymbolsParserState.TextToParse"/> in <see cref="IParseExpressionItemContext.TextSymbolsParser"/>
/// starts with symbol <paramref name="symbolToMatch"/>.
/// For example if parsed text is "f(x) begin++x;end;" and <paramref name="symbolToMatch"/> is "begin" and property
/// <see cref="ITextSymbolsParserState.PositionInText"/> in <see cref="IParseExpressionItemContext.TextSymbolsParser"/>
/// is 5 (index of "begin"), then this method will return true. On the other hand if we change the parsed text is "f(x) beginy+x;end;", with all the other
/// values being the same, the returned value will be false.
/// </summary>
/// <param name="parseExpressionItemContext">Pare expression context data.</param>
/// <param name="symbolToMatch">Symbol to match.</param>
/// <param name="matchedSymbol">
/// An output parameter for the matched symbol. If the returned value is true, the value is not null.
/// Otherwise the value is null.<br/>
/// If the value of <see cref="IExpressionLanguageProvider.IsLanguageCaseSensitive"/> is true, the value is the same as
/// <paramref name="symbolToMatch"/>, otherwise, the value is equal to <paramref name="matchedSymbol"/> when case is ignored.
/// </param>
public static bool StartsWithSymbol([NotNull] this IParseExpressionItemContext parseExpressionItemContext, string symbolToMatch,
out string matchedSymbol)
{
var textSymbolsParser = parseExpressionItemContext.TextSymbolsParser;
return Helpers.StartsWithSymbol(textSymbolsParser.TextToParse, symbolToMatch, textSymbolsParser.PositionInText, textSymbolsParser.ParsedTextEnd,
parseExpressionItemContext.ExpressionLanguageProviderWrapper.ExpressionLanguageProvider, null, out matchedSymbol);
}
/// <summary>
/// Returns true if parsed text in property <see cref="ITextSymbolsParserState.TextToParse"/> in <see cref="IParseExpressionItemContext.TextSymbolsParser"/>
/// starts with symbol <paramref name="symbolToMatch"/>.
/// For example if parsed text is "f(x) begin++x;end;" and <paramref name="symbolToMatch"/> is "begin" and property
/// <see cref="ITextSymbolsParserState.PositionInText"/> in <see cref="IParseExpressionItemContext.TextSymbolsParser"/>
/// is 5 (index of "begin"), then this method will return true. On the other hand if we change the parsed text is "f(x) beginy+x;end;", with all the other
/// values being the same, the returned value will be false.
/// </summary>
/// <param name="parseExpressionItemContext">Pare expression context data.</param>
/// <param name="symbolToMatch">Symbol to match.</param>
/// <param name="isValidTextAfterTextToMatch">A delegate that specifies if the text after the matched symbol is not part of the same symbol.
/// For example if parsed text is "var var1+", <paramref name="symbolToMatch"/> is "var1", and property
/// <see cref="ITextSymbolsParserState.PositionInText"/> in <see cref="IParseExpressionItemContext.TextSymbolsParser"/> is 4 (i.e., index of "var1"),
/// then if this delegate returns true for character '+', then the method <see cref="StartsWithSymbol(IParseExpressionItemContext, string, IsValidTextAfterMatchedTextDelegate)"/>
/// will return true, otherwise, the method call will return false.
/// </param>
public static bool StartsWithSymbol([NotNull] this IParseExpressionItemContext parseExpressionItemContext, string symbolToMatch,
IsValidTextAfterMatchedTextDelegate isValidTextAfterTextToMatch)
{
var textSymbolsParser = parseExpressionItemContext.TextSymbolsParser;
return Helpers.StartsWithSymbol(textSymbolsParser.TextToParse, symbolToMatch, textSymbolsParser.PositionInText, textSymbolsParser.ParsedTextEnd,
parseExpressionItemContext.ExpressionLanguageProviderWrapper.ExpressionLanguageProvider, isValidTextAfterTextToMatch);
}
/// <summary>
/// Returns true if parsed text in property <see cref="ITextSymbolsParserState.TextToParse"/> in <see cref="IParseExpressionItemContext.TextSymbolsParser"/>
/// starts with symbol <paramref name="symbolToMatch"/>.
/// For example if parsed text is "f(x) begin++x;end;" and <paramref name="symbolToMatch"/> is "begin" and property
/// <see cref="ITextSymbolsParserState.PositionInText"/> in <see cref="IParseExpressionItemContext.TextSymbolsParser"/>
/// is 5 (index of "begin"), then this method will return true. On the other hand if we change the parsed text is "f(x) beginy+x;end;", with all the other
/// values being the same, the returned value will be false.
/// </summary>
/// <param name="parseExpressionItemContext">Pare expression context data.</param>
/// <param name="symbolToMatch">Symbol to match.</param>
/// <param name="isValidTextAfterTextToMatch">A delegate that specifies if the text after the matched symbol is not part of the same symbol.
/// For example if parsed text is "var var1+", <paramref name="symbolToMatch"/> is "var1", and property
/// <see cref="ITextSymbolsParserState.PositionInText"/> in <see cref="IParseExpressionItemContext.TextSymbolsParser"/> is 4 (i.e., index of "var1"),
/// then if this delegate returns true for character '+', then the method <see cref="StartsWithSymbol(IParseExpressionItemContext, string, IsValidTextAfterMatchedTextDelegate)"/>
/// will return true, otherwise, the method call will return false.
/// </param>
/// <param name="matchedSymbol">
/// An output parameter for the matched symbol. If the returned value is true, the value is not null.
/// Otherwise the value is null.<br/>
/// If the value of <see cref="IExpressionLanguageProvider.IsLanguageCaseSensitive"/> is true, the value is the same as
/// <paramref name="symbolToMatch"/>, otherwise, the value is equal to <paramref name="matchedSymbol"/> when case is ignored.
/// </param>
public static bool StartsWithSymbol([NotNull] this IParseExpressionItemContext parseExpressionItemContext, string symbolToMatch,
IsValidTextAfterMatchedTextDelegate isValidTextAfterTextToMatch, out string matchedSymbol)
{
var textSymbolsParser = parseExpressionItemContext.TextSymbolsParser;
return Helpers.StartsWithSymbol(textSymbolsParser.TextToParse, symbolToMatch, textSymbolsParser.PositionInText, textSymbolsParser.ParsedTextEnd,
parseExpressionItemContext.ExpressionLanguageProviderWrapper.ExpressionLanguageProvider, isValidTextAfterTextToMatch, out matchedSymbol);
}
}
}