Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public DefaultDynamicLinqCustomTypeProvider(bool cacheCustomTypes = true)
_cacheCustomTypes = cacheCustomTypes;
}

/// <inheritdoc cref="IDynamicLinkCustomTypeProvider.GetCustomTypes"/>
/// <inheritdoc cref="IDynamicLinqCustomTypeProvider.GetCustomTypes"/>
public virtual HashSet<Type> GetCustomTypes()
{
if (_cacheCustomTypes)
Expand All @@ -47,7 +47,7 @@ public virtual HashSet<Type> GetCustomTypes()
return GetCustomTypesInternal();
}

/// <inheritdoc cref="IDynamicLinkCustomTypeProvider.GetExtensionMethods"/>
/// <inheritdoc cref="IDynamicLinqCustomTypeProvider.GetExtensionMethods"/>
public Dictionary<Type, List<MethodInfo>> GetExtensionMethods()
{
if (_cacheCustomTypes)
Expand All @@ -63,7 +63,7 @@ public Dictionary<Type, List<MethodInfo>> GetExtensionMethods()
return GetExtensionMethodsInternal();
}

/// <inheritdoc cref="IDynamicLinkCustomTypeProvider.ResolveType"/>
/// <inheritdoc cref="IDynamicLinqCustomTypeProvider.ResolveType"/>
public Type ResolveType(string typeName)
{
Check.NotEmpty(typeName, nameof(typeName));
Expand All @@ -72,7 +72,7 @@ public Type ResolveType(string typeName)
return ResolveType(assemblies, typeName);
}

/// <inheritdoc cref="IDynamicLinkCustomTypeProvider.ResolveTypeBySimpleName"/>
/// <inheritdoc cref="IDynamicLinqCustomTypeProvider.ResolveTypeBySimpleName"/>
public Type ResolveTypeBySimpleName(string simpleTypeName)
{
Check.NotEmpty(simpleTypeName, nameof(simpleTypeName));
Expand All @@ -91,7 +91,7 @@ private Dictionary<Type, List<MethodInfo>> GetExtensionMethodsInternal()
{
var types = GetCustomTypes();

List<Tuple<Type, MethodInfo>> list= new List<Tuple<Type, MethodInfo>>();
List<Tuple<Type, MethodInfo>> list = new List<Tuple<Type, MethodInfo>>();

foreach (var type in types)
{
Expand Down
125 changes: 106 additions & 19 deletions src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1045,6 +1045,42 @@ Expression ParseIdentifier()
return expr;
}

//// This could be enum like "MyEnum.Value1"
//if (_textParser.CurrentToken.Id == TokenId.Identifier)
//{
// var parts = new List<string> { _textParser.CurrentToken.Text };

// _textParser.NextToken();
// _textParser.ValidateToken(TokenId.Dot, Res.DotExpected);
// while (_textParser.CurrentToken.Id == TokenId.Dot || _textParser.CurrentToken.Id == TokenId.Plus)
// {
// parts.Add(_textParser.CurrentToken.Text);

// _textParser.NextToken();
// _textParser.ValidateToken(TokenId.Identifier, Res.IdentifierExpected);

// parts.Add(_textParser.CurrentToken.Text);

// _textParser.NextToken();
// }

// var enumTypeAsString = string.Join("", parts.Take(parts.Count - 2).ToArray());
// var enumType = _typeFinder.FindTypeByName(enumTypeAsString, null, true);
// if (enumType == null)
// {
// throw ParseError(_textParser.CurrentToken.Pos, Res.EnumTypeNotFound, enumTypeAsString);
// }

// string enumValue = parts.Last();
// var @enum = TypeHelper.ParseEnum(enumValue, enumType);
// if (@enum == null)
// {
// throw ParseError(_textParser.CurrentToken.Pos, Res.EnumValueNotDefined, enumValue, enumTypeAsString);
// }

// return Expression.Constant(@enum);
//}

if (_it != null)
{
return ParseMemberAccess(null, _it);
Expand Down Expand Up @@ -1682,10 +1718,9 @@ Expression ParseMemberAccess(Type type, Expression expression)
}
}

if (type.GetTypeInfo().IsEnum)
var @enum = TypeHelper.ParseEnum(id, type);
if (@enum != null)
{
var @enum = Enum.Parse(type, id, true);

return Expression.Constant(@enum);
}

Expand Down Expand Up @@ -1722,33 +1757,85 @@ Expression ParseMemberAccess(Type type, Expression expression)
return _expressionHelper.ConvertToExpandoObjectAndCreateDynamicExpression(expression, type, id);
}
#endif

