Skip to content

Commit a94d3b6

Browse files
committed
out method with inline variable declaration typed or not
1 parent 83952a8 commit a94d3b6

File tree

2 files changed

+90
-26
lines changed

2 files changed

+90
-26
lines changed

CodingSeb.ExpressionEvaluator.Tests/ExpressionEvaluatorTests.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2245,6 +2245,42 @@ public void MethodWithOutParameter()
22452245
.ShouldBe(10);
22462246
}
22472247

2248+
[Test]
2249+
public void MethodWithOutParameterWithoutExistingVariable()
2250+
{
2251+
ExpressionEvaluator evaluator = new ExpressionEvaluator();
2252+
2253+
evaluator.Variables["myDict"] = new Dictionary<string, object>
2254+
{
2255+
{ "ANumber", 10 },
2256+
};
2257+
2258+
evaluator.Evaluate<bool>("myDict.TryGetValue(\"ANumber\",out x)").ShouldBeTrue();
2259+
2260+
evaluator.Variables.ShouldContainKey("x");
2261+
evaluator.Variables["x"]
2262+
.ShouldBeOfType<int>()
2263+
.ShouldBe(10);
2264+
}
2265+
2266+
[Test]
2267+
public void MethodWithOutParameterInlineVarDeclaration()
2268+
{
2269+
ExpressionEvaluator evaluator = new ExpressionEvaluator();
2270+
2271+
evaluator.Variables["myDict"] = new Dictionary<string, object>
2272+
{
2273+
{ "ANumber", 10 },
2274+
};
2275+
2276+
evaluator.Evaluate<bool>("myDict.TryGetValue(\"ANumber\",out int x)").ShouldBeTrue();
2277+
2278+
evaluator.Variables.ShouldContainKey("x");
2279+
evaluator.Variables["x"]
2280+
.ShouldBeOfType<StronglyTypedVariable>()
2281+
.Value.ShouldBe(10);
2282+
}
2283+
22482284
#endregion
22492285
}
22502286
}

CodingSeb.ExpressionEvaluator/ExpressionEvaluator.cs

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public partial class ExpressionEvaluator
5353
protected static readonly Regex lambdaExpressionRegex = new Regex(@"^(?>\s*)(?<args>((?>\s*)[(](?>\s*)([\p{L}_](?>[\p{L}_0-9]*)(?>\s*)([,](?>\s*)[\p{L}_][\p{L}_0-9]*(?>\s*))*)?[)])|[\p{L}_](?>[\p{L}_0-9]*))(?>\s*)=>(?<expression>.*)$", RegexOptions.Singleline | RegexOptions.Compiled);
5454
protected static readonly Regex lambdaArgRegex = new Regex(@"[\p{L}_](?>[\p{L}_0-9]*)", RegexOptions.Compiled);
5555
protected static readonly Regex initInNewBeginningRegex = new Regex(@"^(?>\s*){", RegexOptions.Compiled);
56-
protected static readonly Regex functionArgKeywordsRegex = new Regex(@"^\s*(?<keyword>out|ref)\s*(?<varName>[\p{L}_](?>[\p{L}_0-9]*))", RegexOptions.Compiled | RegexOptions.IgnoreCase);
56+
protected static readonly Regex functionArgKeywordsRegex = new Regex(@"^\s*(?<keyword>out|ref)\s+((?<typeName>[\p{L}_][\p{L}_0-9\.\[\]<>]*[?]?)\s+(?=[\p{L}_]))?(?<varName>[\p{L}_](?>[\p{L}_0-9]*))", RegexOptions.Compiled | RegexOptions.IgnoreCase);
5757

