namespace Ariadne.UnitTests { /// /// Calls its own passage until three levels deep, with a local at each level that is used after the pause. /// public partial class Countdown : Arc { public string Log = ""; private void Descend(ArcTests.Gates gates, int level) { int mine = level * 10; wait: while (!gates.Open.Contains("go" + level)) { Yield(); } if (level < 3) { deeper: Descend(gates, level + 1); } Log += mine + ";"; } protected override void Run(ArcTests.Gates gates) { start: Descend(gates, 1); } } /// /// Has two passages that call each other, each pausing at every level. /// public partial class Rally : Arc { public string Log = ""; private void Ping(ArcTests.Gates gates, int left) { wait: while (!gates.Open.Contains("ping" + left)) { Yield(); } Log += "ping" + left + ";"; if (left > 0) { back: Pong(gates, left - 1); } } private void Pong(ArcTests.Gates gates, int left) { wait: while (!gates.Open.Contains("pong" + left)) { Yield(); } Log += "pong" + left + ";"; if (left > 0) { again: Ping(gates, left - 1); } } protected override void Run(ArcTests.Gates gates) { start: Ping(gates, 3); } } /// /// Has a generic passage that calls itself with the type arguments it was given. /// public partial class Layering : Arc { public string Log = ""; private void Stack(ArcTests.Gates gates, X item, int left) { X kept = item; wait: while (!gates.Open.Contains("layer" + left)) { Yield(); } if (left > 0) { deeper: Stack(gates, kept, left - 1); } Log += kept + "@" + left + ";"; } protected override void Run(ArcTests.Gates gates) { start: Stack(gates, "box", 2); } } /// /// Has a generic passage that calls itself with its two type arguments swapped, so its frames alternate between /// two types. /// public partial class Trading : Arc { public string Log = ""; private void Swap(ArcTests.Gates gates, X first, Y second, int left) { X kept = first; Y other = second; wait: while (!gates.Open.Contains("trade" + left)) { Yield(); } Log += kept + "/" + other + ";"; if (left > 0) { deeper: Swap(gates, other, kept, left - 1); } } protected override void Run(ArcTests.Gates gates) { start: Swap(gates, 1, "one", 2); } } /// /// Runs a passage that two arcs of this class hand to each other, so each serve is run on the other arc. /// public partial class Volley : Arc { public Volley Partner; public string Log = ""; public void Serve(ArcTests.Gates gates, int shot) { int mine = shot; wait: while (!gates.Open.Contains("hit" + shot)) { Yield(); } Log += "serve" + mine + ";"; if (shot > 1) { back: Partner.Serve(gates, shot - 1); } } protected override void Run(ArcTests.Gates gates) { start: Serve(gates, 3); } } /// /// Offers a passage that calls itself, for other arcs to run. /// public partial class Orchard : Arc { public string Log = ""; public void Grow(ArcTests.Gates gates, int rings) { int mine = rings; wait: while (!gates.Open.Contains("ring" + rings)) { Yield(); } if (rings > 1) { deeper: Grow(gates, rings - 1); } Log += mine + ";"; } protected override void Run(ArcTests.Gates gates) { } } /// /// Runs the passage of another arc that calls itself. /// public partial class Orchardist : Arc { public Orchard Trees = new Orchard(); protected override void Run(ArcTests.Gates gates) { plant: Trees.Grow(gates, 2); } } /// /// Holds a passage that calls itself in a base class, for the scripts that derive from it to run. /// public abstract partial class Digging : Arc { public string Log = ""; protected void Dig(ArcTests.Gates gates, int depth) { int here = depth; wait: while (!gates.Open.Contains("dig" + depth)) { Yield(); } if (depth < 2) { deeper: Dig(gates, depth + 1); } Log += here + ";"; } } public partial class Shaft : Digging { protected override void Run(ArcTests.Gates gates) { start: Dig(gates, 1); } } /// /// Calls its own passage down to the third level before it pauses there, and does nothing else while it waits. /// public partial class Plunging : Arc { public int Spins; private void Plunge(ArcTests.Gates gates, int level) { int mine = level; if (level < 3) { deeper: Plunge(gates, level + 1); } wait: while (!gates.Open.Contains("go")) { ++Spins; Yield(); } Spins += mine; } protected override void Run(ArcTests.Gates gates) { start: Plunge(gates, 1); } } /// /// Has a generic passage that calls itself with its type argument wrapped in a list, so every level is a frame of a /// new type. /// public partial class Widening : Arc { public string Log = ""; private static int Wrapping(System.Type type) { int depth = 0; while (type.IsGenericType) { ++depth; type = type.GetGenericArguments()[0]; } return depth; } private void Wrap(ArcTests.Gates gates, X item, int left) { X kept = item; wait: while (!gates.Open.Contains("wrap" + left)) { Yield(); } Log += Wrapping(typeof(X)) + "@" + left + ";"; if (left > 0) { deeper: Wrap(gates, new System.Collections.Generic.List { kept }, left - 1); } Log += "up" + Wrapping(kept.GetType()) + ";"; } protected override void Run(ArcTests.Gates gates) { start: Wrap(gates, 7, 2); } } /// /// Runs Run again from a passage that Run calls, so each lap has a frame for Run's locals. /// public partial class Relapsing : Arc { public int Laps; public string Log = ""; private void Again(ArcTests.Gates gates, int kept) { wait: while (!gates.Open.Contains("lap" + kept)) { Yield(); } Log += "lap" + kept + ";"; if (kept < 2) { back: Run(gates); } } protected override void Run(ArcTests.Gates gates) { int lap = Laps++; start: Again(gates, lap); Log += "end" + lap + ";"; } } /// /// Runs Run again from Run itself. /// public partial class Repeating : Arc { public int Laps; public string Log = ""; protected override void Run(ArcTests.Gates gates) { int lap = Laps++; wait: while (!gates.Open.Contains("round" + lap)) { Yield(); } Log += "round" + lap + ";"; if (lap < 2) { again: Run(gates); } Log += "done" + lap + ";"; } } /// /// Has a Run that is part of a cycle, for a class that derives from it to override with a cycle of its own. /// public partial class Cycling : Arc { public string Log = ""; public int Laps; private void Pass(ArcTests.Gates gates, int kept) { wait: while (!gates.Open.Contains("pass" + kept)) { Yield(); } Log += "pass" + kept + ";"; if (kept < 1) { back: Run(gates); } } protected override void Run(ArcTests.Gates gates) { int lap = Laps++; start: Pass(gates, lap); } } public partial class CyclingChild : Cycling { private void Push(ArcTests.Gates gates, int kept) { wait: while (!gates.Open.Contains("push" + kept)) { Yield(); } Log += "push" + kept + ";"; if (kept < 1) { back: Run(gates); } } protected override void Run(ArcTests.Gates gates) { int lap = Laps++; start: Push(gates, lap); } } /// /// Calls its own generic passage without end, wrapping its type argument at every level. /// public partial class Fathomless : Arc { public int Reached; private void Sink(ArcTests.Gates gates, X item, int level) { Reached = level; if (level < 0) { never: while (!gates.Open.Contains("never")) { Yield(); } } deeper: Sink(gates, new System.Collections.Generic.List { item }, level + 1); } protected override void Run(ArcTests.Gates gates) { start: Sink(gates, 0, 0); } } /// /// Calls its own passage without end, so only the stack stops it. /// public partial class Bottomless : Arc { public int Reached; private void Deeper(ArcTests.Gates gates, int level) { Reached = level; if (level < 0) { never: while (!gates.Open.Contains("never")) { Yield(); } } deeper: Deeper(gates, level + 1); } protected override void Run(ArcTests.Gates gates) { start: Deeper(gates, 0); } } }