|
@@ -0,0 +1,141 @@
|
|
|
|
+namespace Invercargill {
|
|
|
|
+
|
|
|
|
+ internal class DebugPrinter {
|
|
|
|
+
|
|
|
|
+ private const string COLOUR_RESET = "\x1b[0m";
|
|
|
|
+ private const string COLOUR_DEBUG = "\x1b[90m";
|
|
|
|
+ private const string COLOUR_PROGRAM = "\x1b[97m";
|
|
|
|
+ private const string COLOUR_CLASS = "\x1b[92m";
|
|
|
|
+ private const string COLOUR_CATEGORY = "\x1b[96m";
|
|
|
|
+
|
|
|
|
+ private static string format_colour(string colour, string message) {
|
|
|
|
+ return colour + message + COLOUR_RESET;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static DebugOutputDelegate get_delegate(DebugOutputDelegate? override_func, bool formatting = true) {
|
|
|
|
+ DebugOutputDelegate default_output_func = m => printerr(m);
|
|
|
|
+ var output_func = override_func ?? default_output_func;
|
|
|
|
+ if(formatting){
|
|
|
|
+ return output_func;
|
|
|
|
+ }
|
|
|
|
+ return (o) => output_func(o
|
|
|
|
+ .replace(COLOUR_RESET, "")
|
|
|
|
+ .replace(COLOUR_DEBUG, "")
|
|
|
|
+ .replace(COLOUR_PROGRAM, "")
|
|
|
|
+ .replace(COLOUR_CLASS, "")
|
|
|
|
+ .replace(COLOUR_CATEGORY, ""));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static void print_enumerable_dump<T>(Enumerable<T> enumerable, TransformDelegate<T, string> stringifier, string additional_message = "", DebugOutputDelegate? output_func = null, bool formatting = true) {
|
|
|
|
+ var output = get_delegate(output_func, formatting);
|
|
|
|
+
|
|
|
|
+ output("\n\n" + format_colour(COLOUR_DEBUG, "Invercargill enumerable debug dump: ") + format_colour(COLOUR_PROGRAM, additional_message) + "\n");
|
|
|
|
+ print_enumerable_info(enumerable.get_info(), 0, output_func, formatting);
|
|
|
|
+
|
|
|
|
+ var count = 0;
|
|
|
|
+ output(format_colour(COLOUR_DEBUG, "\nBegin iterating enumerable:\n"));
|
|
|
|
+ foreach (var item in enumerable) {
|
|
|
|
+ output(format_colour(COLOUR_DEBUG, @" $count:\t") + format_colour(COLOUR_PROGRAM, stringifier(item)) + "\n");
|
|
|
|
+ count++;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ output(format_colour(COLOUR_DEBUG, "End of enumerable iteration and dump.\n"));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static void print_enumerable_information(EnumerableInfo info, string additional_message = "", DebugOutputDelegate? output_func = null, bool formatting = true) {
|
|
|
|
+ var output = get_delegate(output_func, formatting);
|
|
|
|
+
|
|
|
|
+ output("\n\n" + format_colour(COLOUR_DEBUG, "Invercargill enumerable debug type: ") + format_colour(COLOUR_PROGRAM, additional_message) + "\n");
|
|
|
|
+ print_enumerable_info(info, 0, output_func, formatting);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static void print_trace_registration(EnumerableInfo info, string additional_message = "", DebugOutputDelegate? output_func = null, bool formatting = true) {
|
|
|
|
+ var output = get_delegate(output_func, formatting);
|
|
|
|
+
|
|
|
|
+ output("\n\n" + format_colour(COLOUR_DEBUG, "Invercargill enumerable debug trace: ") + format_colour(COLOUR_PROGRAM, additional_message) + "\n");
|
|
|
|
+ print_enumerable_info(info, 0, output_func, formatting);
|
|
|
|
+ output(format_colour(COLOUR_DEBUG, "Trace registered, output will be printed when the enumerable is iterated.\n"));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static void print_trace(string message, string additional_message = "", DebugOutputDelegate? output_func = null, bool formatting = true) {
|
|
|
|
+ var output = get_delegate(output_func, formatting);
|
|
|
|
+ var seperator = (additional_message != null && additional_message.length > 0) ? ": " : "";
|
|
|
|
+ output(format_colour(COLOUR_DEBUG, "[TRACE] ") + format_colour(COLOUR_PROGRAM, additional_message) + format_colour(COLOUR_DEBUG, seperator) + format_colour(COLOUR_PROGRAM, message) + "\n");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static void print_trace_debug_message(string message, string additional_message = "", DebugOutputDelegate? output_func = null, bool formatting = true) {
|
|
|
|
+ var output = get_delegate(output_func, formatting);
|
|
|
|
+ var seperator = (additional_message != null && additional_message.length > 0) ? ": " : "";
|
|
|
|
+ output(format_colour(COLOUR_DEBUG, "[TRACE] ") + format_colour(COLOUR_PROGRAM, additional_message) + format_colour(COLOUR_DEBUG, seperator) + format_colour(COLOUR_DEBUG, message) + "\n");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static void print_enumerable_info(EnumerableInfo info, int indents, DebugOutputDelegate? output_func = null, bool formatting = true) {
|
|
|
|
+ var output = get_delegate(output_func, formatting);
|
|
|
|
+
|
|
|
|
+ var indent = "";
|
|
|
|
+ for(int i = 0; i < indents; i++) indent += " ";
|
|
|
|
+ var has_sources = info.sources.any();
|
|
|
|
+ var known_count = info.count != null;
|
|
|
|
+ output(
|
|
|
|
+ format_colour(COLOUR_DEBUG, indent) +
|
|
|
|
+ format_colour(COLOUR_CATEGORY, info.category.to_string()) +
|
|
|
|
+ format_colour(COLOUR_DEBUG, " Enumerable ") +
|
|
|
|
+ format_colour(COLOUR_CLASS, info.enumerable_type.name()) +
|
|
|
|
+ format_colour(COLOUR_DEBUG, " with ") +
|
|
|
|
+ (known_count ? format_colour(COLOUR_PROGRAM, @"$(info.count) ") : "") +
|
|
|
|
+ format_colour(COLOUR_CLASS, info.element_type.name() ?? "UNKNOWN") +
|
|
|
|
+ format_colour(COLOUR_DEBUG, info.count == 1 ? " element" : " elements") +
|
|
|
|
+ (has_sources ? format_colour(COLOUR_DEBUG, ", sources from:") : ".") +
|
|
|
|
+ "\n"
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ if(has_sources)
|
|
|
|
+ info.sources.iterate(s => print_enumerable_info(s, indents + 1, output_func, formatting));
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ internal class TraceEnumerable<T> : Enumerable<T> {
|
|
|
|
+ private Enumerable<T> input;
|
|
|
|
+ private TransformDelegate<T, string> stringifier;
|
|
|
|
+ private string additional_message;
|
|
|
|
+ private DebugOutputDelegate? output_func;
|
|
|
|
+ private bool formatting;
|
|
|
|
+
|
|
|
|
+ public TraceEnumerable(owned Enumerable<T> input, EnumerableInfo info, owned TransformDelegate<T, string> stringifier, string additional_message = "", owned DebugOutputDelegate? output_func, bool formatting) {
|
|
|
|
+ this.input = (owned)input;
|
|
|
|
+ this.additional_message = additional_message;
|
|
|
|
+ this.stringifier = (owned)stringifier;
|
|
|
|
+ this.output_func = (owned)output_func;
|
|
|
|
+ this.formatting = formatting;
|
|
|
|
+ DebugPrinter.print_trace_registration(info, additional_message, output_func, formatting);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public override int? peek_count() {
|
|
|
|
+ var count = input.peek_count();
|
|
|
|
+ var str = count == null ? "NULL" : count.to_string();
|
|
|
|
+ DebugPrinter.print_trace_debug_message(@"peek_count() returned value $str", additional_message, output_func, formatting);
|
|
|
|
+ return count;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public override EnumerableInfo get_info() {
|
|
|
|
+ DebugPrinter.print_trace_debug_message(@"get_info() called", additional_message, output_func, formatting);
|
|
|
|
+ return new EnumerableInfo.infer_single(this, EnumerableCategory.COMPUTED, input);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public override Tracker<T> get_tracker() {
|
|
|
|
+ var tracker = input.get_tracker();
|
|
|
|
+ return new LambdaTracker<T>(
|
|
|
|
+ () => tracker.has_next(),
|
|
|
|
+ () => {
|
|
|
|
+ var item = tracker.get_next();
|
|
|
|
+ DebugPrinter.print_trace(stringifier(item), additional_message, output_func, formatting);
|
|
|
|
+ return item;
|
|
|
|
+ }
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+}
|