// // NRefactoryExpressionEvaluator.cs // // Authors: Lluis Sanchez Gual // Jeffrey Stedfast // // Copyright (c) 2008 Novell, Inc (http://www.novell.com) // Copyright (c) 2012 Xamarin Inc. (http://www.xamarin.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; using System.Linq; using System.Collections.Generic; using Mono.Debugging.Client; namespace Mono.Debugging.Evaluation { /*public class NRefactoryExpressionEvaluator : ExpressionEvaluator { readonly Dictionary userVariables = new Dictionary (); public override ValueReference Evaluate (EvaluationContext ctx, string expression, object expectedType) { expression = expression.Trim (); if (expression.Length > 0 && expression[0] == '?') expression = expression.Substring (1).TrimStart (); if (expression.Length > 3 && expression.StartsWith ("var", StringComparison.Ordinal) && char.IsWhiteSpace (expression[3])) { expression = expression.Substring (4).TrimStart (); string variable = null; for (int n = 0; n < expression.Length; n++) { if (!char.IsLetterOrDigit (expression[n]) && expression[n] != '_') { variable = expression.Substring (0, n); if (!expression.Substring (n).TrimStart ().StartsWith ("=", StringComparison.Ordinal)) variable = null; break; } if (n == expression.Length - 1) { variable = expression; expression = null; break; } } if (!string.IsNullOrEmpty (variable)) userVariables[variable] = new UserVariableReference (ctx, variable); if (expression == null) return null; } expression = ReplaceExceptionTag (expression, ctx.Options.CurrentExceptionTag); var expr = SyntaxFactory.ParseExpression (expression); if (expr == null) throw new EvaluatorException ("Could not parse expression '{0}'", expression); var evaluator = new NRefactoryExpressionEvaluatorVisitor (ctx, expression, expectedType, userVariables); return evaluator.Visit (expr); } public override string Resolve (DebuggerSession session, SourceLocation location, string exp) { return Resolve (session, location, exp, false); } string Resolve (DebuggerSession session, SourceLocation location, string expression, bool tryTypeOf) { expression = expression.Trim (); if (expression.Length > 0 && expression[0] == '?') return "?" + Resolve (session, location, expression.Substring (1).Trim ()); if (expression.Length > 3 && expression.StartsWith ("var", StringComparison.Ordinal) && char.IsWhiteSpace (expression[3])) return "var " + Resolve (session, location, expression.Substring (4).Trim (' ', '\t')); expression = ReplaceExceptionTag (expression, session.Options.EvaluationOptions.CurrentExceptionTag); var expr = SyntaxFactory.ParseExpression (expression); if (expr == null) return expression; var resolver = new NRefactoryExpressionResolverVisitor (session, location, expression); resolver.Visit (expr); string resolved = resolver.GetResolvedExpression (); if (resolved == expression && !tryTypeOf && (expr is BinaryExpressionSyntax) && IsTypeName (expression)) { // This is a hack to be able to parse expressions such as "List". The NRefactory parser // can parse a single type name, so a solution is to wrap it around a typeof(). We do it if // the evaluation fails. string res = Resolve (session, location, "typeof(" + expression + ")", true); return res.Substring (7, res.Length - 8); } return resolved; } public override ValidationResult ValidateExpression (EvaluationContext ctx, string expression) { expression = expression.Trim (); if (expression.Length > 0 && expression[0] == '?') expression = expression.Substring (1).TrimStart (); if (expression.Length > 3 && expression.StartsWith ("var", StringComparison.Ordinal) && char.IsWhiteSpace (expression[3])) expression = expression.Substring (4).TrimStart (); expression = ReplaceExceptionTag (expression, ctx.Options.CurrentExceptionTag); ParseOptions options = new CSharpParseOptions (); var expr = SyntaxFactory.ParseExpression (expression, options: options); if (expr.ContainsDiagnostics) return new ValidationResult (false, expr.GetDiagnostics().First ().GetMessage()); return new ValidationResult (true, null); } string ReplaceExceptionTag (string exp, string tag) { // FIXME: Don't replace inside string literals return exp.Replace (tag, "__EXCEPTION_OBJECT__"); } bool IsTypeName (string name) { int pos = 0; bool res = ParseTypeName (name + "$", ref pos); return res && pos >= name.Length; } bool ParseTypeName (string name, ref int pos) { EatSpaces (name, ref pos); if (!ParseName (name, ref pos)) return false; EatSpaces (name, ref pos); if (!ParseGenericArgs (name, ref pos)) return false; EatSpaces (name, ref pos); if (!ParseIndexer (name, ref pos)) return false; EatSpaces (name, ref pos); return true; } void EatSpaces (string name, ref int pos) { while (char.IsWhiteSpace (name[pos])) pos++; } bool ParseName (string name, ref int pos) { if (name[0] == 'g' && pos < name.Length - 8 && name.Substring (pos, 8) == "global::") pos += 8; do { int oldp = pos; while (char.IsLetterOrDigit (name[pos])) pos++; if (oldp == pos) return false; if (name[pos] != '.') return true; pos++; } while (true); } bool ParseGenericArgs (string name, ref int pos) { if (name [pos] != '<') return true; pos++; EatSpaces (name, ref pos); while (true) { if (!ParseTypeName (name, ref pos)) return false; EatSpaces (name, ref pos); char c = name [pos++]; if (c == '>') return true; if (c == ',') continue; return false; } } bool ParseIndexer (string name, ref int pos) { if (name [pos] != '[') return true; do { pos++; EatSpaces (name, ref pos); } while (name [pos] == ','); return name [pos++] == ']'; } }*/ }