~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to src/core/Mono.Debugging/Mono.Debugging.Evaluation/NRefactoryExpressionEvaluator.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// NRefactoryExpressionEvaluator.cs
 
3
//
 
4
// Authors: Lluis Sanchez Gual <lluis@novell.com>
 
5
//          Jeffrey Stedfast <jeff@xamarin.com>
 
6
//
 
7
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
 
8
// Copyright (c) 2012 Xamarin Inc. (http://www.xamarin.com)
 
9
//
 
10
// Permission is hereby granted, free of charge, to any person obtaining a copy
 
11
// of this software and associated documentation files (the "Software"), to deal
 
12
// in the Software without restriction, including without limitation the rights
 
13
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 
14
// copies of the Software, and to permit persons to whom the Software is
 
15
// furnished to do so, subject to the following conditions:
 
16
//
 
17
// The above copyright notice and this permission notice shall be included in
 
18
// all copies or substantial portions of the Software.
 
19
//
 
20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
21
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
22
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 
23
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
24
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
25
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 
26
// THE SOFTWARE.
 
27
 
 
28
using System;
 
29
using System.Linq;
 
30
using System.Collections.Generic;
 
31
 
 
32
using Mono.Debugging.Client;
 
33
 
 
34
using ICSharpCode.NRefactory.CSharp;
 
35
 
 
36
namespace Mono.Debugging.Evaluation
 
