File: Intellisense.cs

package info (click to toggle)
mono 6.12.0.199%2Bdfsg-6
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 1,296,836 kB
  • sloc: cs: 11,181,803; xml: 2,850,076; ansic: 699,709; cpp: 123,344; perl: 59,361; javascript: 30,841; asm: 21,853; makefile: 20,405; sh: 15,009; python: 4,839; pascal: 925; sql: 859; sed: 16; php: 1
file content (239 lines) | stat: -rw-r--r-- 8,875 bytes parent folder | download | duplicates (7)
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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
using System;
using System.Collections.Generic;
using System.Collections;
using System.Workflow.Activities.Rules;


namespace System.Workflow.Activities.Rules
{
    internal class IntellisenseParser
    {
        private List<Token> tokens = new List<Token>();
        private int tokenIndex;

        internal IntellisenseParser(string inputString)
        {
            Scanner scanner = new Scanner(inputString);
            // Tokenize the input, but insert a marker at the beginning.
            tokens.Add(new Token(TokenID.EndOfInput, 0, null));

            scanner.TokenizeForIntellisense(tokens);
        }

        private Token CurrentToken
        {
            get { return tokens[tokenIndex]; }
        }

        private Token PrevToken()
        {
            if (tokenIndex > 0)
                --tokenIndex;

            return CurrentToken;
        }

        internal ParserContext BackParse()
        {
            tokenIndex = tokens.Count - 1;
            if (tokenIndex < 0)
                return null;

            Token token = CurrentToken;
            bool valid = false;

            // Skip past the right-most EndOfIput.  For our backparsing, we've inserted an
            // EndOfInput at the start.
            if (token.TokenID == TokenID.EndOfInput)
                token = PrevToken();

            int endTokenIndex = tokenIndex;

            if (token.TokenID == TokenID.Identifier && ((string)token.Value).Length == 1 && PrevToken().TokenID != TokenID.Dot)
            {
                // Assume this is the start of a root identifier
                valid = true;
            }
            else if (token.TokenID == TokenID.Dot)
            {
                // Assume it's a member selection operator.
                valid = BackParsePostfix();
            }
            else if (token.TokenID == TokenID.LParen)
            {
                // Assume it's the start of a method call argument list.
                if (PrevToken().TokenID == TokenID.Identifier)
                {
                    if (PrevToken().TokenID == TokenID.Dot)
                    {
                        // The tail looked like ".identifier(", so now we continue as in
                        // the member selection operator reverse parse above.
                        valid = BackParsePostfix();
                    }
                    else
                    {
                        // The tail looked like "identifier(", with no preceeding ".", so
                        // we're actually done.
                        valid = true;
                    }

                    if (valid)
                    {
                        // Back up over the "new" if there is one.
                        if (CurrentToken.TokenID == TokenID.New)
                            PrevToken();
                    }
                }
            }

            if (!valid)
                return null;

            // We successfully backward-parsed a postfix expression.  Create a
            // ParserContext for the real parser, giving it the subrange of tokens
            // that comprise the postfix expression.
            List<Token> postfixTokens = tokens.GetRange(tokenIndex + 1, endTokenIndex - tokenIndex);
            postfixTokens.Add(new Token(TokenID.EndOfInput, 0, null));
            ParserContext parserContext = new ParserContext(postfixTokens);
            return parserContext;
        }

        private bool BackParsePostfix()
        {
            while (CurrentToken.TokenID == TokenID.Dot)
            {
                Token token = PrevToken();
                switch (token.TokenID)
                {
                    case TokenID.Identifier:
                    case TokenID.TypeName:
                        PrevToken(); // eat the token
                        break;

                    case TokenID.This:
                        PrevToken(); // eat the "this"
                        // This is the start of the expression.
                        return true;

                    case TokenID.RParen:
                        // This may be the argument list of a method call,
                        // or it may be a parenthesized expression.
                        if (!BackParseMatchingDelimiter(TokenID.LParen))
                            return false;

                        if (CurrentToken.TokenID == TokenID.Identifier)
                        {
                            // It was a method call.
                            PrevToken(); // eat the method identifier
                        }
                        else
                        {
                            // It was a parenthesized subexpression.  We are finished,
                            // we have found the start of the subexpression.
                            return true;
                        }
                        break;

                    case TokenID.RBracket:
                        // Loop backward over all [..][..]
                        do
                        {
                            if (!BackParseMatchingDelimiter(TokenID.LBracket))
                                return false;
                        } while (CurrentToken.TokenID == TokenID.RBracket);

                        // Preceeding the indexers might be an identifier, or a method call.
                        if (CurrentToken.TokenID == TokenID.Identifier)
                        {
                            // It was an identifier.  Eat it and continue.
                            PrevToken(); // eat the identifier.
                        }
                        else if (CurrentToken.TokenID == TokenID.RParen)
                        {
                            // This may be the argument list of a method call,
                            // or it may be a parenthesized expression.
                            if (!BackParseMatchingDelimiter(TokenID.LParen))
                                return false;

                            if (CurrentToken.TokenID == TokenID.Identifier)
                            {
                                // It was a method call.
                                PrevToken(); // eat the method identifier
                            }
                            else
                            {
                                // It was a parenthesized subexpression.  We are finished,
                                // we have found the start of the subexpression.
                                return true;
                            }
                        }
                        else
                        {
                            // It's not valid.
                            return false;
                        }

                        break;

                    case TokenID.Greater:
                        if (!BackParseMatchingDelimiter(TokenID.Less))
                            return false;

                        if (CurrentToken.TokenID == TokenID.Identifier)
                        {
                            // It was a generic type
                            PrevToken(); // Eat the type identifier
                        }
                        else
                        {
                            // This wasn't valid... it was a type argument list, but wasn't
                            // preceeded by an identifier.
                            return false;
                        }
                        break;

                    default:
                        // We saw a "." that wasn't preceeded by a useful token.
                        return false;
                }
            }

            // If an identifier or type name is preceeded by "new", keep that.
            if (CurrentToken.TokenID == TokenID.New)
                PrevToken();

            return true;
        }

        // Having parsed a closing delimiter, eat tokens until the matching open delimiter
        // is found.
        private bool BackParseMatchingDelimiter(TokenID openDelimiter)
        {
            TokenID closeDelimiter = CurrentToken.TokenID;
            int level = 1;

            Token token = PrevToken(); // Eat the close delimiter
            while (token.TokenID != TokenID.EndOfInput)
            {
                if (token.TokenID == closeDelimiter)
                {
                    ++level;
                }
                else if (token.TokenID == openDelimiter)
                {
                    --level;
                    if (level == 0)
                    {
                        PrevToken(); // eat the open delimiter
                        break;
                    }
                }

                token = PrevToken();
            }

            // Back parse was successful if we matched all delimiters.
            return level == 0;
        }
    }
}