@@ -1767,24 +1767,27 @@ private bool TryGenerateConversion(Expression sourceExpression, Type destination
1767
1767
return false ;
1768
1768
}
1769
1769
1770
- private Expression ParseMemberAccess ( Type ? type , Expression ? expression )
1770
+ private Expression ParseMemberAccess ( Type ? type , Expression ? expression , string ? id = null )
1771
1771
{
1772
- var isStaticAccess = false ;
1772
+ var errorPos = _textParser . CurrentToken . Pos ;
1773
+
1774
+ // In case the expression is not null and the type is null, get the type from the expression.
1773
1775
if ( expression != null )
1774
1776
{
1775
- type = expression . Type ;
1777
+ type ?? = expression . Type ;
1776
1778
}
1777
- else
1779
+
1780
+ // In case the id is not defined, get it and move the TextParser forward.
1781
+ if ( id == null )
1778
1782
{
1779
- isStaticAccess = true ;
1783
+ id = GetIdentifier ( ) ;
1784
+ _textParser . NextToken ( ) ;
1780
1785
}
1781
1786
1782
- int errorPos = _textParser . CurrentToken . Pos ;
1783
- string id = GetIdentifier ( ) ;
1784
- _textParser . NextToken ( ) ;
1785
-
1786
1787
if ( _textParser . CurrentToken . Id == TokenId . OpenParen )
1787
1788
{
1789
+ var isStaticAccess = expression == null ;
1790
+
1788
1791
if ( ! isStaticAccess && type != typeof ( string ) )
1789
1792
{
1790
1793
var enumerableType = TypeHelper . FindGenericType ( typeof ( IEnumerable < > ) , type ) ;
@@ -1827,10 +1830,9 @@ private Expression ParseMemberAccess(Type? type, Expression? expression)
1827
1830
}
1828
1831
}
1829
1832
1830
- var @enum = TypeHelper . ParseEnum ( id , type ) ;
1831
- if ( @enum != null )
1833
+ if ( TypeHelper . TryParseEnum ( id , type , out var enumValue ) )
1832
1834
{
1833
- return Expression . Constant ( @enum ) ;
1835
+ return Expression . Constant ( enumValue ) ;
1834
1836
}
1835
1837
1836
1838
#if UAP10_0 || NETSTANDARD1_3
@@ -1839,15 +1841,9 @@ private Expression ParseMemberAccess(Type? type, Expression? expression)
1839
1841
return Expression . MakeIndex ( expression , typeof ( DynamicClass ) . GetProperty ( "Item" ) , new [ ] { Expression . Constant ( id ) } ) ;
1840
1842
}
1841
1843
#endif
1842
- MemberInfo ? member = FindPropertyOrField ( type ! , id , expression == null ) ;
1843
- if ( member is PropertyInfo property )
1844
+ if ( TryFindPropertyOrField ( type ! , id , expression , out var propertyOrFieldExpression ) )
1844
1845
{
1845
- return Expression . Property ( expression , property ) ;
1846
- }
1847
-
1848
- if ( member is FieldInfo field )
1849
- {
1850
- return Expression . Field ( expression , field ) ;
1846
+ return propertyOrFieldExpression ;
1851
1847
}
1852
1848
1853
1849
// #357 #662
@@ -1876,15 +1872,38 @@ private Expression ParseMemberAccess(Type? type, Expression? expression)
1876
1872
return ParseAsLambda ( id ) ;
1877
1873
}
1878
1874
1879
- // This could be enum like "A.B.C.MyEnum.Value1" or "A.B.C+MyEnum.Value1"
1875
+ // This could be enum like "A.B.C.MyEnum.Value1" or "A.B.C+MyEnum.Value1".
1876
+ //
1877
+ // Or it's a nested (static) class with a
1878
+ // - static property like "NestedClass.MyProperty"
1879
+ // - static method like "NestedClass.MyMethod"
1880
1880
if ( _textParser . CurrentToken . Id is TokenId . Dot or TokenId . Plus )
1881
1881
{
1882
- return ParseAsEnum ( id ) ;
1882
+ return ParseAsEnumOrNestedClass ( id ) ;
1883
1883
}
1884
1884
1885
1885
throw ParseError ( errorPos , Res . UnknownPropertyOrField , id , TypeHelper . GetTypeName ( type ) ) ;
1886
1886
}
1887
1887
1888
+ private bool TryFindPropertyOrField ( Type type , string id , Expression ? expression , [ NotNullWhen ( true ) ] out Expression ? propertyOrFieldExpression )
1889
+ {
1890
+ var member = FindPropertyOrField ( type , id , expression == null ) ;
1891
+ switch ( member )
1892
+ {
1893
+ case PropertyInfo property :
1894
+ propertyOrFieldExpression = Expression . Property ( expression , property ) ;
1895
+ return true ;
1896
+
1897
+ case FieldInfo field :
1898
+ propertyOrFieldExpression = Expression . Field ( expression , field ) ;
1899
+ return true ;
1900
+
1901
+ default :
1902
+ propertyOrFieldExpression = null ;
1903
+ return false ;
1904
+ }
1905
+ }
1906
+
1888
1907
private static Expression CallMethod ( Expression ? expression , MethodInfo methodToCall , Expression [ ] args )
1889
1908
{
1890
1909
#if NET35
@@ -1963,13 +1982,13 @@ private Expression ParseAsLambda(string id)
1963
1982
return exp ;
1964
1983
}
1965
1984
1966
- private Expression ParseAsEnum ( string id )
1985
+ private Expression ParseAsEnumOrNestedClass ( string id )
1967
1986
{
1968
1987
var parts = new List < string > { id } ;
1969
1988
1970
- while ( _textParser . CurrentToken . Id == TokenId . Dot || _textParser . CurrentToken . Id == TokenId . Plus )
1989
+ while ( _textParser . CurrentToken . Id is TokenId . Dot or TokenId . Plus )
1971
1990
{
1972
- if ( _textParser . CurrentToken . Id == TokenId . Dot || _textParser . CurrentToken . Id == TokenId . Plus )
1991
+ if ( _textParser . CurrentToken . Id is TokenId . Dot or TokenId . Plus )
1973
1992
{
1974
1993
parts . Add ( _textParser . CurrentToken . Text ) ;
1975
1994
_textParser . NextToken ( ) ;
@@ -1982,26 +2001,37 @@ private Expression ParseAsEnum(string id)
1982
2001
}
1983
2002
}
1984
2003
1985
- var enumTypeAsString = string . Concat ( parts . Take ( parts . Count - 2 ) . ToArray ( ) ) ;
1986
- var enumType = _typeFinder . FindTypeByName ( enumTypeAsString , null , true ) ;
1987
- if ( enumType == null )
2004
+ var typeAsString = string . Concat ( parts . Take ( parts . Count - 2 ) . ToArray ( ) ) ;
2005
+ var type = _typeFinder . FindTypeByName ( typeAsString , null , true ) ;
2006
+ if ( type == null )
1988
2007
{
1989
- throw ParseError ( _textParser . CurrentToken . Pos , Res . EnumTypeNotFound , enumTypeAsString ) ;
2008
+ throw ParseError ( _textParser . CurrentToken . Pos , Res . TypeNotFound , typeAsString ) ;
1990
2009
}
1991
2010
1992
- var enumValueAsString = parts . LastOrDefault ( ) ;
1993
- if ( enumValueAsString == null )
2011
+ var isEnum = TypeHelper . IsEnumType ( type ) ;
2012
+
2013
+ var identifier = parts . LastOrDefault ( ) ;
2014
+ if ( identifier == null )
1994
2015
{
1995
- throw ParseError ( _textParser . CurrentToken . Pos , Res . EnumValueExpected ) ;
2016
+ if ( isEnum )
2017
+ {
2018
+ throw ParseError ( _textParser . CurrentToken . Pos , Res . EnumTypeNotFound , typeAsString ) ;
2019
+ }
2020
+
2021
+ throw ParseError ( _textParser . CurrentToken . Pos , Res . UnknownIdentifier , typeAsString ) ;
1996
2022
}
1997
2023
1998
- var enumValue = TypeHelper . ParseEnum ( enumValueAsString , enumType ) ;
1999
- if ( enumValue == null )
2024
+ if ( isEnum )
2000
2025
{
2001
- throw ParseError ( _textParser . CurrentToken . Pos , Res . EnumValueNotDefined , enumValueAsString , enumTypeAsString ) ;
2026
+ if ( TypeHelper . TryParseEnum ( identifier , type , out var enumValue ) )
2027
+ {
2028
+ return Expression . Constant ( enumValue ) ;
2029
+ }
2030
+
2031
+ throw ParseError ( _textParser . CurrentToken . Pos , Res . EnumValueNotDefined , identifier , typeAsString ) ;
2002
2032
}
2003
2033
2004
- return Expression . Constant ( enumValue ) ;
2034
+ return ParseMemberAccess ( type , null , identifier ) ;
2005
2035
}
2006
2036
2007
2037
private Expression ParseEnumerable ( Expression instance , Type elementType , string methodName , int errorPos , Type ? type )
@@ -2301,8 +2331,10 @@ private void CheckAndPromoteOperand(Type signatures, string opName, ref Expressi
2301
2331
case TokenId . DoubleEqual :
2302
2332
case TokenId . Equal :
2303
2333
return "op_Equality" ;
2334
+
2304
2335
case TokenId . ExclamationEqual :
2305
2336
return "op_Inequality" ;
2337
+
2306
2338
default :
2307
2339
return null ;
2308
2340
}
0 commit comments