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;
|
|
|
|
|
|
|
|
namespace Antlr4.Runtime.Misc
|
|
|
|
{
|
2013-02-16 22:14:20 +08:00
|
|
|
/// <author>Sam Harwell</author>
|
|
|
|
public class RuleDependencyChecker
|
|
|
|
{
|
2013-02-26 05:09:31 +08:00
|
|
|
#if false
|
2013-02-16 22:14:20 +08:00
|
|
|
private static readonly Logger Logger = Logger.GetLogger(typeof(Antlr4.Runtime.Misc.RuleDependencyChecker
|
|
|
|
).FullName);
|
2013-02-26 05:09:31 +08:00
|
|
|
#endif
|
2013-02-16 05:30:47 +08:00
|
|
|
|
2013-02-17 04:34:47 +08:00
|
|
|
private static readonly ISet<Type> checkedTypes = new HashSet<Type>();
|
2013-02-16 05:30:47 +08:00
|
|
|
|
2013-02-26 05:09:31 +08:00
|
|
|
public static void CheckDependencies(Type dependentClass)
|
2013-02-16 22:14:20 +08:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
2013-02-26 05:09:31 +08:00
|
|
|
IList<Tuple<RuleDependencyAttribute, ICustomAttributeProvider>> dependencies = GetDependencies(clazz
|
2013-02-16 22:14:20 +08:00
|
|
|
);
|
2013-02-18 10:34:36 +08:00
|
|
|
if (dependencies.Count == 0)
|
2013-02-16 22:14:20 +08:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2013-02-26 05:09:31 +08:00
|
|
|
IDictionary<Type, IList<Tuple<RuleDependencyAttribute, ICustomAttributeProvider>>> recognizerDependencies
|
|
|
|
= new Dictionary<Type, IList<Tuple<RuleDependencyAttribute, ICustomAttributeProvider>>>();
|
|
|
|
foreach (Tuple<RuleDependencyAttribute, ICustomAttributeProvider> dependency in dependencies)
|
2013-02-26 04:37:45 +08:00
|
|
|
{
|
2013-02-26 05:09:31 +08:00
|
|
|
Type recognizerType = dependency.Item1.Recognizer;
|
|
|
|
IList<Tuple<RuleDependencyAttribute, ICustomAttributeProvider>> list = recognizerDependencies.Get
|
2013-02-26 04:37:45 +08:00
|
|
|
(recognizerType);
|
|
|
|
if (list == null)
|
|
|
|
{
|
2013-02-26 05:09:31 +08:00
|
|
|
list = new List<Tuple<RuleDependencyAttribute, ICustomAttributeProvider>>();
|
2013-02-26 04:37:45 +08:00
|
|
|
recognizerDependencies.Put(recognizerType, list);
|
|
|
|
}
|
2013-02-26 05:09:31 +08:00
|
|
|
list.Add(dependency);
|
2013-02-26 04:37:45 +08:00
|
|
|
}
|
2013-02-26 05:09:31 +08:00
|
|
|
foreach (KeyValuePair<Type, IList<Tuple<RuleDependencyAttribute, ICustomAttributeProvider>>> entry
|
|
|
|
in recognizerDependencies)
|
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-26 05:09:31 +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 05:09:31 +08:00
|
|
|
private static IList<Type> GetTypesToCheck(Type clazz)
|
2013-02-26 04:37:45 +08:00
|
|
|
{
|
|
|
|
ISet<Type> result = new HashSet<Type>();
|
|
|
|
GetTypesToCheck(clazz, result);
|
|
|
|
return new List<Type>(result);
|
|
|
|
}
|
|
|
|
|
2013-02-26 05:09:31 +08:00
|
|
|
private static void GetTypesToCheck(Type clazz, ISet<Type> result)
|
2013-02-26 04:37:45 +08:00
|
|
|
{
|
2013-02-26 05:09:31 +08:00
|
|
|
if (!result.Add(clazz))
|
2013-02-26 04:37:45 +08:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2013-02-26 05:09:31 +08:00
|
|
|
foreach (Type declared in clazz.GetNestedTypes())
|
2013-02-26 04:37:45 +08:00
|
|
|
{
|
|
|
|
GetTypesToCheck(declared, result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-26 05:09:31 +08:00
|
|
|
private static bool IsChecked(Type clazz)
|
2013-02-16 22:14:20 +08:00
|
|
|
{
|
|
|
|
lock (checkedTypes)
|
|
|
|
{
|
|
|
|
return checkedTypes.Contains(clazz);
|
|
|
|
}
|
|
|
|
}
|
2013-02-16 05:30:47 +08:00
|
|
|
|
2013-02-26 05:09:31 +08:00
|
|
|
private static void MarkChecked(Type clazz)
|
2013-02-16 22:14:20 +08:00
|
|
|
{
|
|
|
|
lock (checkedTypes)
|
|
|
|
{
|
2013-02-26 05:09:31 +08:00
|
|
|
checkedTypes.Add(clazz);
|
2013-02-16 22:14:20 +08:00
|
|
|
}
|
|
|
|
}
|
2013-02-16 05:30:47 +08:00
|
|
|
|
2013-02-26 05:09:31 +08:00
|
|
|
private static void CheckDependencies(IList<Tuple<RuleDependencyAttribute, ICustomAttributeProvider
|
|
|
|
>> dependencies, Type recognizerType)
|
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);
|
|
|
|
RuleDependencyChecker.RuleRelations relations = ExtractRuleRelations(recognizerType
|
|
|
|
);
|
|
|
|
StringBuilder errors = new StringBuilder();
|
2013-02-26 05:09:31 +08:00
|
|
|
foreach (Tuple<RuleDependencyAttribute, ICustomAttributeProvider> dependency in dependencies)
|
2013-02-16 22:14:20 +08:00
|
|
|
{
|
2013-02-26 05:09:31 +08:00
|
|
|
if (!dependency.Item1.Recognizer.IsAssignableFrom(recognizerType))
|
2013-02-26 04:37:45 +08:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// this is the rule in the dependency set with the highest version number
|
2013-02-26 05:09:31 +08:00
|
|
|
int effectiveRule = dependency.Item1.Rule;
|
2013-02-26 04:37:45 +08:00
|
|
|
if (effectiveRule < 0 || effectiveRule >= ruleVersions.Length)
|
2013-02-16 22:14:20 +08:00
|
|
|
{
|
2013-02-26 04:37:45 +08:00
|
|
|
string message = string.Format("Rule dependency on unknown rule %d@%d in %s%n", dependency
|
2013-02-26 05:09:31 +08:00
|
|
|
.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;
|
|
|
|
}
|
2013-02-26 05:09:31 +08:00
|
|
|
Dependents dependents = 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();
|
2013-02-26 04:37:45 +08:00
|
|
|
int highestRequiredDependency = CheckDependencyVersion(errors, dependency, ruleNames
|
|
|
|
, ruleVersions, effectiveRule, null);
|
2013-02-26 05:09:31 +08:00
|
|
|
if (dependents.HasFlag(Dependents.Parents))
|
2013-02-26 04:37:45 +08:00
|
|
|
{
|
2013-02-26 05:09:31 +08:00
|
|
|
BitSet parents = relations.parents[dependency.Item1.Rule];
|
2013-02-26 04:37:45 +08:00
|
|
|
for (int parent = parents.NextSetBit(0); parent >= 0; parent = parents.NextSetBit
|
|
|
|
(parent + 1))
|
|
|
|
{
|
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);
|
2013-02-26 04:37:45 +08:00
|
|
|
int required = CheckDependencyVersion(errors, dependency, ruleNames, ruleVersions
|
|
|
|
, parent, "parent");
|
|
|
|
highestRequiredDependency = Math.Max(highestRequiredDependency, required);
|
|
|
|
}
|
|
|
|
}
|
2013-02-26 05:09:31 +08:00
|
|
|
if (dependents.HasFlag(Dependents.Children))
|
2013-02-26 04:37:45 +08:00
|
|
|
{
|
2013-02-26 05:09:31 +08:00
|
|
|
BitSet children = relations.children[dependency.Item1.Rule];
|
2013-02-26 04:37:45 +08:00
|
|
|
for (int child = children.NextSetBit(0); child >= 0; child = children.NextSetBit(
|
|
|
|
child + 1))
|
|
|
|
{
|
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);
|
2013-02-26 04:37:45 +08:00
|
|
|
int required = CheckDependencyVersion(errors, dependency, ruleNames, ruleVersions
|
|
|
|
, child, "child");
|
|
|
|
highestRequiredDependency = Math.Max(highestRequiredDependency, required);
|
|
|
|
}
|
|
|
|
}
|
2013-02-26 05:09:31 +08:00
|
|
|
if (dependents.HasFlag(Dependents.Ancestors))
|
2013-02-16 22:14:20 +08:00
|
|
|
{
|
2013-02-26 05:09:31 +08:00
|
|
|
BitSet ancestors = relations.GetAncestors(dependency.Item1.Rule);
|
2013-02-26 04:37:45 +08:00
|
|
|
for (int ancestor = ancestors.NextSetBit(0); ancestor >= 0; ancestor = ancestors.
|
|
|
|
NextSetBit(ancestor + 1))
|
|
|
|
{
|
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);
|
2013-02-26 04:37:45 +08:00
|
|
|
int required = CheckDependencyVersion(errors, dependency, ruleNames, ruleVersions
|
|
|
|
, ancestor, "ancestor");
|
|
|
|
highestRequiredDependency = Math.Max(highestRequiredDependency, required);
|
|
|
|
}
|
2013-02-16 22:14:20 +08:00
|
|
|
}
|
2013-02-26 05:09:31 +08:00
|
|
|
if (dependents.HasFlag(Dependents.Descendants))
|
2013-02-16 22:14:20 +08:00
|
|
|
{
|
2013-02-26 05:09:31 +08:00
|
|
|
BitSet descendants = relations.GetDescendants(dependency.Item1.Rule);
|
2013-02-26 04:37:45 +08:00
|
|
|
for (int descendant = descendants.NextSetBit(0); descendant >= 0; descendant = descendants
|
|
|
|
.NextSetBit(descendant + 1))
|
2013-02-16 22:14:20 +08:00
|
|
|
{
|
2013-02-26 04:38:30 +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);
|
2013-02-26 04:37:45 +08:00
|
|
|
int required = CheckDependencyVersion(errors, dependency, ruleNames, ruleVersions
|
|
|
|
, descendant, "descendant");
|
|
|
|
highestRequiredDependency = Math.Max(highestRequiredDependency, required);
|
2013-02-16 22:14:20 +08:00
|
|
|
}
|
|
|
|
}
|
2013-02-26 05:09:31 +08:00
|
|
|
int declaredVersion = dependency.Item1.Version;
|
2013-02-26 04:37:45 +08:00
|
|
|
if (declaredVersion > highestRequiredDependency)
|
|
|
|
{
|
|
|
|
string message = string.Format("Rule dependency version mismatch: %s has maximum dependency version %d (expected %d) in %s%n"
|
2013-02-26 05:09:31 +08:00
|
|
|
, 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);
|
|
|
|
}
|
|
|
|
|
2013-02-26 05:09:31 +08:00
|
|
|
private static readonly Dependents ImplementedDependents = Dependents
|
|
|
|
.Self | Dependents.Parents | Dependents.Children | Dependents.Ancestors | Dependents
|
|
|
|
.Descendants;
|
2013-02-26 04:37:45 +08:00
|
|
|
|
2013-02-26 05:09:31 +08:00
|
|
|
private static void ReportUnimplementedDependents(StringBuilder errors, Tuple<RuleDependencyAttribute
|
|
|
|
, ICustomAttributeProvider> dependency, Dependents dependents)
|
2013-02-26 04:37:45 +08:00
|
|
|
{
|
2013-02-26 05:09:31 +08:00
|
|
|
Dependents unimplemented = dependents;
|
|
|
|
unimplemented &= ~ImplementedDependents;
|
|
|
|
if (unimplemented != Dependents.None)
|
2013-02-26 04:37:45 +08:00
|
|
|
{
|
|
|
|
string message = string.Format("Cannot validate the following dependents of rule %d: %s%n"
|
2013-02-26 05:09:31 +08:00
|
|
|
, dependency.Item1.Rule, unimplemented);
|
2013-02-26 04:37:45 +08:00
|
|
|
errors.Append(message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-26 05:09:31 +08:00
|
|
|
private static int CheckDependencyVersion(StringBuilder errors, Tuple<RuleDependencyAttribute
|
|
|
|
, ICustomAttributeProvider> dependency, string[] ruleNames, int[] ruleVersions, int
|
2013-02-26 04:37:45 +08:00
|
|
|
relatedRule, string relation)
|
|
|
|
{
|
2013-02-26 05:09:31 +08:00
|
|
|
string ruleName = ruleNames[dependency.Item1.Rule];
|
2013-02-26 04:37:45 +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-26 05:09:31 +08:00
|
|
|
int declaredVersion = dependency.Item1.Version;
|
2013-02-26 04:37:45 +08:00
|
|
|
int actualVersion = ruleVersions[relatedRule];
|
|
|
|
if (actualVersion > declaredVersion)
|
|
|
|
{
|
|
|
|
string message = string.Format("Rule dependency version mismatch: %s has version %d (expected <= %d) in %s%n"
|
2013-02-26 05:09:31 +08:00
|
|
|
, 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
|
|
|
|
2013-02-26 05:09:31 +08:00
|
|
|
private static int[] GetRuleVersions(Type recognizerClass, string[] ruleNames
|
|
|
|
)
|
2013-02-16 22:14:20 +08:00
|
|
|
{
|
|
|
|
int[] versions = new int[ruleNames.Length];
|
|
|
|
FieldInfo[] fields = recognizerClass.GetFields();
|
|
|
|
foreach (FieldInfo field in fields)
|
|
|
|
{
|
2013-02-26 05:09:31 +08:00
|
|
|
bool isStatic = field.IsStatic;
|
2013-02-16 22:14:20 +08:00
|
|
|
bool isInteger = field.FieldType == typeof(int);
|
|
|
|
if (isStatic && isInteger && field.Name.StartsWith("RULE_"))
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2013-02-26 05:09:31 +08:00
|
|
|
string name = field.Name.Substring("RULE_".Length);
|
2013-02-18 10:34:36 +08:00
|
|
|
if (name.Length == 0 || !System.Char.IsLower(name[0]))
|
2013-02-16 22:14:20 +08:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2013-02-26 05:09:31 +08:00
|
|
|
int index = (int)field.GetValue(null);
|
2013-02-16 22:14:20 +08:00
|
|
|
if (index < 0 || index >= versions.Length)
|
|
|
|
{
|
|
|
|
object[] @params = new object[] { index, field.Name, recognizerClass.Name };
|
2013-02-26 05:09:31 +08:00
|
|
|
#if false
|
2013-02-16 22:14:20 +08:00
|
|
|
Logger.Log(Level.Warning, "Rule index {0} for rule ''{1}'' out of bounds for recognizer {2}."
|
|
|
|
, @params);
|
2013-02-26 05:09:31 +08:00
|
|
|
#endif
|
2013-02-16 22:14:20 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
MethodInfo ruleMethod = GetRuleMethod(recognizerClass, name);
|
|
|
|
if (ruleMethod == null)
|
|
|
|
{
|
|
|
|
object[] @params = new object[] { name, recognizerClass.Name };
|
2013-02-26 05:09:31 +08:00
|
|
|
#if false
|
2013-02-16 22:14:20 +08:00
|
|
|
Logger.Log(Level.Warning, "Could not find rule method for rule ''{0}'' in recognizer {1}."
|
|
|
|
, @params);
|
2013-02-26 05:09:31 +08:00
|
|
|
#endif
|
2013-02-16 22:14:20 +08:00
|
|
|
continue;
|
|
|
|
}
|
2013-02-26 05:09:31 +08:00
|
|
|
RuleVersionAttribute ruleVersion = ruleMethod.GetCustomAttribute<RuleVersionAttribute>();
|
|
|
|
int version = ruleVersion != null ? ruleVersion.Version : 0;
|
2013-02-16 22:14:20 +08:00
|
|
|
versions[index] = version;
|
|
|
|
}
|
|
|
|
catch (ArgumentException ex)
|
|
|
|
{
|
2013-02-26 05:09:31 +08:00
|
|
|
#if false
|
2013-02-16 22:14:20 +08:00
|
|
|
Logger.Log(Level.Warning, null, ex);
|
2013-02-26 05:09:31 +08:00
|
|
|
#endif
|
2013-02-16 22:14:20 +08:00
|
|
|
}
|
|
|
|
catch (MemberAccessException ex)
|
|
|
|
{
|
2013-02-26 05:09:31 +08:00
|
|
|
#if false
|
2013-02-16 22:14:20 +08:00
|
|
|
Logger.Log(Level.Warning, null, ex);
|
2013-02-26 05:09:31 +08:00
|
|
|
#endif
|
2013-02-16 22:14:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return versions;
|
|
|
|
}
|
2013-02-16 05:30:47 +08:00
|
|
|
|
2013-02-26 05:09:31 +08:00
|
|
|
private static MethodInfo GetRuleMethod(Type recognizerClass, string name
|
|
|
|
)
|
2013-02-16 22:14:20 +08:00
|
|
|
{
|
|
|
|
MethodInfo[] declaredMethods = recognizerClass.GetMethods();
|
|
|
|
foreach (MethodInfo method in declaredMethods)
|
|
|
|
{
|
2013-02-26 05:09:31 +08:00
|
|
|
if (method.Name.Equals(name) && method.GetCustomAttribute<RuleVersionAttribute>() != null)
|
2013-02-16 22:14:20 +08:00
|
|
|
{
|
|
|
|
return method;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
2013-02-16 05:30:47 +08:00
|
|
|
|
2013-02-26 05:09:31 +08:00
|
|
|
private static string[] GetRuleNames(Type recognizerClass)
|
2013-02-16 22:14:20 +08:00
|
|
|
{
|
2013-02-26 05:09:31 +08:00
|
|
|
FieldInfo ruleNames = recognizerClass.GetField("ruleNames");
|
|
|
|
return (string[])ruleNames.GetValue(null);
|
2013-02-16 22:14:20 +08:00
|
|
|
}
|
2013-02-16 05:30:47 +08:00
|
|
|
|
2013-02-26 05:09:31 +08:00
|
|
|
public static IList<Tuple<RuleDependencyAttribute, ICustomAttributeProvider>> GetDependencies(Type clazz)
|
2013-02-16 22:14:20 +08:00
|
|
|
{
|
2013-02-26 05:09:31 +08:00
|
|
|
IList<Tuple<RuleDependencyAttribute, ICustomAttributeProvider>> result = new List<Tuple<RuleDependencyAttribute
|
|
|
|
, ICustomAttributeProvider>>();
|
2013-02-16 05:30:47 +08:00
|
|
|
|
2013-02-26 05:09:31 +08:00
|
|
|
GetElementDependencies(clazz, result);
|
|
|
|
foreach (ConstructorInfo ctor in clazz.GetConstructors(BindingFlags.DeclaredOnly))
|
|
|
|
{
|
|
|
|
GetElementDependencies(ctor, result);
|
|
|
|
foreach (ParameterInfo parameter in ctor.GetParameters())
|
|
|
|
GetElementDependencies(parameter, result);
|
|
|
|
}
|
2013-02-16 05:30:47 +08:00
|
|
|
|
2013-02-26 05:09:31 +08:00
|
|
|
foreach (FieldInfo field in clazz.GetFields(BindingFlags.DeclaredOnly))
|
|
|
|
{
|
|
|
|
GetElementDependencies(field, result);
|
|
|
|
}
|
2013-02-16 05:30:47 +08:00
|
|
|
|
2013-02-26 05:09:31 +08:00
|
|
|
foreach (MethodInfo method in clazz.GetMethods(BindingFlags.DeclaredOnly))
|
|
|
|
{
|
|
|
|
GetElementDependencies(method, result);
|
|
|
|
if (method.ReturnParameter != null)
|
|
|
|
GetElementDependencies(method.ReturnParameter, result);
|
2013-02-16 05:30:47 +08:00
|
|
|
|
2013-02-26 05:09:31 +08:00
|
|
|
foreach (ParameterInfo parameter in method.GetParameters())
|
|
|
|
GetElementDependencies(parameter, result);
|
2013-02-16 22:14:20 +08:00
|
|
|
}
|
2013-02-26 05:09:31 +08:00
|
|
|
|
2013-02-16 22:14:20 +08:00
|
|
|
return result;
|
|
|
|
}
|
2013-02-16 05:30:47 +08:00
|
|
|
|
2013-02-26 05:09:31 +08:00
|
|
|
private static void GetElementDependencies(ICustomAttributeProvider annotatedElement, IList
|
|
|
|
<Tuple<RuleDependencyAttribute, ICustomAttributeProvider>> result)
|
2013-02-16 22:14:20 +08:00
|
|
|
{
|
2013-02-26 05:09:31 +08:00
|
|
|
foreach (RuleDependencyAttribute dependency in annotatedElement.GetCustomAttributes(typeof(RuleDependencyAttribute), true))
|
2013-02-16 22:14:20 +08:00
|
|
|
{
|
2013-02-26 05:09:31 +08:00
|
|
|
result.Add(Tuple.Create(dependency, annotatedElement));
|
2013-02-16 22:14:20 +08:00
|
|
|
}
|
|
|
|
}
|
2013-02-16 05:30:47 +08:00
|
|
|
|
2013-02-26 05:09:31 +08:00
|
|
|
private static RuleDependencyChecker.RuleRelations ExtractRuleRelations(Type
|
|
|
|
recognizer)
|
2013-02-26 04:37:45 +08:00
|
|
|
{
|
|
|
|
string serializedATN = GetSerializedATN(recognizer);
|
|
|
|
if (serializedATN == null)
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
ATN atn = ATNSimulator.Deserialize(serializedATN.ToCharArray());
|
|
|
|
RuleDependencyChecker.RuleRelations relations = new RuleDependencyChecker.RuleRelations
|
|
|
|
(atn.ruleToStartState.Length);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-02-26 05:09:31 +08:00
|
|
|
private static string GetSerializedATN(Type recognizerClass)
|
2013-02-26 04:37:45 +08:00
|
|
|
{
|
2013-02-26 05:09:31 +08:00
|
|
|
FieldInfo serializedAtnField = recognizerClass.GetField("_serializedATN", BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
|
|
|
if (serializedAtnField != null)
|
|
|
|
return (string)serializedAtnField.GetValue(null);
|
|
|
|
|
|
|
|
if (recognizerClass.BaseType != null)
|
|
|
|
return GetSerializedATN(recognizerClass.BaseType);
|
|
|
|
|
|
|
|
return null;
|
2013-02-26 04:37:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private sealed class RuleRelations
|
|
|
|
{
|
2013-02-26 05:09:31 +08:00
|
|
|
public readonly BitSet[] parents;
|
2013-02-26 04:37:45 +08:00
|
|
|
|
2013-02-26 05:09:31 +08:00
|
|
|
public readonly BitSet[] children;
|
2013-02-26 04:37:45 +08:00
|
|
|
|
|
|
|
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
|
|
|
}
|