/Raven.Client.Lightweight/Indexes/ExpressionStringBuilder.cs
C# | 2285 lines | 1830 code | 204 blank | 251 comment | 363 complexity | 0d6ccb7154d59fef53d2aa93b3464f69 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, Apache-2.0, BSD-3-Clause
Large files files are truncated, but you can click here to view the full file
- // //-----------------------------------------------------------------------
- // // <copyright company="Hibernating Rhinos LTD">
- // // Copyright (c) Hibernating Rhinos LTD. All rights reserved.
- // // </copyright>
- // //-----------------------------------------------------------------------
- using System;
- using System.Collections.Generic;
- using System.Dynamic;
- using System.Globalization;
- using System.Linq;
- using System.Linq.Expressions;
- using System.Reflection;
- using System.Runtime.CompilerServices;
- using System.Text;
- using Raven.Abstractions.Data;
- using Raven.Client.Document;
- using Raven.Imports.Newtonsoft.Json;
- using Raven.Client.Linq;
- using Raven.Imports.Newtonsoft.Json.Utilities;
- using Raven.Json.Linq;
- using Raven.Abstractions.Extensions;
-
- namespace Raven.Client.Indexes
- {
- /// <summary>
- /// Based off of System.Linq.Expressions.ExpressionStringBuilder
- /// </summary>
- public class ExpressionStringBuilder : ExpressionVisitor
- {
- // Fields
- private static readonly char[] LiteralSymbolsToEscape = new[] { '\'', '\"', '\\', '\a', '\b', '\f', '\n', '\r', '\t', '\v' };
- private static readonly string[] LiteralEscapedSymbols = new[] { @"\'", @"\""", @"\\", @"\a", @"\b", @"\f", @"\n", @"\r", @"\t", @"\v" };
-
- private readonly StringBuilder _out = new StringBuilder();
- private readonly DocumentConvention convention;
- private readonly Type queryRoot;
- private readonly string queryRootName;
- private readonly bool translateIdentityProperty;
- private ExpressionOperatorPrecedence _currentPrecedence;
- private Dictionary<object, int> _ids;
- private Dictionary<string, object> _duplicatedParams = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
- private bool castLambdas;
-
-
- // Methods
- private ExpressionStringBuilder(DocumentConvention convention, bool translateIdentityProperty, Type queryRoot,
- string queryRootName)
- {
- this.convention = convention;
- this.translateIdentityProperty = translateIdentityProperty;
- this.queryRoot = queryRoot;
- this.queryRootName = queryRootName;
- }
-
- private int GetLabelId(LabelTarget label)
- {
- if (_ids == null)
- {
- _ids = new Dictionary<object, int> { { label, 0 } };
- }
- else if (!_ids.ContainsKey(label))
- {
- _ids.Add(label, _ids.Count);
- }
- return _ids.Count;
- }
-
- private void AddParam(ParameterExpression p)
- {
- if (_ids == null)
- {
- _ids = new Dictionary<object, int>();
- _ids.Add(_ids, 0);
- }
- else if (!_ids.ContainsKey(p))
- {
- _ids.Add(p, _ids.Count);
- }
- }
-
- internal string CatchBlockToString(CatchBlock node)
- {
- var builder = new ExpressionStringBuilder(convention, translateIdentityProperty, queryRoot, queryRootName);
- builder.VisitCatchBlock(node);
- return builder.ToString();
- }
-
- private void DumpLabel(LabelTarget target)
- {
- if (!string.IsNullOrEmpty(target.Name))
- {
- Out(target.Name);
- }
- else
- {
- Out("UnnamedLabel_" + GetLabelId(target));
- }
- }
-
- internal string ElementInitBindingToString(ElementInit node)
- {
- var builder = new ExpressionStringBuilder(convention, translateIdentityProperty, queryRoot, queryRootName);
- builder.VisitElementInit(node);
- return builder.ToString();
- }
-
- /// <summary>
- /// Convert the expression to a string
- /// </summary>
- public static string ExpressionToString(DocumentConvention convention, bool translateIdentityProperty, Type queryRoot,
- string queryRootName, Expression node)
- {
- var builder = new ExpressionStringBuilder(convention, translateIdentityProperty, queryRoot, queryRootName);
- builder.Visit(node, ExpressionOperatorPrecedence.ParenthesisNotNeeded);
- return builder.ToString();
- }
-
- private static string FormatBinder(CallSiteBinder binder)
- {
- var binder2 = binder as ConvertBinder;
- if (binder2 != null)
- {
- return ("Convert " + binder2.Type);
- }
- var binder3 = binder as GetMemberBinder;
- if (binder3 != null)
- {
- return ("GetMember " + binder3.Name);
- }
- var binder4 = binder as SetMemberBinder;
- if (binder4 != null)
- {
- return ("SetMember " + binder4.Name);
- }
- var binder5 = binder as DeleteMemberBinder;
- if (binder5 != null)
- {
- return ("DeleteMember " + binder5.Name);
- }
- if (binder is GetIndexBinder)
- {
- return "GetIndex";
- }
- if (binder is SetIndexBinder)
- {
- return "SetIndex";
- }
- if (binder is DeleteIndexBinder)
- {
- return "DeleteIndex";
- }
- var binder6 = binder as InvokeMemberBinder;
- if (binder6 != null)
- {
- return ("Call " + binder6.Name);
- }
- if (binder is InvokeBinder)
- {
- return "Invoke";
- }
- if (binder is CreateInstanceBinder)
- {
- return "Create";
- }
- var binder7 = binder as UnaryOperationBinder;
- if (binder7 != null)
- {
- return binder7.Operation.ToString();
- }
- var binder8 = binder as BinaryOperationBinder;
- if (binder8 != null)
- {
- return binder8.Operation.ToString();
- }
- return "CallSiteBinder";
- }
-
-
- private int GetParamId(ParameterExpression p)
- {
- int count;
- if (_ids == null)
- {
- _ids = new Dictionary<object, int>();
- AddParam(p);
- return 0;
- }
- if (!_ids.TryGetValue(p, out count))
- {
- count = _ids.Count;
- AddParam(p);
- }
- return count;
- }
-
- internal string MemberBindingToString(MemberBinding node)
- {
- var builder = new ExpressionStringBuilder(convention, translateIdentityProperty, queryRoot, queryRootName);
- builder.VisitMemberBinding(node);
- return builder.ToString();
- }
-
- private void Out(char c)
- {
- _out.Append(c);
- }
-
- private void Out(string s)
- {
- _out.Append(s);
- }
-
- private void OutMember(Expression instance, MemberInfo member, Type exprType)
- {
- bool isJsonProperty;
- var name = GetPropertyName(member.Name, exprType,out isJsonProperty);
- if (TranslateToDocumentId(instance, member, exprType))
- {
- name = Constants.DocumentIdFieldName;
- }
- if (instance != null)
- {
- if (ShouldParantesisMemberExpression(instance))
- Out("(");
- Visit(instance);
- if (ShouldParantesisMemberExpression(instance))
- Out(")");
- Out(isJsonProperty && !name.IsValidIdentifier() ?"[\"" + name +"\"]": "." + name);
- }
- else
- {
- var parentType = member.DeclaringType;
- while (parentType.IsNested)
- {
- parentType = parentType.DeclaringType;
- if (parentType == null)
- break;
- Out(parentType.Name + ".");
- }
-
- Out(member.DeclaringType.Name + "." + name);
- }
- }
-
- private static bool ShouldParantesisMemberExpression(Expression instance)
- {
- switch (instance.NodeType)
- {
- case ExpressionType.Parameter:
- case ExpressionType.MemberAccess:
- return false;
- default:
- return true;
- }
- }
-
- private bool TranslateToDocumentId(Expression instance, MemberInfo member, Type exprType)
- {
- if (translateIdentityProperty == false)
- return false;
-
- if (convention.GetIdentityProperty(member.DeclaringType) != member)
- return false;
-
- // only translate from the root type or derivatives
- if (queryRoot != null && (exprType.IsAssignableFrom(queryRoot) == false))
- return false;
-
- if (queryRootName == null)
- return true; // just in case, shouldn't really happen
-
- // only translate from the root alias
- string memberName = null;
- while (true)
- {
- switch (instance.NodeType)
- {
- case ExpressionType.MemberAccess:
- var memberExpression = ((MemberExpression)instance);
- if (memberName == null)
- {
- memberName = memberExpression.Member.Name;
- }
- instance = memberExpression.Expression;
- break;
- case ExpressionType.Parameter:
- var parameterExpression = ((ParameterExpression)instance);
- if (memberName == null)
- {
- memberName = parameterExpression.Name;
- }
- return memberName == queryRootName;
- default:
- return false;
- }
- }
-
- }
-
- private string GetPropertyName(string name, Type exprType,out bool isJsonProperty)
- {
- isJsonProperty = false;
- var memberInfo = (MemberInfo)exprType.GetProperty(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly) ??
- exprType.GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
-
- if (memberInfo == null)
- {
- memberInfo = ReflectionUtil.GetPropertiesAndFieldsFor(exprType, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
- .FirstOrDefault(x => x.Name == name);
- }
-
- if (memberInfo != null)
- {
- foreach (var customAttribute in memberInfo.GetCustomAttributes(true))
- {
- string propName;
- var customAttributeType = customAttribute.GetType();
- if (typeof(JsonPropertyAttribute).Namespace != customAttributeType.Namespace)
- continue;
- switch (customAttributeType.Name)
- {
- case "JsonPropertyAttribute":
- propName = ((dynamic)customAttribute).PropertyName;
- isJsonProperty = true;
- break;
- case "DataMemberAttribute":
- propName = ((dynamic)customAttribute).Name;
- break;
- default:
- continue;
- }
- if (keywordsInCSharp.Contains(propName))
- return '@' + propName;
- return propName ?? name;
- }
- }
- return name;
- }
-
-
- private static Type GetMemberType(MemberInfo member)
- {
- var prop = member as PropertyInfo;
- if (prop != null)
- return prop.PropertyType;
- return ((FieldInfo)member).FieldType;
- }
-
- internal string SwitchCaseToString(SwitchCase node)
- {
- var builder = new ExpressionStringBuilder(convention, translateIdentityProperty, queryRoot, queryRootName);
- builder.VisitSwitchCase(node);
- return builder.ToString();
- }
-
- /// <summary>
- /// Returns a <see cref = "System.String" /> that represents this instance.
- /// </summary>
- /// <returns>
- /// A <see cref = "System.String" /> that represents this instance.
- /// </returns>
- public override string ToString()
- {
- return _out.ToString();
- }
-
- private void SometimesParenthesis(ExpressionOperatorPrecedence outer, ExpressionOperatorPrecedence inner,
- Action visitor)
- {
- var needParenthesis = outer.NeedsParenthesisFor(inner);
-
- if (needParenthesis)
- Out("(");
-
- visitor();
-
- if (needParenthesis)
- Out(")");
- }
-
- private void Visit(Expression node, ExpressionOperatorPrecedence outerPrecedence)
- {
- var previous = _currentPrecedence;
- _currentPrecedence = outerPrecedence;
- Visit(node);
- _currentPrecedence = previous;
- }
-
- /// <summary>
- /// Visits the children of the <see cref = "T:System.Linq.Expressions.BinaryExpression" />.
- /// </summary>
- /// <param name = "node">The expression to visit.</param>
- /// <returns>
- /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
- /// </returns>
- protected override Expression VisitBinary(BinaryExpression node)
- {
- return VisitBinary(node, _currentPrecedence);
- }
-
- private Expression VisitBinary(BinaryExpression node, ExpressionOperatorPrecedence outerPrecedence)
- {
- ExpressionOperatorPrecedence innerPrecedence;
-
- string str;
- var leftOp = node.Left;
- var rightOp = node.Right;
-
- FixupEnumBinaryExpression(ref leftOp, ref rightOp);
- switch (node.NodeType)
- {
- case ExpressionType.Add:
- str = "+";
- innerPrecedence = ExpressionOperatorPrecedence.Additive;
- break;
-
- case ExpressionType.AddChecked:
- str = "+";
- innerPrecedence = ExpressionOperatorPrecedence.Additive;
- break;
-
- case ExpressionType.And:
- if ((node.Type != typeof(bool)) && (node.Type != typeof(bool?)))
- {
- str = "&";
- innerPrecedence = ExpressionOperatorPrecedence.LogicalAND;
- }
- else
- {
- str = "And";
- innerPrecedence = ExpressionOperatorPrecedence.ConditionalAND;
- }
- break;
-
- case ExpressionType.AndAlso:
- str = "&&";
- innerPrecedence = ExpressionOperatorPrecedence.ConditionalAND;
- break;
-
- case ExpressionType.Coalesce:
- str = "??";
- innerPrecedence = ExpressionOperatorPrecedence.NullCoalescing;
- break;
-
- case ExpressionType.Divide:
- str = "/";
- innerPrecedence = ExpressionOperatorPrecedence.Multiplicative;
- break;
-
- case ExpressionType.Equal:
- str = "==";
- innerPrecedence = ExpressionOperatorPrecedence.Equality;
- break;
-
- case ExpressionType.ExclusiveOr:
- str = "^";
- innerPrecedence = ExpressionOperatorPrecedence.LogicalXOR;
- break;
-
- case ExpressionType.GreaterThan:
- str = ">";
- innerPrecedence = ExpressionOperatorPrecedence.RelationalAndTypeTesting;
- break;
-
- case ExpressionType.GreaterThanOrEqual:
- str = ">=";
- innerPrecedence = ExpressionOperatorPrecedence.RelationalAndTypeTesting;
- break;
-
- case ExpressionType.LeftShift:
- str = "<<";
- innerPrecedence = ExpressionOperatorPrecedence.Shift;
- break;
-
- case ExpressionType.LessThan:
- str = "<";
- innerPrecedence = ExpressionOperatorPrecedence.RelationalAndTypeTesting;
- break;
-
- case ExpressionType.LessThanOrEqual:
- str = "<=";
- innerPrecedence = ExpressionOperatorPrecedence.RelationalAndTypeTesting;
- break;
-
- case ExpressionType.Modulo:
- str = "%";
- innerPrecedence = ExpressionOperatorPrecedence.Multiplicative;
- break;
-
- case ExpressionType.Multiply:
- str = "*";
- innerPrecedence = ExpressionOperatorPrecedence.Multiplicative;
- break;
-
- case ExpressionType.MultiplyChecked:
- str = "*";
- innerPrecedence = ExpressionOperatorPrecedence.Multiplicative;
- break;
-
- case ExpressionType.NotEqual:
- str = "!=";
- innerPrecedence = ExpressionOperatorPrecedence.RelationalAndTypeTesting;
- break;
-
- case ExpressionType.Or:
- if ((node.Type != typeof(bool)) && (node.Type != typeof(bool?)))
- {
- str = "|";
- innerPrecedence = ExpressionOperatorPrecedence.LogicalOR;
- }
- else
- {
- str = "Or";
- innerPrecedence = ExpressionOperatorPrecedence.LogicalOR;
- }
- break;
-
- case ExpressionType.OrElse:
- str = "||";
- innerPrecedence = ExpressionOperatorPrecedence.ConditionalOR;
- break;
-
- case ExpressionType.Power:
- str = "^";
- innerPrecedence = ExpressionOperatorPrecedence.LogicalXOR;
- break;
-
- case ExpressionType.RightShift:
- str = ">>";
- innerPrecedence = ExpressionOperatorPrecedence.Shift;
- break;
-
- case ExpressionType.Subtract:
- str = "-";
- innerPrecedence = ExpressionOperatorPrecedence.Additive;
- break;
-
- case ExpressionType.SubtractChecked:
- str = "-";
- innerPrecedence = ExpressionOperatorPrecedence.Additive;
- break;
-
- case ExpressionType.Assign:
- str = "=";
- innerPrecedence = ExpressionOperatorPrecedence.Assignment;
- break;
-
- case ExpressionType.AddAssign:
- str = "+=";
- innerPrecedence = ExpressionOperatorPrecedence.Assignment;
- break;
-
- case ExpressionType.AndAssign:
- if ((node.Type != typeof(bool)) && (node.Type != typeof(bool?)))
- {
- str = "&=";
- innerPrecedence = ExpressionOperatorPrecedence.Assignment;
- }
- else
- {
- str = "&&=";
- innerPrecedence = ExpressionOperatorPrecedence.Assignment;
- }
- break;
-
- case ExpressionType.DivideAssign:
- str = "/=";
- innerPrecedence = ExpressionOperatorPrecedence.Assignment;
- break;
-
- case ExpressionType.ExclusiveOrAssign:
- str = "^=";
- innerPrecedence = ExpressionOperatorPrecedence.Assignment;
- break;
-
- case ExpressionType.LeftShiftAssign:
- str = "<<=";
- innerPrecedence = ExpressionOperatorPrecedence.Assignment;
- break;
-
- case ExpressionType.ModuloAssign:
- str = "%=";
- innerPrecedence = ExpressionOperatorPrecedence.Assignment;
- break;
-
- case ExpressionType.MultiplyAssign:
- str = "*=";
- innerPrecedence = ExpressionOperatorPrecedence.Assignment;
- break;
-
- case ExpressionType.OrAssign:
- if ((node.Type != typeof(bool)) && (node.Type != typeof(bool?)))
- {
- str = "|=";
- innerPrecedence = ExpressionOperatorPrecedence.Assignment;
- }
- else
- {
- str = "||=";
- innerPrecedence = ExpressionOperatorPrecedence.Assignment;
- }
- break;
-
- case ExpressionType.PowerAssign:
- str = "**=";
- innerPrecedence = ExpressionOperatorPrecedence.Assignment;
- break;
-
- case ExpressionType.RightShiftAssign:
- str = ">>=";
- innerPrecedence = ExpressionOperatorPrecedence.Assignment;
- break;
-
- case ExpressionType.SubtractAssign:
- str = "-=";
- innerPrecedence = ExpressionOperatorPrecedence.Assignment;
- break;
-
- case ExpressionType.AddAssignChecked:
- str = "+=";
- innerPrecedence = ExpressionOperatorPrecedence.Assignment;
- break;
-
- case ExpressionType.MultiplyAssignChecked:
- str = "*=";
- innerPrecedence = ExpressionOperatorPrecedence.Assignment;
- break;
-
- case ExpressionType.SubtractAssignChecked:
- str = "-=";
- innerPrecedence = ExpressionOperatorPrecedence.Assignment;
- break;
-
- case ExpressionType.ArrayIndex:
-
- innerPrecedence = ExpressionOperatorPrecedence.Primary;
-
- SometimesParenthesis(outerPrecedence, innerPrecedence, delegate
- {
- Visit(leftOp, innerPrecedence);
- Out("[");
- Visit(rightOp, innerPrecedence);
- Out("]");
- });
- return node;
-
- default:
- throw new InvalidOperationException();
- }
-
-
- SometimesParenthesis(outerPrecedence, innerPrecedence, delegate
- {
- var needsCasting = (innerPrecedence == ExpressionOperatorPrecedence.NullCoalescing) && TypeExistsOnServer(rightOp.Type);
- if (needsCasting)
- {
- Out("((");
- Out(ConvertTypeToCSharpKeyword(rightOp.Type));
- Out(")(");
- }
- if (rightOp.NodeType == ExpressionType.Constant)
- {
- // on the server side, double is treated as decimal, so we have
- // to force this coercion so the constants would work
- if (rightOp.Type == typeof(double))
- {
- Out("(double?)");
- }
- else if (rightOp.Type == typeof(float))
- {
- Out("(float?)");
- }
- }
- Visit(leftOp, innerPrecedence);
- Out(' ');
- Out(str);
- Out(' ');
- Visit(rightOp, innerPrecedence);
- if (rightOp.NodeType == ExpressionType.Constant)
- {
- // on the server side, double is treated as decimal, so we have
- // to force this coercion so the constants would work
- if (rightOp.Type == typeof(double))
- {
- Out("D");
- }
- else if (rightOp.Type == typeof(float))
- {
- Out("F");
- }
- }
- if (needsCasting)
- {
- Out("))");
- }
- });
-
- return node;
- }
-
- private void FixupEnumBinaryExpression(ref Expression left, ref Expression right)
- {
- switch (left.NodeType)
- {
- case ExpressionType.ConvertChecked:
- case ExpressionType.Convert:
- var expression = ((UnaryExpression)left).Operand;
- var enumType = Nullable.GetUnderlyingType(expression.Type) ?? expression.Type;
- if (enumType.IsEnum() == false)
- return;
-
- var constantExpression = SkipConvertExpressions(right) as ConstantExpression;
- if (constantExpression == null)
- return;
- left = expression;
- if (constantExpression.Value == null)
- {
- right = Expression.Constant(null);
- }
- else
- {
- right = convention.SaveEnumsAsIntegers
- ? Expression.Constant(Convert.ToInt32(constantExpression.Value))
- : Expression.Constant(Enum.ToObject(enumType, constantExpression.Value).ToString());
-
- }
- break;
- }
-
- while (true)
- {
- switch (left.NodeType)
- {
- case ExpressionType.ConvertChecked:
- case ExpressionType.Convert:
- left = ((UnaryExpression)left).Operand;
- break;
- default:
- return;
- }
- }
- }
-
- private Expression SkipConvertExpressions(Expression expression)
- {
- switch (expression.NodeType)
- {
- case ExpressionType.ConvertChecked:
- case ExpressionType.Convert:
- return SkipConvertExpressions(((UnaryExpression)expression).Operand);
- default:
- return expression;
- }
- }
-
- /// <summary>
- /// Visits the children of the <see cref = "T:System.Linq.Expressions.BlockExpression" />.
- /// </summary>
- /// <param name = "node">The expression to visit.</param>
- /// <returns>
- /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
- /// </returns>
- protected override Expression VisitBlock(BlockExpression node)
- {
- Out("{");
- foreach (var expression in node.Variables)
- {
- Out("var ");
- Visit(expression);
- Out(";");
- }
- Out(" ... }");
- return node;
- }
-
- /// <summary>
- /// Visits the children of the <see cref = "T:System.Linq.Expressions.CatchBlock" />.
- /// </summary>
- /// <param name = "node">The expression to visit.</param>
- /// <returns>
- /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
- /// </returns>
- protected override CatchBlock VisitCatchBlock(CatchBlock node)
- {
- Out("catch (" + node.Test.Name);
- if (node.Variable != null)
- {
- Out(node.Variable.Name);
- }
- Out(") { ... }");
- return node;
- }
-
- /// <summary>
- /// Visits the children of the <see cref = "T:System.Linq.Expressions.ConditionalExpression" />.
- /// </summary>
- /// <param name = "node">The expression to visit.</param>
- /// <returns>
- /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
- /// </returns>
- protected override Expression VisitConditional(ConditionalExpression node)
- {
- return VisitConditional(node, _currentPrecedence);
- }
-
- private Expression VisitConditional(ConditionalExpression node, ExpressionOperatorPrecedence outerPrecedence)
- {
- const ExpressionOperatorPrecedence innerPrecedence = ExpressionOperatorPrecedence.Conditional;
-
- SometimesParenthesis(outerPrecedence, innerPrecedence, delegate
- {
- Visit(node.Test, innerPrecedence);
- Out(" ? ");
- Visit(node.IfTrue, innerPrecedence);
- Out(" : ");
- Visit(node.IfFalse, innerPrecedence);
- });
-
- return node;
- }
-
- /// <summary>
- /// Visits the <see cref = "T:System.Linq.Expressions.ConstantExpression" />.
- /// </summary>
- /// <param name = "node">The expression to visit.</param>
- /// <returns>
- /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
- /// </returns>
- protected override Expression VisitConstant(ConstantExpression node)
- {
- if (node.Value == null)
- {
- // Avoid converting/casting the type, if it already converted/casted.
- if (_currentPrecedence == ExpressionOperatorPrecedence.Assignment)
- ConvertTypeToCSharpKeywordIncludeNullable(node.Type);
- Out("null");
- return node;
- }
-
- var s = Convert.ToString(node.Value, CultureInfo.InvariantCulture);
- if (node.Value is string)
- {
- Out("\"");
- OutLiteral(node.Value as string);
- Out("\"");
- return node;
- }
- if (node.Value is bool)
- {
- Out(node.Value.ToString().ToLower());
- return node;
- }
- if (node.Value is char)
- {
- Out("'");
- OutLiteral((char)node.Value);
- Out("'");
- return node;
- }
- if (node.Value is Enum)
- {
- var enumType = node.Value.GetType();
- if (TypeExistsOnServer(enumType))
- {
- Out(enumType.FullName.Replace("+", "."));
- Out('.');
- Out(s);
- return node;
- }
- if (convention.SaveEnumsAsIntegers)
- Out((Convert.ToInt32(node.Value)).ToString());
- else
- {
- Out('"');
- Out(node.Value.ToString());
- Out('"');
- }
- return node;
- }
- if (node.Value is decimal)
- {
- Out(s);
- Out('M');
- return node;
- }
- Out(s);
- return node;
- }
-
- private void OutLiteral(string value)
- {
- if (value.Length == 0)
- return;
-
- _out.Append(string.Concat(value.ToCharArray().Select(EscapeChar)));
- }
-
- private void OutLiteral(char c)
- {
- _out.Append(EscapeChar(c));
- }
-
- private static string EscapeChar(char c)
- {
- var index = Array.IndexOf(LiteralSymbolsToEscape, c);
-
- if (index != -1)
- return LiteralEscapedSymbols[index];
-
- if (!char.IsLetterOrDigit(c) && !char.IsWhiteSpace(c) && !char.IsSymbol(c) && !char.IsPunctuation(c))
- return @"\u" + ((int)c).ToString("x4");
-
- #if !DNXCORE50
- return c.ToString(CultureInfo.InvariantCulture);
- #else
- return c.ToString();
- #endif
- }
-
- private void ConvertTypeToCSharpKeywordIncludeNullable(Type type)
- {
- var nonNullableType = Nullable.GetUnderlyingType(type);
- type = nonNullableType ?? type;
- var isNullableType = nonNullableType != null;
-
-
- // we only cast enums and types is mscorlib. We don't support anything else
- // because the VB compiler like to put converts all over the place, and include
- // types that we can't really support (only exists on the client)
- if (ShouldConvert(type) == false)
- return;
-
- Out("(");
- Out(ConvertTypeToCSharpKeyword(type));
-
- if (isNullableType && nonNullableType != typeof(Guid))
- {
- Out("?");
- }
- Out(")");
- }
-
- private string ConvertTypeToCSharpKeyword(Type type)
- {
- if (type.IsGenericType())
- {
- if (TypeExistsOnServer(type) == false)
- throw new InvalidOperationException("Cannot make use of type " + type + " because it is a generic type that doesn't exists on the server");
- var typeDefinition = type.GetGenericTypeDefinition();
- var sb = new StringBuilder(typeDefinition.FullName, 0)
- {
- Length = typeDefinition.FullName.IndexOf('`')
- };
- sb.Replace('+', '.');
- sb.Append("<");
-
- var arguments = type.GetGenericArguments();
- for (int i = 0; i < arguments.Length; i++)
- {
- if (i != 0)
- sb.Append(", ");
- sb.Append(ConvertTypeToCSharpKeyword(arguments[i]));
- }
-
- sb.Append(">");
-
- return sb.ToString();
- }
-
- if (type == typeof(string))
- {
- return "string";
- }
- if (type == typeof(Guid) || type == typeof(Guid?))
- {
- return "string"; // on the server, Guids are represented as strings
- }
- if (type == typeof(char))
- {
- return "char";
- }
- if (type == typeof(bool))
- {
- return "bool";
- }
- if (type == typeof(bool?))
- {
- return "bool?";
- }
- if (type == typeof(decimal))
- {
- return "decimal";
- }
- if (type == typeof(decimal?))
- {
- return "decimal?";
- }
- if (type == typeof(double))
- {
- return "double";
- }
- if (type == typeof(double?))
- {
- return "double?";
- }
- if (type == typeof(float))
- {
- return "float";
- }
- if (type == typeof(float?))
- {
- return "float?";
- }
-
- if (type == typeof(long))
- {
- return "long";
- }
- if (type == typeof(long?))
- {
- return "long?";
- }
- if (type == typeof(int))
- {
- return "int";
- }
- if (type == typeof(int?))
- {
- return "int?";
- }
- if (type == typeof(short))
- {
- return "short";
- }
- if (type == typeof(short?))
- {
- return "short?";
- }
- if (type == typeof(byte))
- {
- return "byte";
- }
- if (type == typeof(byte?))
- {
- return "byte?";
- }
- if (type.IsEnum())
- {
- return "string";
- }
- if (type.FullName == "System.Object")
- {
- return "object";
- }
-
- const string knownNamespace = "System";
- if (knownNamespace == type.Namespace)
- return type.Name;
- return type.FullName;
- }
-
- private bool TypeExistsOnServer(Type type)
- {
- if (type.Assembly() == typeof(object).Assembly()) // mscorlib
- return true;
-
- if (type.Assembly() == typeof(Uri).Assembly()) // System assembly
- return true;
-
- if (type.Assembly() == typeof(HashSet<>).Assembly()) // System.Core
- return true;
-
- if (type.Assembly() == typeof(RavenJObject).Assembly())
- return true;
-
- if (type.Assembly().FullName.StartsWith("Lucene.Net") &&
- type.Assembly().FullName.Contains("PublicKeyToken=85089178b9ac3181"))
- return true;
-
- return false;
- }
-
- /// <summary>
- /// Visits the <see cref = "T:System.Linq.Expressions.DebugInfoExpression" />.
- /// </summary>
- /// <param name = "node">The expression to visit.</param>
- /// <returns>
- /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
- /// </returns>
- protected override Expression VisitDebugInfo(DebugInfoExpression node)
- {
- var s = string.Format(CultureInfo.CurrentCulture, "<DebugInfo({0}: {1}, {2}, {3}, {4})>",
- new object[] { node.Document.FileName, node.StartLine, node.StartColumn, node.EndLine, node.EndColumn });
- Out(s);
- return node;
- }
-
- /// <summary>
- /// Visits the <see cref = "T:System.Linq.Expressions.DefaultExpression" />.
- /// </summary>
- /// <param name = "node">The expression to visit.</param>
- /// <returns>
- /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
- /// </returns>
- protected override Expression VisitDefault(DefaultExpression node)
- {
- Out("default(");
-
- var nonNullable = Nullable.GetUnderlyingType(node.Type);
- Out(ConvertTypeToCSharpKeyword(nonNullable ?? node.Type));
- if (nonNullable != null && nonNullable != typeof(Guid))
- Out("?");
-
- Out(")");
- return node;
- }
-
- #if !DNXCORE50
- /// <summary>
- /// Visits the children of the <see cref = "T:System.Linq.Expressions.DynamicExpression" />.
- /// </summary>
- /// <param name = "node">The expression to visit.</param>
- /// <returns>
- /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
- /// </returns>
- protected override Expression VisitDynamic(DynamicExpression node)
- {
- Out(FormatBinder(node.Binder));
- VisitExpressions('(', node.Arguments, ')');
- return node;
- }
- #endif
-
- /// <summary>
- /// Visits the element init.
- /// </summary>
- /// <param name = "initializer">The initializer.</param>
- /// <returns></returns>
- protected override ElementInit VisitElementInit(ElementInit initializer)
- {
- Out(initializer.AddMethod.ToString());
- VisitExpressions('(', initializer.Arguments, ')');
- return initializer;
- }
-
- private void VisitExpressions<T>(char open, IEnumerable<T> expressions, char close) where T : Expression
- {
- Out(open);
- if (expressions != null)
- {
- var flag = true;
- foreach (var local in expressions)
- {
- if (flag)
- {
- flag = false;
- }
- else
- {
- Out(", ");
- }
- Visit(local, ExpressionOperatorPrecedence.ParenthesisNotNeeded);
- }
- }
- Out(close);
- }
-
- /// <summary>
- /// Visits the children of the extension expression.
- /// </summary>
- /// <param name = "node">The expression to visit.</param>
- /// <returns>
- /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
- /// </returns>
- protected override Expression VisitExtension(Expression node)
- {
- #if !DNXCORE50
- const BindingFlags bindingAttr = BindingFlags.ExactBinding | BindingFlags.Public | BindingFlags.Instance;
- #else
- const BindingFlags bindingAttr = BindingFlags.Public | BindingFlags.Instance;
- #endif
-
- if (node.GetType().GetMethod("ToString", bindingAttr, null, ReflectionUtils.EmptyTypes, null).DeclaringType !=
- typeof(Expression))
- {
- Out(node.ToString());
- return node;
- }
- Out("[");
- Out(node.NodeType == ExpressionType.Extension ? node.GetType().FullName : node.NodeType.ToString());
- Out("]");
- return node;
- }
-
- /// <summary>
- /// Visits the children of the <see cref = "T:System.Linq.Expressions.GotoExpression" />.
- /// </summary>
- /// <param name = "node">The expression to visit.</param>
- /// <returns>
- /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
- /// </returns>
- protected override Expression VisitGoto(GotoExpression node)
- {
- #if !DNXCORE50
- Out(node.Kind.ToString().ToLower(CultureInfo.CurrentCulture));
- #else
- Out(node.Kind.ToString().ToLower());
- #endif
-
- DumpLabel(node.Target);
- if (node.Value != null)
- {
- Out(" (");
- Visit(node.Value);
- Out(") ");
- }
- return node;
- }
-
- /// <summary>
- /// Visits the children of the <see cref = "T:System.Linq.Expressions.IndexExpression" />.
- /// </summary>
- /// <param name = "node">The expression to visit.</param>
- /// <returns>
- /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
- /// </returns>
- protected override Expression VisitIndex(IndexExpression node)
- {
- if (node.Object != null)
- {
- Visit(node.Object);
- }
- else
- {
- Out(node.Indexer.DeclaringType.Name);
- }
- if (node.Indexer != null)
- {
- Out(".");
- Out(node.Indexer.Name);
- }
- VisitExpressions('[', node.Arguments, ']');
- return node;
- }
-
- /// <summary>
- /// Visits the children of the <see cref = "T:System.Linq.Expressions.InvocationExpression" />.
- /// </summary>
- /// <param name = "node">The expression to visit.</param>
- /// <returns>
- /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
- /// </returns>
- protected override Expression VisitInvocation(InvocationExpression node)
- {
- Out("Invoke(");
- Visit(node.Expression);
- var num = 0;
- var count = node.Arguments.Count;
- while (num < count)
- {
- Out(", ");
- Visit(node.Arguments[num]);
- num++;
- }
- Out(")");
- return node;
- }
-
- /// <summary>
- /// Visits the children of the <see cref = "T:System.Linq.Expressions.LabelExpression" />.
- /// </summary>
- /// <param name = "node">The expression to visit.</param>
- /// <returns>
- /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
- /// </returns>
- protected override Expression VisitLabel(LabelExpression node)
- {
- Out("{ ... } ");
- DumpLabel(node.Target);
- Out(":");
- return node;
- }
-
- /// <summary>
- /// Visits the lambda.
- /// </summary>
- /// <typeparam name = "T"></typeparam>
- /// <param name = "node">The node.</param>
- /// <returns></returns>
- protected override Expression VisitLambda<T>(Expression<T> node)
- {
- if (node.Parameters.Count == 1)
- {
- Visit(node.Parameters[0]);
- }
- else
- {
- VisitExpressions('(', node.Parameters, ')');
- }
- Out(" => ");
- var body = node.Body;
- if (castLambdas)
- {
- switch (body.NodeType)
- {
- case ExpressionType.Convert:
- case ExpressionType.ConvertChecked:
- break;
- default:
- body = Expression.Convert(body, body.Type);
- break;
- }
- }
- Visit(body);
- return node;
- }
-
- /// <summary>
- /// Visits the children of the <see cref = "T:System.Linq.Expressions.ListInitExpression" />.
- /// </summary>
- /// <param name = "node">The expression to visit.</param>
- /// <returns>
- /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
- /// </returns>
- protected override Expression VisitListInit(ListInitExpression node)
- {
- Visit(node.NewExpression);
- Out(" {");
- var num = 0;
- var count = node.Initializers.Count;
- while (num < count)
- {
- if (num > 0)
- {
- Out(", ");
- }
- Out("{");
- bool first = true;
- foreach (var expression in node.Initializers[num].Arguments)
- {
- if (first == false)
- Out(", ");
- first = false;
- Visit(expression);
- }
- Out("}");
- num++;
- }
- Out("}");
- return node;
- }
-
- /// <summary>
- /// Visits the children of the <see cref = "T:System.Linq.Expressions.LoopExpression" />.
- /// </summary>
- /// <param name = "node">The expression to visit.</param>
- /// <returns>
- /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
- /// </returns>
- protected override Expression VisitLoop(LoopExpression node)
- {
- Out("loop { ... }");
- return node;
- }
-
- /// <summary>
- /// Visits the children of the <see cref = "T:System.Linq.Expressions.MemberExpression" />.
- /// </summary>
- /// <pa…
Large files files are truncated, but you can click here to view the full file