Improved method overload matching
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/f38c2d00 Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/f38c2d00 Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/f38c2d00 Branch: refs/heads/tp32 Commit: f38c2d004e4683adcc65dd1c5ab9e9aa84e1e2be Parents: 8fc2b84 Author: Jorge Bay Gondra <jorgebaygon...@gmail.com> Authored: Thu Nov 2 18:05:04 2017 +0100 Committer: Jorge Bay Gondra <jorgebaygon...@gmail.com> Committed: Thu Nov 30 10:00:08 2017 +0100 ---------------------------------------------------------------------- .../Process/Traversal/Instruction.cs | 6 +- .../ContextBasedParameter.cs | 5 +- .../TraversalEvaluation/ITokenParameter.cs | 8 +- .../TraversalEvaluation/LiteralParameter.cs | 87 ++++++++++++ .../ModernGraphTypeInformation.cs | 4 +- .../TraversalEvaluation/NumericParameter.cs | 84 ------------ .../StaticTraversalParameter.cs | 20 ++- .../TraversalEvaluation/StringParameter.cs | 7 +- .../Gherkin/TraversalEvaluation/Token.cs | 11 ++ .../TraversalEnumParameter.cs | 7 +- .../TraversalEvaluationTests.cs | 15 ++- .../TraversalEvaluation/TraversalParser.cs | 135 +++++++++++++++++-- .../TraversalPredicateParameter.cs | 19 ++- 13 files changed, 279 insertions(+), 129 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f38c2d00/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Instruction.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Instruction.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Instruction.cs index a9163be..65847c5 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Instruction.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Instruction.cs @@ -27,9 +27,7 @@ namespace Gremlin.Net.Process.Traversal /// Represents a <see cref="Bytecode" /> instruction by an operator name and its arguments. /// </summary> public class Instruction - { - private static readonly object[] EmptyArgs = new object[0]; - + { /// <summary> /// Initializes a new instance of the <see cref="Instruction" /> class. /// </summary> @@ -38,7 +36,7 @@ namespace Gremlin.Net.Process.Traversal public Instruction(string operatorName, params dynamic[] arguments) { OperatorName = operatorName; - Arguments = arguments ?? EmptyArgs; + Arguments = arguments; } /// <summary> http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f38c2d00/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ContextBasedParameter.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ContextBasedParameter.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ContextBasedParameter.cs index 4f837d4..fa8f3f1 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ContextBasedParameter.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ContextBasedParameter.cs @@ -57,7 +57,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation _name = name; } - private void SetValue(IDictionary<string, object> parameterValues) + public void SetContextParameterValues(IDictionary<string, object> parameterValues) { if (parameterValues == null || !parameterValues.TryGetValue(_name, out var value)) { @@ -66,9 +66,8 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation _value = value; } - public object GetValue(IDictionary<string, object> contextParameterValues) + public object GetValue() { - SetValue(contextParameterValues); return _value; } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f38c2d00/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ITokenParameter.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ITokenParameter.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ITokenParameter.cs index 9b06e80..357e35b 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ITokenParameter.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ITokenParameter.cs @@ -31,12 +31,16 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation /// <summary> /// Gets the value of the parameter /// </summary> - object GetValue(IDictionary<string, object> contextParameterValues); + object GetValue(); /// <summary> /// Gets the type of the parameter /// </summary> - /// <returns></returns> Type GetParameterType(); + + /// <summary> + /// Sets the context parameter values by a given name, ie: "v1Id" = 1 + /// </summary> + void SetContextParameterValues(IDictionary<string, object> values); } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f38c2d00/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/LiteralParameter.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/LiteralParameter.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/LiteralParameter.cs new file mode 100644 index 0000000..da0ac24 --- /dev/null +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/LiteralParameter.cs @@ -0,0 +1,87 @@ +#region License + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#endregion + +using System; +using System.Collections.Generic; + +namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation +{ + /// <summary> + /// Represents a literal (number / boolean) that is allowed as a gremlin parameter. + /// </summary> + public class LiteralParameter<T> : ITokenParameter, IEquatable<LiteralParameter<T>> where T : struct + { + public bool Equals(LiteralParameter<T> other) + { + return Value.Equals(other.Value); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((LiteralParameter<T>) obj); + } + + public override int GetHashCode() + { + return Value.GetHashCode(); + } + + public T Value { get; } + + public LiteralParameter(T value) + { + Value = value; + } + + public override string ToString() + { + return $"NumericParameter<{typeof(T).Name}>({Value})"; + } + + public object GetValue() + { + return Value; + } + + public Type GetParameterType() + { + return typeof(T); + } + + public void SetContextParameterValues(IDictionary<string, object> parameterValues) + { + + } + } + + internal static class LiteralParameter + { + public static LiteralParameter<TType> Create<TType>(TType value) where TType : struct + { + return new LiteralParameter<TType>(value); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f38c2d00/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ModernGraphTypeInformation.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ModernGraphTypeInformation.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ModernGraphTypeInformation.cs index bce3449..e26ec5f 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ModernGraphTypeInformation.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/ModernGraphTypeInformation.cs @@ -47,7 +47,6 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation { switch (method.Name) { - case nameof(GraphTraversal<object,object>.ValueMap): case nameof(GraphTraversal<object,object>.Values) when parameterValues.Length == 1: // The parameter contains the element property names var properties = ((IEnumerable) parameterValues[parameterValues.Length - 1]).Cast<string>(); @@ -57,6 +56,9 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation return types[0]; } return typeof(object); + case nameof(GraphTraversal<object,object>.ValueMap): + // Use IDictionary<string, object> for value maps + return typeof(object); } return null; } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f38c2d00/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/NumericParameter.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/NumericParameter.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/NumericParameter.cs deleted file mode 100644 index 7428cc2..0000000 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/NumericParameter.cs +++ /dev/null @@ -1,84 +0,0 @@ -#region License - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#endregion - -using System; -using System.Collections.Generic; - -namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation -{ - public class NumericParameter<T> : ITokenParameter, IEquatable<NumericParameter<T>> where T : struct - { - public bool Equals(NumericParameter<T> other) - { - return Value.Equals(other.Value); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != GetType()) return false; - return Equals((NumericParameter<T>) obj); - } - - public override int GetHashCode() - { - return Value.GetHashCode(); - } - - public T Value { get; } - - public NumericParameter(T value) - { - Value = value; - } - - public override string ToString() - { - return $"NumericParameter<{typeof(T).Name}>({Value})"; - } - - public object GetValue(IDictionary<string, object> contextParameterValues) - { - return Value; - } - - public Type GetParameterType() - { - return typeof(T); - } - } - - internal static class NumericParameter - { - public static NumericParameter<TType> Create<TType>(TType value) where TType : struct - { - return new NumericParameter<TType>(value); - } - - public static NumericParameter<long> CreateLong(string value) - { - return NumericParameter.Create(Convert.ToInt64(value.Substring(0, value.Length - 1))); - } - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f38c2d00/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/StaticTraversalParameter.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/StaticTraversalParameter.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/StaticTraversalParameter.cs index dd38dca..d8fad5b 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/StaticTraversalParameter.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/StaticTraversalParameter.cs @@ -31,6 +31,15 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation internal class StaticTraversalParameter : ITokenParameter, IEquatable<StaticTraversalParameter> { private readonly string _traversalText; + private IDictionary<string, object> _contextParameterValues; + + public IList<Token> Tokens { get; } + + public StaticTraversalParameter(IList<Token> tokens, string traversalText) + { + _traversalText = traversalText; + Tokens = tokens; + } public bool Equals(StaticTraversalParameter other) { @@ -50,9 +59,9 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation return Tokens != null ? Tokens.GetHashCode() : 0; } - public object GetValue(IDictionary<string, object> contextParameterValues) + public object GetValue() { - return TraversalParser.GetTraversalFromTokens(Tokens, null, contextParameterValues, _traversalText); + return TraversalParser.GetTraversalFromTokens(Tokens, null, _contextParameterValues, _traversalText); } public Type GetParameterType() @@ -60,12 +69,9 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation return typeof(ITraversal); } - public IList<Token> Tokens { get; } - - public StaticTraversalParameter(IList<Token> tokens, string traversalText) + public void SetContextParameterValues(IDictionary<string, object> parameterValues) { - _traversalText = traversalText; - Tokens = tokens; + _contextParameterValues = parameterValues; } } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f38c2d00/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/StringParameter.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/StringParameter.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/StringParameter.cs index 430c2d2..716a2ce 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/StringParameter.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/StringParameter.cs @@ -67,7 +67,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation return $"{GetType().Name}({Value})"; } - public object GetValue(IDictionary<string, object> contextParameterValues) + public object GetValue() { return Value; } @@ -76,5 +76,10 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation { return typeof(string); } + + public void SetContextParameterValues(IDictionary<string, object> parameterValues) + { + + } } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f38c2d00/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/Token.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/Token.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/Token.cs index 539be89..e0acf4b 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/Token.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/Token.cs @@ -77,5 +77,16 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation Name = name; Parameters = new[] {parameter}; } + + /// <summary> + /// Sets the context parameter values by a given name, ie: "v1Id" = 1 + /// </summary> + public void SetContextParameterValues(IDictionary<string, object> values) + { + foreach (var tokenParameter in Parameters) + { + tokenParameter.SetContextParameterValues(values); + } + } } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f38c2d00/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalEnumParameter.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalEnumParameter.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalEnumParameter.cs index c99fc95..c305df7 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalEnumParameter.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalEnumParameter.cs @@ -85,7 +85,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation return _text.GetHashCode(); } - public object GetValue(IDictionary<string, object> contextParameterValues) + public object GetValue() { return _value; } @@ -94,5 +94,10 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation { return _type; } + + public void SetContextParameterValues(IDictionary<string, object> parameterValues) + { + + } } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f38c2d00/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalEvaluationTests.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalEvaluationTests.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalEvaluationTests.cs index be5f444..d2a62b4 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalEvaluationTests.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalEvaluationTests.cs @@ -23,6 +23,7 @@ using System; using System.Linq; +using Gremlin.Net.Process.Traversal; using Gremlin.Net.Structure; using Xunit; using Xunit.Abstractions; @@ -40,13 +41,13 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation Tuple.Create("g.V().values(\"name\")", new[] {new Token("values", new StringParameter("name"))}), Tuple.Create("g.V().constant(123l)", - new[] {new Token("constant", new[] {NumericParameter.Create(123L)})}), + new[] {new Token("constant", new[] {LiteralParameter.Create(123L)})}), Tuple.Create("g.V().constant(123)", - new[] {new Token("constant", new[] {NumericParameter.Create(123)})}), + new[] {new Token("constant", new[] {LiteralParameter.Create(123)})}), Tuple.Create("g.V().constant(123.1)", - new[] {new Token("constant", new[] {NumericParameter.Create(123.1)})}), + new[] {new Token("constant", new[] {LiteralParameter.Create(123.1)})}), Tuple.Create("g.V().constant(123.1f)", - new[] {new Token("constant", new[] {NumericParameter.Create(123.1f)})}), + new[] {new Token("constant", new[] {LiteralParameter.Create(123.1f)})}), Tuple.Create("g.V().has(\"no\").count()", new[] {new Token("has", new StringParameter("no")), new Token("count")}), Tuple.Create("g.V().has(\"lang\", \"java\")", @@ -57,7 +58,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation Tuple.Create("g.V().has(\"age\",P.gt(27))", new[] {new Token("has", new ITokenParameter[] { new StringParameter("age"), new TraversalPredicateParameter( - new[] { new Token("P"), new Token("gt", NumericParameter.Create(27)) }) })}), + new[] { new Token("P"), new Token("gt", LiteralParameter.Create(27)) }) })}), Tuple.Create("g.V().count(Scope.local)", new[] { new Token("count", new TraversalEnumParameter("Scope.local"))}) }; @@ -74,10 +75,10 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation var traversalTexts = new [] { Tuple.Create("g.V().count()", 2), -// //"g.V().constant(123L)", Can be parsed using the new type-safe API +// Tuple.Create("g.V().constant(123L)", 2), // Can be parsed using the new type-safe API Tuple.Create("g.V().has(\"no\").count()", 3), Tuple.Create("g.V().values(\"age\")", 2), - Tuple.Create("g.V().valueMap(\"name\", \"age\")", 2), + Tuple.Create("g.V().valueMap(true, \"name\", \"age\")", 2), Tuple.Create("g.V().where(__.in(\"created\").count().is(1)).values(\"name\")", 3), Tuple.Create("g.V().count(Scope.local)", 2), Tuple.Create("g.V().values(\"age\").is(P.lte(30))", 3) http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f38c2d00/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalParser.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalParser.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalParser.cs index 2bd92bc..bb0aac8 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalParser.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalParser.cs @@ -23,6 +23,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.Text.RegularExpressions; using Gremlin.Net.Process.Traversal; @@ -78,13 +79,16 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation for (var i = 1; i < tokens.Count; i++) { var token = tokens[i]; + token.SetContextParameterValues(contextParameterValues); var name = GetCsharpName(token.Name); - var method = instanceType.GetMethod(name); + var methods = instanceType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static) + .Where(m => m.Name == name).ToList(); + var method = GetClosestMethod(methods, token.Parameters); if (method == null) { - throw new InvalidOperationException($"Traversal method '{tokens[i]}' not found for testing"); + throw new InvalidOperationException($"Traversal method '{tokens[i].Name}' not found for testing"); } - var parameterValues = BuildParameters(method, token, contextParameterValues, out var genericParameters); + var parameterValues = BuildParameters(method, token, out var genericParameters); method = BuildGenericMethod(method, genericParameters, parameterValues); instance = method.Invoke(instance, parameterValues); instanceType = instance.GetType(); @@ -92,6 +96,84 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation return (ITraversal) instance; } + /// <summary> + /// Find the method that supports the amount of parameters provided + /// </summary> + private static MethodInfo GetClosestMethod(IList<MethodInfo> methods, IList<ITokenParameter> tokenParameters) + { + if (methods.Count == 0) + { + return null; + } + if (methods.Count == 1) + { + return methods[0]; + } + var ordered = methods.OrderBy(m => m.GetParameters().Length); + if (tokenParameters.Count == 0) + { + return ordered.First(); + } + MethodInfo lastMethod = null; + var compatibleMethods = new Dictionary<int, MethodInfo>(); + foreach (var method in ordered) + { + lastMethod = method; + var parameters = method.GetParameters(); + if (tokenParameters.Count < parameters.Length) + { + continue; + } + var matched = true; + var exactMatches = 0; + for (var i = 0; i < tokenParameters.Count; i++) + { + if (parameters.Length <= i) + { + // The method contains less parameters (and no params array) than provided + matched = false; + break; + } + var methodParameter = parameters[i]; + var tokenParameterType = tokenParameters[i].GetParameterType(); + // Match either the same parameter type + matched = methodParameter.ParameterType == tokenParameterType; + if (matched) + { + exactMatches++; + } + else if (IsParamsArray(methodParameter)) + { + matched = methodParameter.ParameterType == typeof(object[]) || + methodParameter.ParameterType.GetElementType() == tokenParameterType; + // The method has params array, no further parameters are going to be defined + break; + } + else + { + if (!methodParameter.ParameterType.GetTypeInfo().IsAssignableFrom(tokenParameterType)) + { + break; + } + // Is assignable to the parameter type + matched = true; + } + } + if (matched) + { + compatibleMethods[exactMatches] = method; + } + } + // Attempt to use the method with the higher number of matches or the last one + return compatibleMethods.OrderByDescending(kv => kv.Key).Select(kv => kv.Value).FirstOrDefault() ?? + lastMethod; + } + + private static bool IsParamsArray(ParameterInfo methodParameter) + { + return methodParameter.IsDefined(typeof(ParamArrayAttribute), false); + } + private static MethodInfo BuildGenericMethod(MethodInfo method, IDictionary<string, Type> genericParameters, object[] parameterValues) { @@ -114,7 +196,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation { throw new InvalidOperationException( $"Can not build traversal to test as '{method.Name}()' method is generic and type '{name}'" + - $" can not be inferred"); + " can not be inferred"); } types[i] = type; } @@ -122,7 +204,6 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation } private static object[] BuildParameters(MethodInfo method, Token token, - IDictionary<string, object> contextParameterValues, out IDictionary<string, Type> genericParameterTypes) { var paramsInfo = method.GetParameters(); @@ -135,7 +216,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation if (token.Parameters.Count > i) { var tokenParameter = token.Parameters[i]; - value = tokenParameter.GetValue(contextParameterValues); + value = tokenParameter.GetValue(); if (info.ParameterType.IsGenericParameter) { // We've provided a value for parameter of a generic type, we can infer the @@ -144,9 +225,26 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation // if we have the type of value we have the type of E2. genericParameterTypes.Add(info.ParameterType.Name, tokenParameter.GetParameterType()); } - else if (info.ParameterType == typeof(object[])) + } + if (IsParamsArray(info)) + { + // For `params type[] value` we should provide an empty array + if (value == null) + { + // An empty array + value = Array.CreateInstance(info.ParameterType.GetElementType(), 0); + } + else if (!value.GetType().IsArray) { - value = new [] {value}; + // An array with the parameter values + // No more method parameters after this one + var arr = Array.CreateInstance(info.ParameterType.GetElementType(), token.Parameters.Count - i); + arr.SetValue(value, 0); + for (var j = 1; j < token.Parameters.Count - i; j++) + { + arr.SetValue(token.Parameters[i + j].GetValue(), j); + } + value = arr; } } parameters[i] = value ?? GetDefault(info.ParameterType); @@ -282,10 +380,21 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation return new TraversalPredicateParameter(ParseTokens(text, ref i)); } var parameterText = text.Substring(i, text.IndexOf(')', i) - i); - if (string.IsNullOrWhiteSpace(parameterText)) + var separatorIndex = parameterText.IndexOf(','); + if (separatorIndex >= 0) + { + parameterText = parameterText.Substring(0, separatorIndex); + } + parameterText = parameterText.Trim(); + if (parameterText == "") { return null; } + if (parameterText == "true" || parameterText == "false") + { + i += parameterText.Length - 1; + return LiteralParameter.Create(Convert.ToBoolean(parameterText)); + } if (RegexEnum.IsMatch(parameterText)) { i += parameterText.Length - 1; @@ -311,18 +420,18 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation i += match.Value.Length - 1; if (numericText.EndsWith("L")) { - return NumericParameter.Create(Convert.ToInt64(match.Value.Substring(0, match.Value.Length - 1))); + return LiteralParameter.Create(Convert.ToInt64(match.Value.Substring(0, match.Value.Length - 1))); } if (numericText.EndsWith("F")) { - return NumericParameter.Create(Convert.ToSingle(match.Value.Substring(0, match.Value.Length-1))); + return LiteralParameter.Create(Convert.ToSingle(match.Value.Substring(0, match.Value.Length-1))); } if (match.Groups[1].Value != "") { // Captured text with the decimal separator - return NumericParameter.Create(Convert.ToDouble(match.Value)); + return LiteralParameter.Create(Convert.ToDouble(match.Value)); } - return NumericParameter.Create(Convert.ToInt32(match.Value)); + return LiteralParameter.Create(Convert.ToInt32(match.Value)); } private enum ParsingPart http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f38c2d00/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalPredicateParameter.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalPredicateParameter.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalPredicateParameter.cs index 83060c7..57262c1 100644 --- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalPredicateParameter.cs +++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalEvaluation/TraversalPredicateParameter.cs @@ -34,6 +34,14 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation /// </summary> internal class TraversalPredicateParameter : ITokenParameter, IEquatable<TraversalPredicateParameter> { + private IDictionary<string, object> _contextParameterValues; + public IList<Token> Tokens { get; } + + public TraversalPredicateParameter(IList<Token> tokens) + { + Tokens = tokens; + } + public bool Equals(TraversalPredicateParameter other) { return Tokens.SequenceEqual(other.Tokens); @@ -52,13 +60,14 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation return Tokens != null ? Tokens.GetHashCode() : 0; } - public object GetValue(IDictionary<string, object> contextParameterValues) + public object GetValue() { var type = typeof(P); object instance = null; for (var i = 1; i < Tokens.Count; i++) { var token = Tokens[i]; + token.SetContextParameterValues(_contextParameterValues); var method = type.GetMethod(TraversalParser.GetCsharpName(token.Name), BindingFlags.Static | BindingFlags.Public); if (method == null) @@ -66,7 +75,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation throw new InvalidOperationException($"Predicate (P) method '{token}' not found for testing"); } instance = method.Invoke(instance, - new object[] {token.Parameters.Select(p => p.GetValue(contextParameterValues)).ToArray()}); + new object[] {token.Parameters.Select(p => p.GetValue()).ToArray()}); } return instance; } @@ -76,11 +85,9 @@ namespace Gremlin.Net.IntegrationTest.Gherkin.TraversalEvaluation return typeof(TraversalPredicate); } - public IList<Token> Tokens { get; } - - public TraversalPredicateParameter(IList<Token> tokens) + public void SetContextParameterValues(IDictionary<string, object> parameterValues) { - Tokens = tokens; + _contextParameterValues = parameterValues; } } } \ No newline at end of file