using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using glue.Collections.BitArray;
using glue.Extensions.String;
using glue.Extensions.Enumerable;
namespace agree.UnitTest
{
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
///
///
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public class TypeMgrUnitTests : TypeMgr
{
public TypeMgrUnitTests(Globals config, Grammar g)
: base(g, config)
{
}
public HashSet<String> PathsBetween(String t1, String t2)
{
return PathsBetween(type_dict[t1], type_dict[t2]);
}
public HashSet<String> PathsBetween(Type t1, Type t2)
{
HashSet<String> hs = new HashSet<String>();
if (t1 == t2)
return hs;
if (t1.IsSubtypeOf(t2))
{
Type tmp = t1;
t1 = t2;
t2 = tmp;
}
else if (!t1.IsSupertypeOf(t2))
return hs;
Action<String, Type> f = null;
f = (s, t) =>
{
String x = (s.Length == 0 ? String.Empty : s + " -> ") + t.Name;
if (t == t2)
hs.Add(x);
else foreach (Type c in t.Children)
{
if (c.IsSupertypeOrEqual(t2))
f(x, c);
}
};
f("", t1);
return hs;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#if false // update AndToDest for distilled bitarr
public void CheckForUnusedGlbs()
{
HashSet<Type> visited = new HashSet<Type>();
BitArr z = new BitArr(code_size);
foreach (Type n1 in type_dict.Values)
foreach (Type n2 in type_dict.Values)
{
if (n1 == n2)
continue;
// this version allows us to reuse 'z'
if (!BitArr.AndToDest(z, n1.m_code, n2.m_code))
continue;
Type glb;
if (!code_dict.TryGetValue(z, out glb))
throw new Exception(String.Format("missing GLB for {0} and {1}", n1.Name, n2.Name));
visited.Add(glb);
}
foreach (Type n in type_dict.Values)
if (n.IsGlb && !visited.Contains(n))
throw new Exception(String.Format("unreferenced GLB {0}", n.Name));
}
#endif
#if DEBUG
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void CheckGlb()
{
int err_count = 0;
HashSet<BitArr> unique_problems = new HashSet<BitArr>();
int i;
Type[] a_t = type_dict.Values.ToArray();
for (i = 0; i < a_t.Length; i++)
{
for (int j = i + 1; j < a_t.Length; j++)
{
HashSet<Type> glbs = a_t[i].GlbCheck(a_t[j], TopType);
if (glbs != null)
{
BitArr bc = a_t[i].m_code & a_t[j].m_code;
unique_problems.Add(bc);
Type should_use = code_dict[bc];
Console.WriteLine("greatest lower bound problem between {0} & {1}", a_t[i].Name, a_t[j].Name);
Console.WriteLine("should use {0} {1}", should_use.Name, bc.OnesPositions().Layout());
foreach (Type tt in glbs)
Console.WriteLine("\t{0}\t[level {1} {2}]", tt.Name, tt.m_level, tt.m_code.OnesPositions().Layout());
err_count++;
}
}
}
if (unique_problems.Count > 0)
{
Console.WriteLine("{0} glb problems, {1} unique", err_count, unique_problems.Count);
foreach (BitArr bc in unique_problems)
Console.WriteLine("{0}", code_dict[bc].Name);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void CheckGlbAlgs()
{
foreach (Type t in type_dict.Values)
{
HashSet<Type> hs = t.AllAncestors;
if (hs.Contains(t))
throw new Exception();
foreach (Type t2 in type_dict.Values)
{
if (hs.Contains(t2))
{
if (t2.IsSubtypeOf(t) || t.IsSupertypeOf(t2))
throw new Exception();
}
else
{
if (t2.IsSupertypeOf(t) || t.IsSubtypeOf(t2))
throw new Exception();
}
}
hs = t.AllDescendants;
if (hs.Contains(t))
throw new Exception();
foreach (Type t2 in type_dict.Values)
{
if (hs.Contains(t2))
{
if (t2.IsSupertypeOf(t) || t.IsSubtypeOf(t2))
throw new Exception();
}
else
{
if (t2.IsSubtypeOf(t) || t.IsSupertypeOf(t2))
throw new Exception();
}
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void CheckGlbPairForProblems(Type t1, Type t2)
{
HashSet<Type> glbs = t1.GlbCheck(t2, TopType);
if (glbs != null)
{
BitArr bc = t1.m_code & t2.m_code;
Type should_use = code_dict[bc];
Console.WriteLine("greatest lower bound problem between {0} & {1}", t1.Name, t2.Name);
Console.WriteLine("should use {0}", should_use.Name);
foreach (Type tt1 in glbs)
Console.WriteLine("\t{0}\t[level {1}]", tt1.Name, tt1.m_level);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void DisplayMaximalFeatures()
{
foreach (Type tt in type_dict.Values)
{
Console.WriteLine(tt.Name);
foreach (TypeMgr.FeatureInfo fi in tt._dbg_features().Where(cp => cp.maximal_type == tt))
Console.WriteLine("\t{0}", fi.feature.ToUpper());
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void DisplayAllFeatures()
{
foreach (Type tt in type_dict.Values)
{
Console.WriteLine(tt.Name);
foreach (TypeMgr.FeatureInfo fi in tt._dbg_features())
{
Console.WriteLine("\t{0}", fi.feature.ToUpper());
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void DisplayAllTypes()
{
foreach (Type tt in type_dict.Values)
{
Console.WriteLine(tt.Name);
foreach (var fi in tt._dbg_features())
{
Console.Write("\t{0}", fi.feature.ToUpper());
if (fi.maximal_type == tt)
Console.Write("(local)");
Console.WriteLine();
}
}
}
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void CheckFeaturesFlag()
{
foreach (Type t in type_dict.Values)
{
if (t.HasAnyFeatures != (t.FeatureIndexes.Length == 0))
throw new Exception();
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void CheckRedundantLinks()
{
Stack<Type> stk = new Stack<Type>();
Action<Type> f = null;
f = node =>
{
if (!stk.Contains(node))
{
stk.Push(node);
foreach (Type ch in node.Children)
f(ch);
stk.Pop();
}
IEnumerable<Type> r = stk.Skip(1).Intersect(node.Parents);
if (r.Any())
throw new Exception(String.Format("redundant link {0} to {1}", r.First().Name, node.Name));
};
f(TopType);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void CheckForCycle()
{
Stack<Type> stk = new Stack<Type>();
Action<Type> f = null;
f = node =>
{
if (stk.Contains(node))
throw new Exception("cycle detected");
stk.Push(node);
foreach (Type ch in node.Children)
f(ch);
stk.Pop();
};
f(TopType);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public int TypeEdgeCount()
{
HashSet<Type> visited = new HashSet<Type>();
int count = 0;
Action<Type> f = null;
f = node =>
{
if (!visited.Contains(node))
{
visited.Add(node);
count += node.ChildCount;
foreach (Type ch in node.Children)
f(ch);
}
};
f(TopType);
return count;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void DisplayTree(bool f_all)
{
Console.WriteLine("-------------- Type Hierarchy Display -------------------");
foreach (Type t in type_dict.Values)
{
Console.WriteLine(t.Name + ":");
if (!f_all)
{
if (t.Parents.Any())
{
Console.Write("\tparents: { ");
foreach (String s in t.Parents.Select(e => e.Name))
Console.Write(s + " ");
Console.WriteLine("}");
}
if (t.Children.Any())
{
Console.Write("\tchildren: { ");
foreach (String s in t.Children.Select(e => e.Name))
Console.Write(s + " ");
Console.WriteLine("}");
}
}
else
{
foreach (String s in t.AllAncestors.Select(e => e.Name))
Console.WriteLine("\tP : " + s);
foreach (String s in t.AllDescendants.Select(e => e.Name))
Console.WriteLine("\tC : " + s);
}
}
Console.WriteLine("---------------------------------------------------------");
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void CheckConjoinedParents(TextWriter tw)
{
BitArr ba_conj = new BitArr(code_size);
foreach (Type tt in type_dict.Values)
{
if (tt.Parents.Count > 1)
{
ba_conj.SetAll();
foreach (Type tt_par in tt.Parents)
{
if (!ba_conj.AndEq(tt_par.m_code))
throw new Exception(String.Format("Conjoined parents '{0}' on type {1} do not unify.", tt.Parents.Select(e => e.Name).StringJoin(" "), tt_par.Name));
}
if (tw != null)
tw.WriteLine("{0} := {1} ... {2}", tt.Name, tt.Parents.Select(e => e.Name).StringJoin(" & "), code_dict[ba_conj].Name);
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void DisplayConstraintTokens()
{
foreach (Type tt in type_dict.Values.Where(e => e.m_bfc != null))
{
Console.WriteLine(tt.Name);
foreach (var bfc in tt.m_bfc)
{
Console.WriteLine("\t{0}", bfc.ToString());
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void DisplayNonBareTypes()
{
int i = 0;
foreach (Type tt in type_dict.Values.Where(e => e.HasAnyFeatures))
{
i++;
Console.WriteLine(tt.Name + "\t" + tt.IsSubtypeOf(TopType));
}
Console.WriteLine(i);
}
};
static class Extensions
{
public static String Layout(this IEnumerable<int> i)
{
return "{" + i.StringJoin(" ") + "}";
}
};
}