// Parse as Lambda
if (_textParser.CurrentToken.Id == TokenId.Lambda && _it.Type == type)
{
// This might be an internal variable for use within a lambda expression, so store it as such
_internals.Add(id, _it);
string _previousItName = ItName;
return ParseAsLambda(id);
}

// This could be enum like "A.B.C.MyEnum.Value1" or "A.B.C+MyEnum.Value1"
if (_textParser.CurrentToken.Id == TokenId.Dot || _textParser.CurrentToken.Id == TokenId.Plus)
{
return ParseAsEnum(id);
}

throw ParseError(errorPos, Res.UnknownPropertyOrField, id, TypeHelper.GetTypeName(type));
}

private Expression ParseAsLambda(string id)
{
// This might be an internal variable for use within a lambda expression, so store it as such
_internals.Add(id, _it);
string _previousItName = ItName;

// Also store ItName (only once)
if (string.Equals(ItName, KeywordsHelper.KEYWORD_IT))
{
ItName = id;
}

// next
_textParser.NextToken();

LastLambdaItName = ItName;
var exp = ParseConditionalOperator();

// Also store ItName (only once)
if (string.Equals(ItName, KeywordsHelper.KEYWORD_IT))
// Restore previous context and clear internals
_internals.Remove(id);
ItName = _previousItName;

return exp;
}

private Expression ParseAsEnum(string id)
{
var parts = new List<string> { id };

while (_textParser.CurrentToken.Id == TokenId.Dot || _textParser.CurrentToken.Id == TokenId.Plus)
{
if (_textParser.CurrentToken.Id == TokenId.Dot || _textParser.CurrentToken.Id == TokenId.Plus)
{
ItName = id;
parts.Add(_textParser.CurrentToken.Text);
_textParser.NextToken();
}

// next
_textParser.NextToken();
if (_textParser.CurrentToken.Id == TokenId.Identifier)
{
parts.Add(_textParser.CurrentToken.Text);
_textParser.NextToken();
}
}

LastLambdaItName = ItName;
var exp = ParseConditionalOperator();
var enumTypeAsString = string.Join("", parts.Take(parts.Count - 2).ToArray());
var enumType = _typeFinder.FindTypeByName(enumTypeAsString, null, true);
if (enumType == null)
{
throw ParseError(_textParser.CurrentToken.Pos, Res.EnumTypeNotFound, enumTypeAsString);
}

// Restore previous context and clear internals
_internals.Remove(id);
ItName = _previousItName;
string enumValueAsString = parts.LastOrDefault();
if (enumValueAsString == null)
{
throw ParseError(_textParser.CurrentToken.Pos, Res.EnumValueExpected);
}

return exp;
var enumValue = TypeHelper.ParseEnum(enumValueAsString, enumType);
if (enumValue == null)
{
throw ParseError(_textParser.CurrentToken.Pos, Res.EnumValueNotDefined, enumValueAsString, enumTypeAsString);
}

throw ParseError(errorPos, Res.UnknownPropertyOrField, id, TypeHelper.GetTypeName(type));
return Expression.Constant(enumValue);
}

Expression ParseEnumerable(Expression instance, Type elementType, string methodName, int errorPos, Type type)
Expand Down
3 changes: 3 additions & 0 deletions src/System.Linq.Dynamic.Core/Res.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ internal static class Res
public const string DotOrOpenParenOrStringLiteralExpected = "'.' or '(' or string literal expected";
public const string DynamicExpandoObjectIsNotSupported = "Dynamic / ExpandoObject is not supported in .NET 3.5, UAP and .NETStandard 1.3";
public const string DuplicateIdentifier = "The identifier '{0}' was defined more than once";
public const string EnumTypeNotFound = "Enum type '{0}' not found";
public const string EnumValueExpected = "Enum value expected";
public const string EnumValueNotDefined = "Enum value '{0}' is not defined in enum type '{1}'";
public const string ExpressionExpected = "Expression expected";
public const string ExpressionTypeMismatch = "Expression of type '{0}' expected";
public const string FirstExprMustBeBool = "The first expression must be of type 'Boolean'";
Expand Down
Loading