2013-02-16 05:30:47 +08:00
/ *
* [ The "BSD license" ]
* Copyright ( c ) 2013 Terence Parr
* Copyright ( c ) 2013 Sam Harwell
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
*
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* /
using System ;
using System.Collections ;
using System.Collections.Generic ;
using Antlr4.Runtime ;
using Antlr4.Runtime.Atn ;
using Antlr4.Runtime.Misc ;
using Javax.Annotation.Processing ;
using Javax.Lang.Model.Element ;
using Javax.Lang.Model.Type ;
using Javax.Tools ;
using Sharpen ;
using Sharpen.Annotation ;
namespace Antlr4.Runtime.Misc
{
2013-02-16 22:14:20 +08:00
/// <summary>A compile-time validator for rule dependencies.</summary>
/// <remarks>A compile-time validator for rule dependencies.</remarks>
/// <seealso cref="Antlr4.Runtime.RuleDependency">Antlr4.Runtime.RuleDependency</seealso>
/// <seealso cref="Antlr4.Runtime.RuleDependencies">Antlr4.Runtime.RuleDependencies</seealso>
/// <author>Sam Harwell</author>
public class RuleDependencyProcessor : AbstractProcessor
{
public static readonly string RuleDependencyClassName = "org.antlr.v4.runtime.RuleDependency" ;
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
public static readonly string RuleDependenciesClassName = "org.antlr.v4.runtime.RuleDependencies" ;
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
public static readonly string RuleVersionClassName = "org.antlr.v4.runtime.RuleVersion" ;
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
public RuleDependencyProcessor ( )
{
}
2013-02-16 05:30:47 +08:00
2013-02-17 04:34:47 +08:00
public override bool Process < _T0 > ( ISet < _T0 > annotations , IRoundEnvironment roundEnv
)
2013-02-16 22:14:20 +08:00
{
if ( ! CheckClassNameConstants ( ) )
{
return true ;
}
IList < Tuple < RuleDependency , IElement > > dependencies = GetDependencies ( roundEnv ) ;
IDictionary < ITypeMirror , IList < Tuple < RuleDependency , IElement > > > recognizerDependencies
= new Dictionary < ITypeMirror , IList < Tuple < RuleDependency , IElement > > > ( ) ;
foreach ( Tuple < RuleDependency , IElement > dependency in dependencies )
{
2013-02-17 04:34:47 +08:00
ITypeMirror recognizerType = GetRecognizerType ( dependency . Item1 ) ;
2013-02-16 22:14:20 +08:00
IList < Tuple < RuleDependency , IElement > > list = recognizerDependencies . Get ( recognizerType
) ;
if ( list = = null )
{
list = new List < Tuple < RuleDependency , IElement > > ( ) ;
recognizerDependencies . Put ( recognizerType , list ) ;
}
list . AddItem ( dependency ) ;
}
foreach ( KeyValuePair < ITypeMirror , IList < Tuple < RuleDependency , IElement > > > entry in
recognizerDependencies . EntrySet ( ) )
{
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Note , string . Format ( "ANTLR 4: Validating %d dependencies on rules in %s."
, entry . Value . Count , entry . Key . ToString ( ) ) ) ;
CheckDependencies ( entry . Value , entry . Key ) ;
}
return true ;
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
private bool CheckClassNameConstants ( )
{
bool success = CheckClassNameConstant ( RuleDependencyClassName , typeof ( RuleDependency
) ) ;
success & = CheckClassNameConstant ( RuleDependenciesClassName , typeof ( RuleDependencies
) ) ;
success & = CheckClassNameConstant ( RuleVersionClassName , typeof ( RuleVersion ) ) ;
return success ;
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
private bool CheckClassNameConstant < _T0 > ( string className , System . Type < _T0 > clazz
)
{
Args . NotNull ( "className" , className ) ;
Args . NotNull ( "clazz" , clazz ) ;
if ( ! className . Equals ( clazz . GetCanonicalName ( ) ) )
{
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Error , string . Format ( "Unable to process rule dependencies due to class name mismatch: %s != %s"
, className , clazz . GetCanonicalName ( ) ) ) ;
return false ;
}
return true ;
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
private static ITypeMirror GetRecognizerType ( RuleDependency dependency )
{
try
{
dependency . Recognizer ( ) ;
string message = string . Format ( "Expected %s to get the %s." , typeof ( MirroredTypeException
) . Name , typeof ( ITypeMirror ) . Name ) ;
throw new NotSupportedException ( message ) ;
}
catch ( MirroredTypeException ex )
{
return ex . GetTypeMirror ( ) ;
}
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
private void CheckDependencies ( IList < Tuple < RuleDependency , IElement > > dependencies
, ITypeMirror recognizerType )
{
string [ ] ruleNames = GetRuleNames ( recognizerType ) ;
int [ ] ruleVersions = GetRuleVersions ( recognizerType , ruleNames ) ;
RuleDependencyProcessor . RuleRelations relations = ExtractRuleRelations ( recognizerType
) ;
foreach ( Tuple < RuleDependency , IElement > dependency in dependencies )
{
try
{
2013-02-17 04:34:47 +08:00
if ( ! processingEnv . GetTypeUtils ( ) . IsAssignable ( GetRecognizerType ( dependency . Item1
) , recognizerType ) )
2013-02-16 22:14:20 +08:00
{
continue ;
}
// this is the rule in the dependency set with the highest version number
2013-02-17 04:34:47 +08:00
int effectiveRule = dependency . Item1 . Rule ( ) ;
2013-02-16 22:14:20 +08:00
if ( effectiveRule < 0 | | effectiveRule > = ruleVersions . Length )
{
Tuple < IAnnotationMirror , IAnnotationValue > ruleReferenceElement = FindRuleDependencyProperty
( dependency , RuleDependencyProcessor . RuleDependencyProperty . Rule ) ;
string message = string . Format ( "Rule dependency on unknown rule %d@%d in %s" , dependency
2013-02-17 04:34:47 +08:00
. Item1 . Rule ( ) , dependency . Item1 . Version ( ) , GetRecognizerType ( dependency . Item1
) . ToString ( ) ) ;
2013-02-16 22:14:20 +08:00
if ( ruleReferenceElement ! = null )
{
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Error , message , dependency
2013-02-17 04:34:47 +08:00
. Item2 , ruleReferenceElement . Item1 , ruleReferenceElement . Item2 ) ;
2013-02-16 22:14:20 +08:00
}
else
{
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Error , message , dependency
2013-02-17 04:34:47 +08:00
. Item2 ) ;
2013-02-16 22:14:20 +08:00
}
continue ;
}
2013-02-17 04:34:47 +08:00
EnumSet < Dependents > dependents = EnumSet . Of ( Dependents . Self , dependency . Item1 . Dependents
( ) ) ;
2013-02-16 22:14:20 +08:00
ReportUnimplementedDependents ( dependency , dependents ) ;
2013-02-16 23:47:31 +08:00
BitArray checked = new BitArray ( ) ;
2013-02-16 22:14:20 +08:00
int highestRequiredDependency = CheckDependencyVersion ( dependency , ruleNames , ruleVersions
, effectiveRule , null ) ;
if ( dependents . Contains ( Dependents . Parents ) )
{
2013-02-17 04:34:47 +08:00
BitArray parents = relations . parents [ dependency . Item1 . Rule ( ) ] ;
2013-02-16 22:14:20 +08:00
for ( int parent = parents . NextSetBit ( 0 ) ; parent > = 0 ; parent = parents . NextSetBit
( parent + 1 ) )
{
if ( parent < 0 | | parent > = ruleVersions . Length | | checked . Get ( parent ) )
{
continue ;
}
checked . Set ( parent ) ;
int required = CheckDependencyVersion ( dependency , ruleNames , ruleVersions , parent
, "parent" ) ;
highestRequiredDependency = Math . Max ( highestRequiredDependency , required ) ;
}
}
if ( dependents . Contains ( Dependents . Children ) )
{
2013-02-17 04:34:47 +08:00
BitArray children = relations . children [ dependency . Item1 . Rule ( ) ] ;
2013-02-16 22:14:20 +08:00
for ( int child = children . NextSetBit ( 0 ) ; child > = 0 ; child = children . NextSetBit (
child + 1 ) )
{
if ( child < 0 | | child > = ruleVersions . Length | | checked . Get ( child ) )
{
continue ;
}
checked . Set ( child ) ;
int required = CheckDependencyVersion ( dependency , ruleNames , ruleVersions , child ,
"child" ) ;
highestRequiredDependency = Math . Max ( highestRequiredDependency , required ) ;
}
}
if ( dependents . Contains ( Dependents . Ancestors ) )
{
2013-02-17 04:34:47 +08:00
BitArray ancestors = relations . GetAncestors ( dependency . Item1 . Rule ( ) ) ;
2013-02-16 22:14:20 +08:00
for ( int ancestor = ancestors . NextSetBit ( 0 ) ; ancestor > = 0 ; ancestor = ancestors .
NextSetBit ( ancestor + 1 ) )
{
if ( ancestor < 0 | | ancestor > = ruleVersions . Length | | checked . Get ( ancestor ) )
{
continue ;
}
checked . Set ( ancestor ) ;
int required = CheckDependencyVersion ( dependency , ruleNames , ruleVersions , ancestor
, "ancestor" ) ;
highestRequiredDependency = Math . Max ( highestRequiredDependency , required ) ;
}
}
if ( dependents . Contains ( Dependents . Descendants ) )
{
2013-02-17 04:34:47 +08:00
BitArray descendants = relations . GetDescendants ( dependency . Item1 . Rule ( ) ) ;
2013-02-16 22:14:20 +08:00
for ( int descendant = descendants . NextSetBit ( 0 ) ; descendant > = 0 ; descendant = descendants
. NextSetBit ( descendant + 1 ) )
{
if ( descendant < 0 | | descendant > = ruleVersions . Length | | checked . Get ( descendant
) )
{
continue ;
}
checked . Set ( descendant ) ;
int required = CheckDependencyVersion ( dependency , ruleNames , ruleVersions , descendant
, "descendant" ) ;
highestRequiredDependency = Math . Max ( highestRequiredDependency , required ) ;
}
}
2013-02-17 04:34:47 +08:00
int declaredVersion = dependency . Item1 . Version ( ) ;
2013-02-16 22:14:20 +08:00
if ( declaredVersion > highestRequiredDependency )
{
Tuple < IAnnotationMirror , IAnnotationValue > versionElement = FindRuleDependencyProperty
( dependency , RuleDependencyProcessor . RuleDependencyProperty . Version ) ;
string message = string . Format ( "Rule dependency version mismatch: %s has maximum dependency version %d (expected %d) in %s"
2013-02-17 04:34:47 +08:00
, ruleNames [ dependency . Item1 . Rule ( ) ] , highestRequiredDependency , declaredVersion
, GetRecognizerType ( dependency . Item1 ) . ToString ( ) ) ;
2013-02-16 22:14:20 +08:00
if ( versionElement ! = null )
{
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Error , message , dependency
2013-02-17 04:34:47 +08:00
. Item2 , versionElement . Item1 , versionElement . Item2 ) ;
2013-02-16 22:14:20 +08:00
}
else
{
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Error , message , dependency
2013-02-17 04:34:47 +08:00
. Item2 ) ;
2013-02-16 22:14:20 +08:00
}
}
}
catch ( AnnotationTypeMismatchException )
{
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Warning , string . Format ( "Could not validate rule dependencies for element %s"
2013-02-17 04:34:47 +08:00
, dependency . Item2 . ToString ( ) ) , dependency . Item2 ) ;
2013-02-16 22:14:20 +08:00
}
}
}
2013-02-16 05:30:47 +08:00
2013-02-17 04:34:47 +08:00
private static readonly ISet < Dependents > ImplementedDependents = EnumSet . Of ( Dependents
. Self , Dependents . Parents , Dependents . Children , Dependents . Ancestors , Dependents
. Descendants ) ;
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
private void ReportUnimplementedDependents ( Tuple < RuleDependency , IElement > dependency
, EnumSet < Dependents > dependents )
{
EnumSet < Dependents > unimplemented = dependents . Clone ( ) ;
unimplemented . RemoveAll ( ImplementedDependents ) ;
if ( ! unimplemented . IsEmpty ( ) )
{
Tuple < IAnnotationMirror , IAnnotationValue > dependentsElement = FindRuleDependencyProperty
( dependency , RuleDependencyProcessor . RuleDependencyProperty . Dependents ) ;
if ( dependentsElement = = null )
{
dependentsElement = FindRuleDependencyProperty ( dependency , RuleDependencyProcessor . RuleDependencyProperty
. Rule ) ;
}
string message = string . Format ( "Cannot validate the following dependents of rule %d: %s"
2013-02-17 04:34:47 +08:00
, dependency . Item1 . Rule ( ) , unimplemented ) ;
2013-02-16 22:14:20 +08:00
if ( dependentsElement ! = null )
{
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Warning , message , dependency
2013-02-17 04:34:47 +08:00
. Item2 , dependentsElement . Item1 , dependentsElement . Item2 ) ;
2013-02-16 22:14:20 +08:00
}
else
{
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Warning , message , dependency
2013-02-17 04:34:47 +08:00
. Item2 ) ;
2013-02-16 22:14:20 +08:00
}
}
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
private int CheckDependencyVersion ( Tuple < RuleDependency , IElement > dependency , string
[] ruleNames , int [ ] ruleVersions , int relatedRule , string relation )
{
2013-02-17 04:34:47 +08:00
string ruleName = ruleNames [ dependency . Item1 . Rule ( ) ] ;
2013-02-16 22:14:20 +08:00
string path ;
if ( relation = = null )
{
path = ruleName ;
}
else
{
string mismatchedRuleName = ruleNames [ relatedRule ] ;
path = string . Format ( "rule %s (%s of %s)" , mismatchedRuleName , relation , ruleName
) ;
}
2013-02-17 04:34:47 +08:00
int declaredVersion = dependency . Item1 . Version ( ) ;
2013-02-16 22:14:20 +08:00
int actualVersion = ruleVersions [ relatedRule ] ;
if ( actualVersion > declaredVersion )
{
Tuple < IAnnotationMirror , IAnnotationValue > versionElement = FindRuleDependencyProperty
( dependency , RuleDependencyProcessor . RuleDependencyProperty . Version ) ;
string message = string . Format ( "Rule dependency version mismatch: %s has version %d (expected <= %d) in %s"
2013-02-17 04:34:47 +08:00
, path , actualVersion , declaredVersion , GetRecognizerType ( dependency . Item1 ) . ToString
( ) ) ;
2013-02-16 22:14:20 +08:00
if ( versionElement ! = null )
{
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Error , message , dependency
2013-02-17 04:34:47 +08:00
. Item2 , versionElement . Item1 , versionElement . Item2 ) ;
2013-02-16 22:14:20 +08:00
}
else
{
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Error , message , dependency
2013-02-17 04:34:47 +08:00
. Item2 ) ;
2013-02-16 22:14:20 +08:00
}
}
return actualVersion ;
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
private int [ ] GetRuleVersions ( ITypeMirror recognizerClass , string [ ] ruleNames )
{
int [ ] versions = new int [ ruleNames . Length ] ;
IList < IElement > elements = processingEnv . GetElementUtils ( ) . GetAllMembers ( ( ITypeElement
) processingEnv . GetTypeUtils ( ) . AsElement ( recognizerClass ) ) ;
foreach ( IElement element in elements )
{
if ( element . GetKind ( ) ! = ElementKind . Field )
{
continue ;
}
IVariableElement field = ( IVariableElement ) element ;
bool isStatic = element . GetModifiers ( ) . Contains ( Modifier . Static ) ;
object constantValue = field . GetConstantValue ( ) ;
bool isInteger = constantValue is int ;
string name = field . GetSimpleName ( ) . ToString ( ) ;
if ( isStatic & & isInteger & & name . StartsWith ( "RULE_" ) )
{
try
{
name = Sharpen . Runtime . Substring ( name , "RULE_" . Length ) ;
if ( name . IsEmpty ( ) | | ! System . Char . IsLower ( name [ 0 ] ) )
{
continue ;
}
int index = ( int ) constantValue ;
if ( index < 0 | | index > = versions . Length )
{
string message = string . Format ( "Rule index %d for rule '%s' out of bounds for recognizer %s."
, index , name , recognizerClass . ToString ( ) ) ;
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Error , message , element ) ;
continue ;
}
if ( name . IndexOf ( ATNSimulator . RuleVariantDelimiter ) > = 0 )
{
// ignore left-factored pseudo-rules
continue ;
}
IExecutableElement ruleMethod = GetRuleMethod ( recognizerClass , name ) ;
if ( ruleMethod = = null )
{
string message = string . Format ( "Could not find rule method for rule '%s' in recognizer %s."
, name , recognizerClass . ToString ( ) ) ;
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Error , message , element ) ;
continue ;
}
RuleVersion ruleVersion = ruleMethod . GetAnnotation < RuleVersion > ( ) ;
int version = ruleVersion ! = null ? ruleVersion . Value ( ) : 0 ;
versions [ index ] = version ;
}
catch ( ArgumentException )
{
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Error , "Exception occurred while validating rule dependencies."
, element ) ;
}
}
}
return versions ;
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
private IExecutableElement GetRuleMethod ( ITypeMirror recognizerClass , string name
)
{
IList < IElement > elements = processingEnv . GetElementUtils ( ) . GetAllMembers ( ( ITypeElement
) processingEnv . GetTypeUtils ( ) . AsElement ( recognizerClass ) ) ;
foreach ( IElement element in elements )
{
if ( element . GetKind ( ) ! = ElementKind . Method )
{
continue ;
}
IExecutableElement method = ( IExecutableElement ) element ;
if ( method . GetSimpleName ( ) . ContentEquals ( name ) & & HasRuleVersionAnnotation ( method
) )
{
return method ;
}
}
return null ;
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
private bool HasRuleVersionAnnotation ( IExecutableElement method )
{
ITypeElement ruleVersionAnnotationElement = processingEnv . GetElementUtils ( ) . GetTypeElement
( RuleVersionClassName ) ;
if ( ruleVersionAnnotationElement = = null )
{
return false ;
}
foreach ( IAnnotationMirror annotation in method . GetAnnotationMirrors ( ) )
{
if ( processingEnv . GetTypeUtils ( ) . IsSameType ( annotation . GetAnnotationType ( ) , ruleVersionAnnotationElement
. AsType ( ) ) )
{
return true ;
}
}
return false ;
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
private string [ ] GetRuleNames ( ITypeMirror recognizerClass )
{
IList < string > result = new List < string > ( ) ;
IList < IElement > elements = processingEnv . GetElementUtils ( ) . GetAllMembers ( ( ITypeElement
) processingEnv . GetTypeUtils ( ) . AsElement ( recognizerClass ) ) ;
foreach ( IElement element in elements )
{
if ( element . GetKind ( ) ! = ElementKind . Field )
{
continue ;
}
IVariableElement field = ( IVariableElement ) element ;
bool isStatic = element . GetModifiers ( ) . Contains ( Modifier . Static ) ;
object constantValue = field . GetConstantValue ( ) ;
bool isInteger = constantValue is int ;
string name = field . GetSimpleName ( ) . ToString ( ) ;
if ( isStatic & & isInteger & & name . StartsWith ( "RULE_" ) )
{
try
{
name = Sharpen . Runtime . Substring ( name , "RULE_" . Length ) ;
if ( name . IsEmpty ( ) | | ! System . Char . IsLower ( name [ 0 ] ) )
{
continue ;
}
int index = ( int ) constantValue ;
if ( index < 0 )
{
continue ;
}
while ( result . Count < = index )
{
result . AddItem ( string . Empty ) ;
}
result . Set ( index , name ) ;
}
catch ( ArgumentException )
{
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Error , "Exception occurred while validating rule dependencies."
, element ) ;
}
}
}
return Sharpen . Collections . ToArray ( result , new string [ result . Count ] ) ;
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
public static IList < Tuple < RuleDependency , IElement > > GetDependencies ( IRoundEnvironment
roundEnv )
{
IList < Tuple < RuleDependency , IElement > > result = new List < Tuple < RuleDependency , IElement
> > ( ) ;
2013-02-17 04:34:47 +08:00
ISet < IElement > elements = roundEnv . GetElementsAnnotatedWith ( typeof ( RuleDependency
2013-02-16 22:14:20 +08:00
) ) ;
foreach ( IElement element in elements )
{
RuleDependency dependency = element . GetAnnotation < RuleDependency > ( ) ;
if ( dependency = = null )
{
continue ;
}
result . AddItem ( Tuple . Create ( dependency , element ) ) ;
}
elements = roundEnv . GetElementsAnnotatedWith ( typeof ( RuleDependencies ) ) ;
foreach ( IElement element_1 in elements )
{
RuleDependencies dependencies = element_1 . GetAnnotation < RuleDependencies > ( ) ;
if ( dependencies = = null | | dependencies . Value ( ) = = null )
{
continue ;
}
foreach ( RuleDependency dependency in dependencies . Value ( ) )
{
result . AddItem ( Tuple . Create ( dependency , element_1 ) ) ;
}
}
return result ;
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
public enum RuleDependencyProperty
{
Recognizer ,
Rule ,
Version ,
Dependents
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
[Nullable]
private Tuple < IAnnotationMirror , IAnnotationValue > FindRuleDependencyProperty ( Tuple
< RuleDependency , IElement > dependency , RuleDependencyProcessor . RuleDependencyProperty
property )
{
ITypeElement ruleDependencyTypeElement = processingEnv . GetElementUtils ( ) . GetTypeElement
( RuleDependencyClassName ) ;
ITypeElement ruleDependenciesTypeElement = processingEnv . GetElementUtils ( ) . GetTypeElement
( RuleDependenciesClassName ) ;
2013-02-17 04:34:47 +08:00
IList < IAnnotationMirror > mirrors = dependency . Item2 . GetAnnotationMirrors ( ) ;
2013-02-16 22:14:20 +08:00
foreach ( IAnnotationMirror annotationMirror in mirrors )
{
if ( processingEnv . GetTypeUtils ( ) . IsSameType ( ruleDependencyTypeElement . AsType ( ) , annotationMirror
. GetAnnotationType ( ) ) )
{
IAnnotationValue element = FindRuleDependencyProperty ( dependency , annotationMirror
, property ) ;
if ( element ! = null )
{
return Tuple . Create ( annotationMirror , element ) ;
}
}
else
{
if ( processingEnv . GetTypeUtils ( ) . IsSameType ( ruleDependenciesTypeElement . AsType ( ) ,
annotationMirror . GetAnnotationType ( ) ) )
{
IDictionary < IExecutableElement , IAnnotationValue > values = annotationMirror . GetElementValues
( ) ;
foreach ( KeyValuePair < IExecutableElement , IAnnotationValue > value in values . EntrySet
( ) )
{
if ( "value()" . Equals ( value . Key . ToString ( ) ) )
{
IAnnotationValue annotationValue = value . Value ;
if ( ! ( annotationValue . GetValue ( ) is IList ) )
{
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Warning , "Expected array of RuleDependency annotations for annotation property 'value()'."
2013-02-17 04:34:47 +08:00
, dependency . Item2 , annotationMirror , annotationValue ) ;
2013-02-16 22:14:20 +08:00
break ;
}
IList < object > annotationValueList = ( IList < object > ) annotationValue . GetValue ( ) ;
foreach ( object obj in annotationValueList )
{
if ( ! ( obj is IAnnotationMirror ) )
{
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Warning , "Expected RuleDependency annotation mirror for element of property 'value()'."
2013-02-17 04:34:47 +08:00
, dependency . Item2 , annotationMirror , annotationValue ) ;
2013-02-16 22:14:20 +08:00
break ;
}
IAnnotationValue element = FindRuleDependencyProperty ( dependency , ( IAnnotationMirror
) obj , property ) ;
if ( element ! = null )
{
return Tuple . Create ( ( IAnnotationMirror ) obj , element ) ;
}
}
}
else
{
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Error , string . Format ( "Unexpected annotation property %s."
2013-02-17 04:34:47 +08:00
, value . Key . ToString ( ) ) , dependency . Item2 , annotationMirror , value . Value ) ;
2013-02-16 22:14:20 +08:00
}
}
}
}
}
return null ;
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
[Nullable]
private IAnnotationValue FindRuleDependencyProperty ( Tuple < RuleDependency , IElement
> dependency , IAnnotationMirror annotationMirror , RuleDependencyProcessor . RuleDependencyProperty
property )
{
IAnnotationValue recognizerValue = null ;
IAnnotationValue ruleValue = null ;
IAnnotationValue versionValue = null ;
IAnnotationValue dependentsValue = null ;
IDictionary < IExecutableElement , IAnnotationValue > values = annotationMirror . GetElementValues
( ) ;
foreach ( KeyValuePair < IExecutableElement , IAnnotationValue > value in values . EntrySet
( ) )
{
IAnnotationValue annotationValue = value . Value ;
if ( "rule()" . Equals ( value . Key . ToString ( ) ) )
{
ruleValue = annotationValue ;
if ( ! ( annotationValue . GetValue ( ) is int ) )
{
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Warning , "Expected int constant for annotation property 'rule()'."
2013-02-17 04:34:47 +08:00
, dependency . Item2 , annotationMirror , annotationValue ) ;
2013-02-16 22:14:20 +08:00
return null ;
}
2013-02-17 04:34:47 +08:00
if ( ( int ) annotationValue . GetValue ( ) ! = dependency . Item1 . Rule ( ) )
2013-02-16 22:14:20 +08:00
{
// this is a valid dependency annotation, but not the one we're looking for
return null ;
}
}
else
{
if ( "recognizer()" . Equals ( value . Key . ToString ( ) ) )
{
recognizerValue = annotationValue ;
if ( ! ( annotationValue . GetValue ( ) is ITypeMirror ) )
{
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Warning , "Expected Class constant for annotation property 'recognizer()'."
2013-02-17 04:34:47 +08:00
, dependency . Item2 , annotationMirror , annotationValue ) ;
2013-02-16 22:14:20 +08:00
return null ;
}
ITypeMirror annotationRecognizer = ( ITypeMirror ) annotationValue . GetValue ( ) ;
2013-02-17 04:34:47 +08:00
ITypeMirror expectedRecognizer = GetRecognizerType ( dependency . Item1 ) ;
2013-02-16 22:14:20 +08:00
if ( ! processingEnv . GetTypeUtils ( ) . IsSameType ( expectedRecognizer , annotationRecognizer
) )
{
// this is a valid dependency annotation, but not the one we're looking for
return null ;
}
}
else
{
if ( "version()" . Equals ( value . Key . ToString ( ) ) )
{
versionValue = annotationValue ;
if ( ! ( annotationValue . GetValue ( ) is int ) )
{
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Warning , "Expected int constant for annotation property 'version()'."
2013-02-17 04:34:47 +08:00
, dependency . Item2 , annotationMirror , annotationValue ) ;
2013-02-16 22:14:20 +08:00
return null ;
}
2013-02-17 04:34:47 +08:00
if ( ( int ) annotationValue . GetValue ( ) ! = dependency . Item1 . Version ( ) )
2013-02-16 22:14:20 +08:00
{
// this is a valid dependency annotation, but not the one we're looking for
return null ;
}
}
}
}
}
if ( recognizerValue ! = null )
{
if ( property = = RuleDependencyProcessor . RuleDependencyProperty . Recognizer )
{
return recognizerValue ;
}
else
{
if ( ruleValue ! = null )
{
if ( property = = RuleDependencyProcessor . RuleDependencyProperty . Rule )
{
return ruleValue ;
}
else
{
if ( versionValue ! = null )
{
if ( property = = RuleDependencyProcessor . RuleDependencyProperty . Version )
{
return versionValue ;
}
else
{
if ( property = = RuleDependencyProcessor . RuleDependencyProperty . Dependents )
{
return dependentsValue ;
}
}
}
}
}
}
}
if ( recognizerValue = = null )
{
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Warning , "Could not find 'recognizer()' element in annotation."
2013-02-17 04:34:47 +08:00
, dependency . Item2 , annotationMirror ) ;
2013-02-16 22:14:20 +08:00
}
if ( property = = RuleDependencyProcessor . RuleDependencyProperty . Recognizer )
{
return null ;
}
if ( ruleValue = = null )
{
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Warning , "Could not find 'rule()' element in annotation."
2013-02-17 04:34:47 +08:00
, dependency . Item2 , annotationMirror ) ;
2013-02-16 22:14:20 +08:00
}
if ( property = = RuleDependencyProcessor . RuleDependencyProperty . Rule )
{
return null ;
}
if ( versionValue = = null )
{
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Warning , "Could not find 'version()' element in annotation."
2013-02-17 04:34:47 +08:00
, dependency . Item2 , annotationMirror ) ;
2013-02-16 22:14:20 +08:00
}
return null ;
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
private RuleDependencyProcessor . RuleRelations ExtractRuleRelations ( ITypeMirror recognizer
)
{
string serializedATN = GetSerializedATN ( recognizer ) ;
if ( serializedATN = = null )
{
return null ;
}
ATN atn = ATNSimulator . Deserialize ( serializedATN . ToCharArray ( ) ) ;
RuleDependencyProcessor . RuleRelations relations = new RuleDependencyProcessor . RuleRelations
( atn . ruleToStartState . Length ) ;
foreach ( ATNState state in atn . states )
{
if ( ! state . epsilonOnlyTransitions )
{
continue ;
}
foreach ( Transition transition in state . GetTransitions ( ) )
{
2013-02-17 04:09:40 +08:00
if ( transition . TransitionType ! = TransitionType . Rule )
2013-02-16 22:14:20 +08:00
{
continue ;
}
RuleTransition ruleTransition = ( RuleTransition ) transition ;
relations . AddRuleInvocation ( state . ruleIndex , ruleTransition . target . ruleIndex ) ;
}
}
return relations ;
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
private string GetSerializedATN ( ITypeMirror recognizerClass )
{
IList < IElement > elements = processingEnv . GetElementUtils ( ) . GetAllMembers ( ( ITypeElement
) processingEnv . GetTypeUtils ( ) . AsElement ( recognizerClass ) ) ;
foreach ( IElement element in elements )
{
if ( element . GetKind ( ) ! = ElementKind . Field )
{
continue ;
}
IVariableElement field = ( IVariableElement ) element ;
bool isStatic = element . GetModifiers ( ) . Contains ( Modifier . Static ) ;
object constantValue = field . GetConstantValue ( ) ;
bool isString = constantValue is string ;
string name = field . GetSimpleName ( ) . ToString ( ) ;
if ( isStatic & & isString & & name . Equals ( "_serializedATN" ) )
{
return ( string ) constantValue ;
}
}
processingEnv . GetMessager ( ) . PrintMessage ( Diagnostic . Kind . Error , "Could not retrieve serialized ATN from grammar."
) ;
return null ;
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
private sealed class RuleRelations
{
2013-02-16 23:47:31 +08:00
private readonly BitArray [ ] parents ;
2013-02-16 05:30:47 +08:00
2013-02-16 23:47:31 +08:00
private readonly BitArray [ ] children ;
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
public RuleRelations ( int ruleCount )
{
2013-02-16 23:47:31 +08:00
parents = new BitArray [ ruleCount ] ;
2013-02-16 22:14:20 +08:00
for ( int i = 0 ; i < ruleCount ; i + + )
{
2013-02-16 23:47:31 +08:00
parents [ i ] = new BitArray ( ) ;
2013-02-16 22:14:20 +08:00
}
2013-02-16 23:47:31 +08:00
children = new BitArray [ ruleCount ] ;
2013-02-16 22:14:20 +08:00
for ( int i_1 = 0 ; i_1 < ruleCount ; i_1 + + )
{
2013-02-16 23:47:31 +08:00
children [ i_1 ] = new BitArray ( ) ;
2013-02-16 22:14:20 +08:00
}
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
public bool AddRuleInvocation ( int caller , int callee )
{
if ( caller < 0 )
{
// tokens rule
return false ;
}
if ( children [ caller ] . Get ( callee ) )
{
// already added
return false ;
}
children [ caller ] . Set ( callee ) ;
parents [ callee ] . Set ( caller ) ;
return true ;
}
2013-02-16 05:30:47 +08:00
2013-02-16 23:47:31 +08:00
public BitArray GetAncestors ( int rule )
2013-02-16 22:14:20 +08:00
{
2013-02-16 23:47:31 +08:00
BitArray ancestors = new BitArray ( ) ;
2013-02-16 22:14:20 +08:00
ancestors . Or ( parents [ rule ] ) ;
while ( true )
{
int cardinality = ancestors . Cardinality ( ) ;
for ( int i = ancestors . NextSetBit ( 0 ) ; i > = 0 ; i = ancestors . NextSetBit ( i + 1 ) )
{
ancestors . Or ( parents [ i ] ) ;
}
if ( ancestors . Cardinality ( ) = = cardinality )
{
// nothing changed
break ;
}
}
return ancestors ;
}
2013-02-16 05:30:47 +08:00
2013-02-16 23:47:31 +08:00
public BitArray GetDescendants ( int rule )
2013-02-16 22:14:20 +08:00
{
2013-02-16 23:47:31 +08:00
BitArray descendants = new BitArray ( ) ;
2013-02-16 22:14:20 +08:00
descendants . Or ( children [ rule ] ) ;
while ( true )
{
int cardinality = descendants . Cardinality ( ) ;
for ( int i = descendants . NextSetBit ( 0 ) ; i > = 0 ; i = descendants . NextSetBit ( i + 1 ) )
{
descendants . Or ( children [ i ] ) ;
}
if ( descendants . Cardinality ( ) = = cardinality )
{
// nothing changed
break ;
}
}
return descendants ;
}
}
}
2013-02-16 05:30:47 +08:00
}