@@ -1767,24 +1767,27 @@ private bool TryGenerateConversion(Expression sourceExpression, Type destination
17671767 return false ;
17681768 }
17691769
1770- private Expression ParseMemberAccess ( Type ? type , Expression ? expression )
1770+ private Expression ParseMemberAccess ( Type ? type , Expression ? expression , string ? id = null )
17711771 {
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.
17731775 if ( expression != null )
17741776 {
1775- type = expression . Type ;
1777+ type ?? = expression . Type ;
17761778 }
1777- else
1779+
1780+ // In case the id is not defined, get it and move the TextParser forward.
1781+ if ( id == null )
17781782 {
1779- isStaticAccess = true ;
1783+ id = GetIdentifier ( ) ;
1784+ _textParser . NextToken ( ) ;
17801785 }
17811786
1782- int errorPos = _textParser . CurrentToken . Pos ;
1783- string id = GetIdentifier ( ) ;
1784- _textParser . NextToken ( ) ;
1785-
17861787 if ( _textParser . CurrentToken . Id == TokenId . OpenParen )
17871788 {
1789+ var isStaticAccess = expression == null ;
1790+
17881791 if ( ! isStaticAccess && type != typeof ( string ) )
17891792 {
17901793 var enumerableType = TypeHelper . FindGenericType ( typeof ( IEnumerable < > ) , type ) ;
@@ -1827,10 +1830,9 @@ private Expression ParseMemberAccess(Type? type, Expression? expression)
18271830 }
18281831 }
18291832
1830- var @enum = TypeHelper . ParseEnum ( id , type ) ;
1831- if ( @enum != null )
1833+ if ( TypeHelper . TryParseEnum ( id , type , out var enumValue ) )
18321834 {
1833- return Expression . Constant ( @enum ) ;
1835+ return Expression . Constant ( enumValue ) ;
18341836 }
18351837
18361838#if UAP10_0 || NETSTANDARD1_3
@@ -1839,15 +1841,9 @@ private Expression ParseMemberAccess(Type? type, Expression? expression)
18391841 return Expression . MakeIndex ( expression , typeof ( DynamicClass ) . GetProperty ( "Item" ) , new [ ] { Expression . Constant ( id ) } ) ;
18401842 }
18411843#endif
1842- MemberInfo ? member = FindPropertyOrField ( type ! , id , expression == null ) ;
1843- if ( member is PropertyInfo property )
1844+ if ( TryFindPropertyOrField ( type ! , id , expression , out var propertyOrFieldExpression ) )
18441845 {
1845- return Expression . Property ( expression , property ) ;
1846- }
1847-
1848- if ( member is FieldInfo field )
1849- {
1850- return Expression . Field ( expression , field ) ;
1846+ return propertyOrFieldExpression ;
18511847 }
18521848
18531849 // #357 #662
@@ -1876,15 +1872,38 @@ private Expression ParseMemberAccess(Type? type, Expression? expression)
18761872 return ParseAsLambda ( id ) ;
18771873 }
18781874
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"
18801880 if ( _textParser . CurrentToken . Id is TokenId . Dot or TokenId . Plus )
18811881 {
1882- return ParseAsEnum ( id ) ;
1882+ return ParseAsEnumOrNestedClass ( id ) ;
18831883 }
18841884
18851885 throw ParseError ( errorPos , Res . UnknownPropertyOrField , id , TypeHelper . GetTypeName ( type ) ) ;
18861886 }
18871887
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+
18881907 private static Expression CallMethod ( Expression ? expression , MethodInfo methodToCall , Expression [ ] args )
18891908 {
18901909#if NET35
@@ -1963,13 +1982,13 @@ private Expression ParseAsLambda(string id)
19631982 return exp ;
19641983 }
19651984
1966- private Expression ParseAsEnum ( string id )
1985+ private Expression ParseAsEnumOrNestedClass ( string id )
19671986 {
19681987 var parts = new List < string > { id } ;
19691988
1970- while ( _textParser . CurrentToken . Id == TokenId . Dot || _textParser . CurrentToken . Id == TokenId . Plus )
1989+ while ( _textParser . CurrentToken . Id is TokenId . Dot or TokenId . Plus )
19711990 {
1972- if ( _textParser . CurrentToken . Id == TokenId . Dot || _textParser . CurrentToken . Id == TokenId . Plus )
1991+ if ( _textParser . CurrentToken . Id is TokenId . Dot or TokenId . Plus )
19731992 {
19741993 parts . Add ( _textParser . CurrentToken . Text ) ;
19751994 _textParser . NextToken ( ) ;
@@ -1982,26 +2001,37 @@ private Expression ParseAsEnum(string id)
19822001 }
19832002 }
19842003
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 )
19882007 {
1989- throw ParseError ( _textParser . CurrentToken . Pos , Res . EnumTypeNotFound , enumTypeAsString ) ;
2008+ throw ParseError ( _textParser . CurrentToken . Pos , Res . TypeNotFound , typeAsString ) ;
19902009 }
19912010
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 )
19942015 {
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 ) ;
19962022 }
19972023
1998- var enumValue = TypeHelper . ParseEnum ( enumValueAsString , enumType ) ;
1999- if ( enumValue == null )
2024+ if ( isEnum )
20002025 {
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 ) ;
20022032 }
20032033
2004- return Expression . Constant ( enumValue ) ;
2034+ return ParseMemberAccess ( type , null , identifier ) ;
20052035 }
20062036
20072037 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
23012331 case TokenId . DoubleEqual :
23022332 case TokenId . Equal :
23032333 return "op_Equality" ;
2334+
23042335 case TokenId . ExclamationEqual :
23052336 return "op_Inequality" ;
2337+
23062338 default :
23072339 return null ;
23082340 }
0 commit comments