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.Generic ;
using System.Reflection ;
using System.Security ;
using System.Text ;
using Antlr4.Runtime ;
2013-02-26 04:37:45 +08:00
using Antlr4.Runtime.Atn ;
using Antlr4.Runtime.Misc ;
2013-02-16 05:30:47 +08:00
using Sharpen ;
using Sharpen.Annotation ;
using Sharpen.Logging ;
using Sharpen.Reflect ;
namespace Antlr4.Runtime.Misc
{
2013-02-16 22:14:20 +08:00
/// <author>Sam Harwell</author>
public class RuleDependencyChecker
{
2014-02-17 03:33:54 +08:00
private static readonly Logger Logger = Logger . GetLogger ( typeof ( Antlr4 . Runtime . Misc . RuleDependencyChecker ) . FullName ) ;
2013-02-16 05:30:47 +08:00
2013-02-28 02:56:24 +08:00
private static readonly HashSet < Type > checkedTypes = new HashSet < Type > ( ) ;
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
public static void CheckDependencies < _T0 > ( Type < _T0 > dependentClass )
{
if ( IsChecked ( dependentClass ) )
{
return ;
}
2013-02-26 04:37:45 +08:00
IList < Type > typesToCheck = GetTypesToCheck ( dependentClass ) ;
2013-02-16 22:14:20 +08:00
foreach ( Type clazz in typesToCheck )
{
if ( IsChecked ( clazz ) )
{
continue ;
}
2014-02-17 03:33:54 +08:00
IList < Tuple < RuleDependency , IAnnotatedElement > > dependencies = GetDependencies ( clazz ) ;
2013-02-16 22:14:20 +08:00
if ( dependencies . IsEmpty ( ) )
{
continue ;
}
2014-02-17 03:33:54 +08:00
IDictionary < Type , IList < Tuple < RuleDependency , IAnnotatedElement > > > recognizerDependencies = new Dictionary < Type , IList < Tuple < RuleDependency , IAnnotatedElement > > > ( ) ;
2013-02-26 04:37:45 +08:00
foreach ( Tuple < RuleDependency , IAnnotatedElement > dependency in dependencies )
{
Type recognizerType = dependency . Item1 . Recognizer ( ) ;
2014-02-17 03:33:54 +08:00
IList < Tuple < RuleDependency , IAnnotatedElement > > list = recognizerDependencies . Get ( recognizerType ) ;
2013-02-26 04:37:45 +08:00
if ( list = = null )
{
list = new List < Tuple < RuleDependency , IAnnotatedElement > > ( ) ;
recognizerDependencies . Put ( recognizerType , list ) ;
}
list . AddItem ( dependency ) ;
}
2014-02-17 03:33:54 +08:00
foreach ( KeyValuePair < Type , IList < Tuple < RuleDependency , IAnnotatedElement > > > entry in recognizerDependencies . EntrySet ( ) )
2013-02-26 04:37:45 +08:00
{
//processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, String.format("ANTLR 4: Validating %d dependencies on rules in %s.", entry.getValue().size(), entry.getKey().toString()));
CheckDependencies ( entry . Value , entry . Key ) ;
}
2013-02-17 04:34:47 +08:00
CheckDependencies ( dependencies , dependencies [ 0 ] . Item1 . Recognizer ( ) ) ;
2013-02-16 22:14:20 +08:00
}
}
2013-02-16 05:30:47 +08:00
2013-02-26 04:37:45 +08:00
private static IList < Type > GetTypesToCheck < _T0 > ( Type < _T0 > clazz )
{
2013-02-28 02:56:24 +08:00
HashSet < Type > result = new HashSet < Type > ( ) ;
2013-02-26 04:37:45 +08:00
GetTypesToCheck ( clazz , result ) ;
return new List < Type > ( result ) ;
}
2013-02-28 02:56:24 +08:00
private static void GetTypesToCheck < _T0 > ( Type < _T0 > clazz , HashSet < Type > result )
2013-02-26 04:37:45 +08:00
{
if ( ! result . AddItem ( clazz ) )
{
return ;
}
foreach ( Type declared in clazz . GetDeclaredClasses ( ) )
{
GetTypesToCheck ( declared , result ) ;
}
}
2013-02-16 22:14:20 +08:00
private static bool IsChecked < _T0 > ( Type < _T0 > clazz )
{
lock ( checkedTypes )
{
return checkedTypes . Contains ( clazz ) ;
}
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
private static void MarkChecked < _T0 > ( Type < _T0 > clazz )
{
lock ( checkedTypes )
{
checkedTypes . AddItem ( clazz ) ;
}
}
2013-02-16 05:30:47 +08:00
2014-02-17 03:33:54 +08:00
private static void CheckDependencies < _T0 > ( IList < Tuple < RuleDependency , IAnnotatedElement > > dependencies , Type < _T0 > recognizerType )
2014-02-17 03:31:35 +08:00
where _T0 : Recognizer < object , object >
2013-02-16 22:14:20 +08:00
{
2013-02-26 04:37:45 +08:00
string [ ] ruleNames = GetRuleNames ( recognizerType ) ;
int [ ] ruleVersions = GetRuleVersions ( recognizerType , ruleNames ) ;
2014-02-17 03:33:54 +08:00
RuleDependencyChecker . RuleRelations relations = ExtractRuleRelations ( recognizerType ) ;
2013-02-26 04:37:45 +08:00
StringBuilder errors = new StringBuilder ( ) ;
2013-02-16 22:14:20 +08:00
foreach ( Tuple < RuleDependency , IAnnotatedElement > dependency in dependencies )
{
2013-02-26 04:37:45 +08:00
if ( ! dependency . Item1 . Recognizer ( ) . IsAssignableFrom ( recognizerType ) )
{
continue ;
}
// this is the rule in the dependency set with the highest version number
int effectiveRule = dependency . Item1 . Rule ( ) ;
if ( effectiveRule < 0 | | effectiveRule > = ruleVersions . Length )
2013-02-16 22:14:20 +08:00
{
2014-02-17 03:33:54 +08:00
string message = string . Format ( "Rule dependency on unknown rule %d@%d in %s%n" , dependency . Item1 . Rule ( ) , dependency . Item1 . Version ( ) , dependency . Item1 . Recognizer ( ) . ToString ( ) ) ;
2013-02-26 04:37:45 +08:00
errors . Append ( message ) ;
2013-02-16 22:14:20 +08:00
continue ;
}
2014-02-17 03:33:54 +08:00
EnumSet < Dependents > dependents = EnumSet . Of ( Dependents . Self , dependency . Item1 . Dependents ( ) ) ;
2013-02-26 04:37:45 +08:00
ReportUnimplementedDependents ( errors , dependency , dependents ) ;
2013-02-26 04:38:30 +08:00
BitSet @checked = new BitSet ( ) ;
2014-02-17 03:33:54 +08:00
int highestRequiredDependency = CheckDependencyVersion ( errors , dependency , ruleNames , ruleVersions , effectiveRule , null ) ;
2013-02-26 04:37:45 +08:00
if ( dependents . Contains ( Dependents . Parents ) )
{
BitSet parents = relations . parents [ dependency . Item1 . Rule ( ) ] ;
2014-02-17 03:33:54 +08:00
for ( int parent = parents . NextSetBit ( 0 ) ; parent > = 0 ; parent = parents . NextSetBit ( parent + 1 ) )
2013-02-26 04:37:45 +08:00
{
2013-02-26 04:38:30 +08:00
if ( parent < 0 | | parent > = ruleVersions . Length | | @checked . Get ( parent ) )
2013-02-26 04:37:45 +08:00
{
continue ;
}
2013-02-26 04:38:30 +08:00
@checked . Set ( parent ) ;
2014-02-17 03:33:54 +08:00
int required = CheckDependencyVersion ( errors , dependency , ruleNames , ruleVersions , parent , "parent" ) ;
2013-02-26 04:37:45 +08:00
highestRequiredDependency = Math . Max ( highestRequiredDependency , required ) ;
}
}
if ( dependents . Contains ( Dependents . Children ) )
{
BitSet children = relations . children [ dependency . Item1 . Rule ( ) ] ;
2014-02-17 03:33:54 +08:00
for ( int child = children . NextSetBit ( 0 ) ; child > = 0 ; child = children . NextSetBit ( child + 1 ) )
2013-02-26 04:37:45 +08:00
{
2013-02-26 04:38:30 +08:00
if ( child < 0 | | child > = ruleVersions . Length | | @checked . Get ( child ) )
2013-02-26 04:37:45 +08:00
{
continue ;
}
2013-02-26 04:38:30 +08:00
@checked . Set ( child ) ;
2014-02-17 03:33:54 +08:00
int required = CheckDependencyVersion ( errors , dependency , ruleNames , ruleVersions , child , "child" ) ;
2013-02-26 04:37:45 +08:00
highestRequiredDependency = Math . Max ( highestRequiredDependency , required ) ;
}
}
if ( dependents . Contains ( Dependents . Ancestors ) )
2013-02-16 22:14:20 +08:00
{
2013-02-26 04:37:45 +08:00
BitSet ancestors = relations . GetAncestors ( dependency . Item1 . Rule ( ) ) ;
2014-02-17 03:33:54 +08:00
for ( int ancestor = ancestors . NextSetBit ( 0 ) ; ancestor > = 0 ; ancestor = ancestors . NextSetBit ( ancestor + 1 ) )
2013-02-26 04:37:45 +08:00
{
2013-02-26 04:38:30 +08:00
if ( ancestor < 0 | | ancestor > = ruleVersions . Length | | @checked . Get ( ancestor ) )
2013-02-26 04:37:45 +08:00
{
continue ;
}
2013-02-26 04:38:30 +08:00
@checked . Set ( ancestor ) ;
2014-02-17 03:33:54 +08:00
int required = CheckDependencyVersion ( errors , dependency , ruleNames , ruleVersions , ancestor , "ancestor" ) ;
2013-02-26 04:37:45 +08:00
highestRequiredDependency = Math . Max ( highestRequiredDependency , required ) ;
}
2013-02-16 22:14:20 +08:00
}
2013-02-26 04:37:45 +08:00
if ( dependents . Contains ( Dependents . Descendants ) )
2013-02-16 22:14:20 +08:00
{
2013-02-26 04:37:45 +08:00
BitSet descendants = relations . GetDescendants ( dependency . Item1 . Rule ( ) ) ;
2014-02-17 03:33:54 +08:00
for ( int descendant = descendants . NextSetBit ( 0 ) ; descendant > = 0 ; descendant = descendants . NextSetBit ( descendant + 1 ) )
2013-02-16 22:14:20 +08:00
{
2014-02-17 03:33:54 +08:00
if ( descendant < 0 | | descendant > = ruleVersions . Length | | @checked . Get ( descendant ) )
2013-02-26 04:37:45 +08:00
{
continue ;
}
2013-02-26 04:38:30 +08:00
@checked . Set ( descendant ) ;
2014-02-17 03:33:54 +08:00
int required = CheckDependencyVersion ( errors , dependency , ruleNames , ruleVersions , descendant , "descendant" ) ;
2013-02-26 04:37:45 +08:00
highestRequiredDependency = Math . Max ( highestRequiredDependency , required ) ;
2013-02-16 22:14:20 +08:00
}
}
2013-02-26 04:37:45 +08:00
int declaredVersion = dependency . Item1 . Version ( ) ;
if ( declaredVersion > highestRequiredDependency )
{
2014-02-17 03:33:54 +08:00
string message = string . Format ( "Rule dependency version mismatch: %s has maximum dependency version %d (expected %d) in %s%n" , ruleNames [ dependency . Item1 . Rule ( ) ] , highestRequiredDependency , declaredVersion , dependency . Item1 . Recognizer ( ) . ToString ( ) ) ;
2013-02-26 04:37:45 +08:00
errors . Append ( message ) ;
}
2013-02-16 22:14:20 +08:00
}
2013-02-26 04:37:45 +08:00
if ( errors . Length > 0 )
2013-02-16 22:14:20 +08:00
{
2013-02-26 04:37:45 +08:00
throw new InvalidOperationException ( errors . ToString ( ) ) ;
2013-02-16 22:14:20 +08:00
}
2013-02-26 04:37:45 +08:00
MarkChecked ( recognizerType ) ;
}
2014-02-17 03:33:54 +08:00
private static readonly HashSet < Dependents > ImplementedDependents = EnumSet . Of ( Dependents . Self , Dependents . Parents , Dependents . Children , Dependents . Ancestors , Dependents . Descendants ) ;
2013-02-26 04:37:45 +08:00
2014-02-17 03:33:54 +08:00
private static void ReportUnimplementedDependents ( StringBuilder errors , Tuple < RuleDependency , IAnnotatedElement > dependency , EnumSet < Dependents > dependents )
2013-02-26 04:37:45 +08:00
{
EnumSet < Dependents > unimplemented = dependents . Clone ( ) ;
unimplemented . RemoveAll ( ImplementedDependents ) ;
if ( ! unimplemented . IsEmpty ( ) )
{
2014-02-17 03:33:54 +08:00
string message = string . Format ( "Cannot validate the following dependents of rule %d: %s%n" , dependency . Item1 . Rule ( ) , unimplemented ) ;
2013-02-26 04:37:45 +08:00
errors . Append ( message ) ;
}
}
2014-02-17 03:33:54 +08:00
private static int CheckDependencyVersion ( StringBuilder errors , Tuple < RuleDependency , IAnnotatedElement > dependency , string [ ] ruleNames , int [ ] ruleVersions , int relatedRule , string relation )
2013-02-26 04:37:45 +08:00
{
string ruleName = ruleNames [ dependency . Item1 . Rule ( ) ] ;
string path ;
if ( relation = = null )
{
path = ruleName ;
}
else
{
string mismatchedRuleName = ruleNames [ relatedRule ] ;
2014-02-17 03:33:54 +08:00
path = string . Format ( "rule %s (%s of %s)" , mismatchedRuleName , relation , ruleName ) ;
2013-02-26 04:37:45 +08:00
}
int declaredVersion = dependency . Item1 . Version ( ) ;
int actualVersion = ruleVersions [ relatedRule ] ;
if ( actualVersion > declaredVersion )
{
2014-02-17 03:33:54 +08:00
string message = string . Format ( "Rule dependency version mismatch: %s has version %d (expected <= %d) in %s%n" , path , actualVersion , declaredVersion , dependency . Item1 . Recognizer ( ) . ToString ( ) ) ;
2013-02-26 04:37:45 +08:00
errors . Append ( message ) ;
}
return actualVersion ;
2013-02-16 22:14:20 +08:00
}
2013-02-16 05:30:47 +08:00
2014-02-17 03:33:54 +08:00
private static int [ ] GetRuleVersions < _T0 > ( Type < _T0 > recognizerClass , string [ ] ruleNames )
2014-02-17 03:31:35 +08:00
where _T0 : Recognizer < object , object >
2013-02-16 22:14:20 +08:00
{
int [ ] versions = new int [ ruleNames . Length ] ;
FieldInfo [ ] fields = recognizerClass . GetFields ( ) ;
foreach ( FieldInfo field in fields )
{
bool isStatic = ( field . GetModifiers ( ) & Modifier . Static ) ! = 0 ;
bool isInteger = field . FieldType = = typeof ( int ) ;
if ( isStatic & & isInteger & & field . Name . StartsWith ( "RULE_" ) )
{
try
{
string name = Sharpen . Runtime . Substring ( field . Name , "RULE_" . Length ) ;
if ( name . IsEmpty ( ) | | ! System . Char . IsLower ( name [ 0 ] ) )
{
continue ;
}
int index = field . GetInt ( null ) ;
if ( index < 0 | | index > = versions . Length )
{
object [ ] @params = new object [ ] { index , field . Name , recognizerClass . Name } ;
2014-02-17 03:33:54 +08:00
Logger . Log ( Level . Warning , "Rule index {0} for rule ''{1}'' out of bounds for recognizer {2}." , @params ) ;
2013-02-16 22:14:20 +08:00
continue ;
}
MethodInfo ruleMethod = GetRuleMethod ( recognizerClass , name ) ;
if ( ruleMethod = = null )
{
object [ ] @params = new object [ ] { name , recognizerClass . Name } ;
2014-02-17 03:33:54 +08:00
Logger . Log ( Level . Warning , "Could not find rule method for rule ''{0}'' in recognizer {1}." , @params ) ;
2013-02-16 22:14:20 +08:00
continue ;
}
RuleVersion ruleVersion = ruleMethod . GetAnnotation < RuleVersion > ( ) ;
int version = ruleVersion ! = null ? ruleVersion . Value ( ) : 0 ;
versions [ index ] = version ;
}
catch ( ArgumentException ex )
{
Logger . Log ( Level . Warning , null , ex ) ;
}
catch ( MemberAccessException ex )
{
Logger . Log ( Level . Warning , null , ex ) ;
}
}
}
return versions ;
}
2013-02-16 05:30:47 +08:00
2014-02-17 03:33:54 +08:00
private static MethodInfo GetRuleMethod < _T0 > ( Type < _T0 > recognizerClass , string name )
2014-02-17 03:31:35 +08:00
where _T0 : Recognizer < object , object >
2013-02-16 22:14:20 +08:00
{
MethodInfo [ ] declaredMethods = recognizerClass . GetMethods ( ) ;
foreach ( MethodInfo method in declaredMethods )
{
if ( method . Name . Equals ( name ) & & method . IsAnnotationPresent ( typeof ( RuleVersion ) ) )
{
return method ;
}
}
return null ;
}
2013-02-16 05:30:47 +08:00
2014-02-17 03:31:35 +08:00
private static string [ ] GetRuleNames < _T0 > ( Type < _T0 > recognizerClass )
where _T0 : Recognizer < object , object >
2013-02-16 22:14:20 +08:00
{
try
{
FieldInfo ruleNames = recognizerClass . GetField ( "ruleNames" ) ;
return ( string [ ] ) ruleNames . GetValue ( null ) ;
}
catch ( NoSuchFieldException ex )
{
Logger . Log ( Level . Warning , null , ex ) ;
}
catch ( SecurityException ex )
{
Logger . Log ( Level . Warning , null , ex ) ;
}
catch ( ArgumentException ex )
{
Logger . Log ( Level . Warning , null , ex ) ;
}
catch ( MemberAccessException ex )
{
Logger . Log ( Level . Warning , null , ex ) ;
}
return new string [ 0 ] ;
}
2013-02-16 05:30:47 +08:00
2014-02-17 03:33:54 +08:00
public static IList < Tuple < RuleDependency , IAnnotatedElement > > GetDependencies < _T0 > ( Type < _T0 > clazz )
2013-02-16 22:14:20 +08:00
{
2014-02-17 03:33:54 +08:00
IList < Tuple < RuleDependency , IAnnotatedElement > > result = new List < Tuple < RuleDependency , IAnnotatedElement > > ( ) ;
IList < ElementType > supportedTarget = Arrays . AsList ( typeof ( RuleDependency ) . GetAnnotation < Target > ( ) . Value ( ) ) ;
2013-02-16 22:14:20 +08:00
foreach ( ElementType target in supportedTarget )
{
switch ( target )
{
case ElementType . Type :
{
if ( ! clazz . IsAnnotation ( ) )
{
GetElementDependencies ( clazz , result ) ;
}
break ;
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
case ElementType . AnnotationType :
{
if ( ! clazz . IsAnnotation ( ) )
{
GetElementDependencies ( clazz , result ) ;
}
break ;
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
case ElementType . Constructor :
{
foreach ( Constructor < object > ctor in clazz . GetDeclaredConstructors ( ) )
{
GetElementDependencies ( ctor , result ) ;
}
break ;
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
case ElementType . Field :
{
foreach ( FieldInfo field in Sharpen . Runtime . GetDeclaredFields ( clazz ) )
{
GetElementDependencies ( field , result ) ;
}
break ;
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
case ElementType . LocalVariable :
{
2014-02-17 03:33:54 +08:00
System . Console . Error . WriteLine ( "Runtime rule dependency checking is not supported for local variables." ) ;
2013-02-16 22:14:20 +08:00
break ;
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
case ElementType . Method :
{
foreach ( MethodInfo method in Sharpen . Runtime . GetDeclaredMethods ( clazz ) )
{
GetElementDependencies ( method , result ) ;
}
break ;
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
case ElementType . Package :
{
// package is not a subset of class, so nothing to do here
break ;
}
2013-02-16 05:30:47 +08:00
2013-02-16 22:14:20 +08:00
case ElementType . Parameter :
{
2014-02-17 03:33:54 +08:00
System . Console . Error . WriteLine ( "Runtime rule dependency checking is not supported for parameters." ) ;
2013-02-16 22:14:20 +08:00
break ;
}
}
}
return result ;
}
2013-02-16 05:30:47 +08:00
2014-02-17 03:33:54 +08:00
private static void GetElementDependencies ( IAnnotatedElement annotatedElement , IList < Tuple < RuleDependency , IAnnotatedElement > > result )
2013-02-16 22:14:20 +08:00
{
RuleDependency dependency = annotatedElement . GetAnnotation < RuleDependency > ( ) ;
if ( dependency ! = null )
{
result . AddItem ( Tuple . Create ( dependency , annotatedElement ) ) ;
}
2014-02-17 03:33:54 +08:00
RuleDependencies dependencies = annotatedElement . GetAnnotation < RuleDependencies > ( ) ;
2013-02-16 22:14:20 +08:00
if ( dependencies ! = null )
{
foreach ( RuleDependency d in dependencies . Value ( ) )
{
if ( d ! = null )
{
result . AddItem ( Tuple . Create ( d , annotatedElement ) ) ;
}
}
}
}
2013-02-16 05:30:47 +08:00
2014-02-17 03:33:54 +08:00
private static RuleDependencyChecker . RuleRelations ExtractRuleRelations < _T0 > ( Type < _T0 > recognizer )
2014-02-17 03:31:35 +08:00
where _T0 : Recognizer < object , object >
2013-02-26 04:37:45 +08:00
{
string serializedATN = GetSerializedATN ( recognizer ) ;
if ( serializedATN = = null )
{
return null ;
}
ATN atn = ATNSimulator . Deserialize ( serializedATN . ToCharArray ( ) ) ;
2014-02-17 03:33:54 +08:00
RuleDependencyChecker . RuleRelations relations = new RuleDependencyChecker . RuleRelations ( atn . ruleToStartState . Length ) ;
2013-02-26 04:37:45 +08:00
foreach ( ATNState state in atn . states )
{
if ( ! state . epsilonOnlyTransitions )
{
continue ;
}
foreach ( Transition transition in state . GetTransitions ( ) )
{
if ( transition . TransitionType ! = TransitionType . Rule )
{
continue ;
}
RuleTransition ruleTransition = ( RuleTransition ) transition ;
relations . AddRuleInvocation ( state . ruleIndex , ruleTransition . target . ruleIndex ) ;
}
}
return relations ;
}
private static string GetSerializedATN < _T0 > ( Type < _T0 > recognizerClass )
{
try
{
2014-02-17 03:33:54 +08:00
FieldInfo serializedAtnField = Sharpen . Runtime . GetDeclaredField ( recognizerClass , "_serializedATN" ) ;
2013-02-26 04:37:45 +08:00
if ( Modifier . IsStatic ( serializedAtnField . GetModifiers ( ) ) )
{
return ( string ) serializedAtnField . GetValue ( null ) ;
}
return null ;
}
catch ( NoSuchFieldException )
{
if ( recognizerClass . BaseType ! = null )
{
return GetSerializedATN ( recognizerClass . BaseType ) ;
}
return null ;
}
catch ( SecurityException )
{
return null ;
}
catch ( ArgumentException )
{
return null ;
}
catch ( MemberAccessException )
{
return null ;
}
}
private sealed class RuleRelations
{
private readonly BitSet [ ] parents ;
private readonly BitSet [ ] children ;
public RuleRelations ( int ruleCount )
{
parents = new BitSet [ ruleCount ] ;
for ( int i = 0 ; i < ruleCount ; i + + )
{
parents [ i ] = new BitSet ( ) ;
}
children = new BitSet [ ruleCount ] ;
for ( int i_1 = 0 ; i_1 < ruleCount ; i_1 + + )
{
children [ i_1 ] = new BitSet ( ) ;
}
}
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 ;
}
public BitSet GetAncestors ( int rule )
{
BitSet ancestors = new BitSet ( ) ;
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 ;
}
public BitSet GetDescendants ( int rule )
{
BitSet descendants = new BitSet ( ) ;
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-26 03:23:46 +08:00
private RuleDependencyChecker ( )
2013-02-16 22:14:20 +08:00
{
}
}
2013-02-16 05:30:47 +08:00
}