5858
// Depending on OptionInlineNamespacesEvaluationActive. Initialized in constructor
5959
protected string InstanceCreationWithNewKeywordRegexPattern { get { return @"^new(?>\s*)((?<isAnonymous>[{{])|((?<name>[\p{L}_][\p{L}_0-9"+ (OptionInlineNamespacesEvaluationActive ? @"\." : string.Empty) + @"]*)(?>\s*)(?<isgeneric>[<](?>[^<>]+|(?<gentag>[<])|(?<-gentag>[>]))*(?(gentag)(?!))[>])?(?>\s*)((?<isfunction>[(])|(?<isArray>\[)|(?<isInit>[{{]))?))"; } }
@@ -1907,6 +1907,18 @@ protected virtual bool EvaluateVarOrFunc(string expression, Stack<object> stack,
19071907
{
19081908
OutOrRefArg outOrRefArg = new OutOrRefArg() { Index = argIndex, VariableName = functionArgKeywordsMatch.Groups["varName"].Value };
19091909
outOrRefArgs.Add(outOrRefArg);
1910+
1911+
if (functionArgKeywordsMatch.Groups["typeName"].Success)
1912+
{
1913+
Type fixedType = ((ClassOrEnumType)Evaluate(functionArgKeywordsMatch.Groups["typeName"].Value)).Type;
1914+
1915+
variables[outOrRefArg.VariableName] = new StronglyTypedVariable() { Type = fixedType, Value = GetDefaultValueOfType(fixedType) };
1916+
}
1917+
else if (!variables.ContainsKey(outOrRefArg.VariableName))
1918+
{
1919+
variables[outOrRefArg.VariableName] = null;
1920+
}
1921+
19101922
argValue = Evaluate(outOrRefArg.VariableName);
19111923
}
19121924
else
@@ -1917,6 +1929,7 @@ protected virtual bool EvaluateVarOrFunc(string expression, Stack<object> stack,
19171929
argIndex++;
19181930
return argValue;
19191931
});
1932+
19201933
BindingFlags flag = DetermineInstanceOrStatic(ref objType, ref obj, ref valueTypeNestingTrace);
19211934