37
{
 
38
        public class NRefactoryExpressionEvaluator : ExpressionEvaluator
 
39
        {
 
40
                Dictionary<string,ValueReference> userVariables = new Dictionary<string, ValueReference> ();
 
41
 
 
42
                public override ValueReference Evaluate (EvaluationContext ctx, string expression, object expectedType)
 
43
                {
 
44
                        expression = expression.TrimStart ();
 
45
 
 
46
                        if (expression.Length > 0 && expression[0] == '?')
 
47
                                expression = expression.Substring (1).Trim ();
 
48
 
 
49
                        if (expression.Length > 3 && expression.StartsWith ("var", StringComparison.Ordinal) && char.IsWhiteSpace (expression[3])) {
 
50
                                expression = expression.Substring (4).Trim (' ', '\t');
 
51
                                string variable = null;
 
52
 
 
53
                                for (int n = 0; n < expression.Length; n++) {
 
54
                                        if (!char.IsLetterOrDigit (expression[n]) && expression[n] != '_') {
 
55
                                                variable = expression.Substring (0, n);
 
56
                                                if (!expression.Substring (n).Trim (' ', '\t').StartsWith ("=", StringComparison.Ordinal))
 
57
                                                        variable = null;
 
58
                                                break;
 
59
                                        }
 
60
 
 
61
                                        if (n == expression.Length - 1) {
 
62
                                                variable = expression;
 
63
                                                expression = null;
 
64
                                                break;
 
65
                                        }
 
66
                                }
 
67
 
 
68
                                if (!string.IsNullOrEmpty (variable))
 
69
                                        userVariables[variable] = new UserVariableReference (ctx, variable);
 
70
 
 
71
                                if (expression == null)
 
72
                                        return null;
 
73
                        }
 
74
 
 
75
                        expression = ReplaceExceptionTag (expression, ctx.Options.CurrentExceptionTag);
 
76
 
 
77
                        var expr = new CSharpParser ().ParseExpression (expression);
 
78
                        if (expr == null)
 
79
                                throw new EvaluatorException ("Could not parse expression '{0}'", expression);
 
80
 
 
81
                        var evaluator = new NRefactoryExpressionEvaluatorVisitor (ctx, expression, expectedType, userVariables);
 
82
                        return expr.AcceptVisitor<ValueReference> (evaluator);
 
83
                }
 
84
 
 
85
                public override string Resolve (DebuggerSession session, SourceLocation location, string exp)
 
86
                {
 
87
                        return Resolve (session, location, exp, false);
 
88
                }
 
89
 
 
90
                string Resolve (DebuggerSession session, SourceLocation location, string expression, bool tryTypeOf)
 
91
                {
 
92
                        expression = expression.TrimStart ();
 
93
 
 
94
                        if (expression.Length > 0 && expression[0] == '?')
 
95
                                return "?" + Resolve (session, location, expression.Substring (1).Trim ());
 
96
 
 
97
                        if (expression.Length > 3 && expression.StartsWith ("var", StringComparison.Ordinal) && char.IsWhiteSpace (expression[3]))
 
98
                                return "var " + Resolve (session, location, expression.Substring (4).Trim (' ', '\t'));
 
99
 
 
100
                        expression = ReplaceExceptionTag (expression, session.Options.EvaluationOptions.CurrentExceptionTag);
 
101
 
 
102
                        Expression expr = new CSharpParser ().ParseExpression (expression);
 
103
                        if (expr == null)
 
104
                                return expression;
 
105
 
 
106
                        var resolver = new NRefactoryExpressionResolverVisitor (session, location, expression);
 
107
                        expr.AcceptVisitor (resolver);
 
108
 
 
109
                        string resolved = resolver.GetResolvedExpression ();
 
110
                        if (resolved == expression && !tryTypeOf && (expr is BinaryOperatorExpression) && IsTypeName (expression)) {
 
111
                                // This is a hack to be able to parse expressions such as "List<string>". The NRefactory parser
 
112
                                // can parse a single type name, so a solution is to wrap it around a typeof(). We do it if
 
113
                                // the evaluation fails.
 
114
                                string res = Resolve (session, location, "typeof(" + expression + ")", true);
 
115
                                return res.Substring (7, res.Length - 8);
 
116
                        }
 
117
 
 
118
                        return resolved;
 
119
                }
 
120
 
 
121
                public override ValidationResult ValidateExpression (EvaluationContext ctx, string expression)
 
122
                {
 
123
                        expression = expression.TrimStart ();
 
124
 
 
125
                        if (expression.Length > 0 && expression[0] == '?')
 
126
                                expression = expression.Substring (1).Trim ();
 
127
 
 
128
                        if (expression.Length > 3 && expression.StartsWith ("var", StringComparison.Ordinal) && char.IsWhiteSpace (expression[3]))
 
129
                                expression = expression.Substring (4).Trim ();
 
130
 
 
131
                        expression = ReplaceExceptionTag (expression, ctx.Options.CurrentExceptionTag);
 
132
 
 
133
                        // Required as a workaround for a bug in the parser (it won't parse simple expressions like numbers)
 
134
                        if (!expression.EndsWith (";", StringComparison.Ordinal))
 
135
                                expression += ";";
 
136
 
 
137
                        var parser = new CSharpParser ();
 
138
                        parser.ParseExpression (expression);
 
139
 
 
140
                        if (parser.HasErrors)
 
141
                                return new ValidationResult (false, parser.Errors.First ().Message);
 
142
 
 
143
                        return new ValidationResult (true, null);
 
144
                }
 
145
 
 
146
                string ReplaceExceptionTag (string exp, string tag)
 
147
                {
 
148
                        // FIXME: Don't replace inside string literals
 
149
                        return exp.Replace (tag, "__EXCEPTION_OBJECT__");
 
150
                }
 
151
 
 
152
                bool IsTypeName (string name)
 
153
                {
 
154
                        int pos = 0;
 
155
                        bool res = ParseTypeName (name + "$", ref pos);
 
156
                        return res && pos >= name.Length;
 
157
                }
 
158
 
 
159
                bool ParseTypeName (string name, ref int pos)
 
160
                {
 
161
                        EatSpaces (name, ref pos);
 
162
                        if (!ParseName (name, ref pos))
 
163
                                return false;
 
164
 
 
165
                        EatSpaces (name, ref pos);
 
166
                        if (!ParseGenericArgs (name, ref pos))
 
167
                                return false;
 
168
 
 
169
                        EatSpaces (name, ref pos);
 
170
                        if (!ParseIndexer (name, ref pos))
 
171
                                return false;
 
172
 
 
173
                        EatSpaces (name, ref pos);
 
174
                        return true;
 
175
                }
 
176
 
 
177
                void EatSpaces (string name, ref int pos)
 
178
                {
 
179
                        while (char.IsWhiteSpace (name[pos]))
 
180
                                pos++;
 
181
                }
 
182
 
 
183
                bool ParseName (string name, ref int pos)
 
184
                {
 
185
                        if (name[0] == 'g' && pos < name.Length - 8 && name.Substring (pos, 8) == "global::")
 
186
                                pos += 8;
 
187
 
 
188
                        do {
 
189
                                int oldp = pos;
 
190
                                while (char.IsLetterOrDigit (name[pos]))
 
191
                                        pos++;
 
192
 
 
193
                                if (oldp == pos)
 
194
                                        return false;
 
195
 
 
196
                                if (name[pos] != '.')
 
197
                                        return true;
 
198
 
 
199
                                pos++;
 
200
                        }
 
201
                        while (true);
 
202
                }
 
203
 
 
204
                bool ParseGenericArgs (string name, ref int pos)
 
205
                {
 
206
                        if (name [pos] != '<')
 
207
                                return true;
 
208
 
 
209
                        pos++;
 
210
                        EatSpaces (name, ref pos);
 
211
 
 
212
                        while (true) {
 
213
                                if (!ParseTypeName (name, ref pos))
 
214
                                        return false;
 
215
 
 
216
                                EatSpaces (name, ref pos);
 
217
                                char c = name [pos++];
 
218
 
 
219
                                if (c == '>')
 
220
                                        return true;
 
221
 
 
222
                                if (c == ',')
 
223
                                        continue;
 
224
 
 
225
                                return false;
 
226
                        }
 
227
                }
 
228
 
 
229
                bool ParseIndexer (string name, ref int pos)
 
230
                {
 
231
                        if (name [pos] != '[')
 
232
                                return true;
 
233
 
 
234
                        do {
 
235
                                pos++;
 
236
                                EatSpaces (name, ref pos);
 
237
                        } while (name [pos] == ',');
 
238
 
 
239
                        return name [pos++] == ']';
 
240
                }
 
241
        }
 
242
}