19221935
if (!OptionStaticMethodsCallActive && (flag & BindingFlags.Static) != 0)
@@ -1952,7 +1965,7 @@ protected virtual bool EvaluateVarOrFunc(string expression, Stack<object> stack,
19521965
{
19531966
oArgs.Insert(0, obj);
19541967
objType = obj.GetType();
1955-
//obj = null;
1968+
19561969
object extentionObj = null;
19571970
for (int e = 0; e < StaticTypesForExtensionsMethods.Count && methodInfo == null; e++)
19581971
{
@@ -1966,7 +1979,7 @@ protected virtual bool EvaluateVarOrFunc(string expression, Stack<object> stack,
19661979
{
19671980
object[] argsArray = oArgs.ToArray();
19681981
stack.Push(methodInfo.Invoke(isExtention ? null : obj, argsArray));
1969-
outOrRefArgs.ForEach(outOrRefArg => variables[outOrRefArg.VariableName] = argsArray[outOrRefArg.Index]);
1982+
outOrRefArgs.ForEach(outOrRefArg => AssignVariable(outOrRefArg.VariableName, argsArray[outOrRefArg.Index]));
19701983
}
19711984
else if (objType.GetProperty(varFuncName, StaticBindingFlag) is PropertyInfo staticPropertyInfo
19721985
&& (staticPropertyInfo.PropertyType.IsSubclassOf(typeof(Delegate)) || staticPropertyInfo.PropertyType == typeof(Delegate))
@@ -2297,7 +2310,7 @@ where method.GetParameters()[0].ParameterType == objType // static extMethod(thi
22972310
Variables[varFuncName] = new StronglyTypedVariable
22982311
{
22992312
Type = classOrEnum.Type,
2300-
Value = !varFuncMatch.Groups["assignationOperator"].Success && classOrEnum.Type.IsValueType ? Activator.CreateInstance(classOrEnum.Type) : null,
2313+
Value = GetDefaultValueOfType(classOrEnum.Type),
23012314
};
23022315
}
23032316

@@ -2331,27 +2344,7 @@ where method.GetParameters()[0].ParameterType == objType // static extMethod(thi
23312344

23322345
if (assign)
23332346
{
2334-
if (Variables.ContainsKey(varFuncName) && Variables[varFuncName] is StronglyTypedVariable stronglyTypedVariable)
2335-
{
2336-
if (cusVarValueToPush == null && stronglyTypedVariable.Type.IsValueType && Nullable.GetUnderlyingType(stronglyTypedVariable.Type) == null)
2337-
{
2338-
throw new ExpressionEvaluatorSyntaxErrorException($"Can not cast null to {stronglyTypedVariable.Type} because it's not a nullable valueType");
2339-
}
2340-
2341-
Type typeToAssign = cusVarValueToPush?.GetType();
2342-
if (typeToAssign == null || stronglyTypedVariable.Type.IsAssignableFrom(typeToAssign))
2343-
{
2344-
stronglyTypedVariable.Value = cusVarValueToPush;
2345-
}
2346-
else
2347-
{
2348-
throw new InvalidCastException($"A object of type {typeToAssign} can not be cast implicitely in {stronglyTypedVariable.Type}");
2349-
}
2350-
}
2351-
else
2352-
{
2353-
Variables[varFuncName] = cusVarValueToPush;
2354-
}
2347+
AssignVariable(varFuncName, cusVarValueToPush);
23552348
}
23562349
}
23572350
else if (varFuncMatch.Groups["assignationOperator"].Success)
@@ -3042,6 +3035,33 @@ protected virtual object ManageKindOfAssignation(string expression, ref int inde
30423035
return result;
30433036
}
30443037

3038+
protected virtual void AssignVariable(string varName, object value)
3039+
{
3040+
if (Variables.ContainsKey(varName) && Variables[varName] is StronglyTypedVariable stronglyTypedVariable)
3041+
{
3042+
if (value == null && stronglyTypedVariable.Type.IsValueType && Nullable.GetUnderlyingType(stronglyTypedVariable.Type) == null)
3043+
{
3044+
throw new ExpressionEvaluatorSyntaxErrorException($"Can not cast null to {stronglyTypedVariable.Type} because it's not a nullable valueType");
3045+
}
3046+
3047+
Type typeToAssign = value?.GetType();
3048+
if (typeToAssign == null || stronglyTypedVariable.Type.IsAssignableFrom(typeToAssign))
3049+
{
3050+
stronglyTypedVariable.Value = value;
3051+
}
3052+
else
3053+
{
3054+
throw new InvalidCastException($"A object of type {typeToAssign} can not be cast implicitely in {stronglyTypedVariable.Type}");
3055+
}
3056+
}
3057+
else
3058+
{
3059+
Variables[varName] = value;
3060+
}
3061+
}
3062+
3063+
protected virtual object GetDefaultValueOfType(Type type) => type.IsValueType ? Activator.CreateInstance(type) : null;
3064+
30453065
protected virtual bool GetLambdaExpression(string expression, Stack<object> stack)
30463066
{
30473067
Match lambdaExpressionMatch = lambdaExpressionRegex.Match(expression);
@@ -3238,7 +3258,15 @@ protected virtual MethodInfo TryToCastMethodParametersToMakeItCallable(MethodInf
32383258
{
32393259
if (!methodInfoToCast.GetParameters()[a].ParameterType.IsAssignableFrom(modifiedArgs[a].GetType()))
32403260
{
3241-
modifiedArgs[a] = Convert.ChangeType(modifiedArgs[a], methodInfoToCast.GetParameters()[a].ParameterType);
3261+
if (methodInfoToCast.GetParameters()[a].ParameterType.IsByRef)
3262+
{
3263+
if(!methodInfoToCast.GetParameters()[a].ParameterType.GetElementType().IsAssignableFrom(modifiedArgs[a].GetType()))
3264+
modifiedArgs[a] = Convert.ChangeType(modifiedArgs[a], methodInfoToCast.GetParameters()[a].ParameterType.GetElementType());
3265+
}
3266+
else
3267+
{
3268+
modifiedArgs[a] = Convert.ChangeType(modifiedArgs[a], methodInfoToCast.GetParameters()[a].ParameterType);
3269+
}
32423270
}
32433271
}
32443272
catch

0 commit comments

Comments
 (0)