using System; using System.Collections.Generic; namespace Ariadne.UnitTests { /// /// The context the trigger wait scripts run in, with the triggers they wait on and a log they write to. /// public class TriggerWorld { public readonly Trigger Door = new Trigger(); public readonly Trigger Alarm = new Trigger(); [Scratch] public readonly List Log = new List(); } /// /// Waits for the door, then logs. /// public partial class SingleTriggerScript : Arc { protected override void Run(TriggerWorld world) { world.Log.Add("start"); first: Wait(world.Door); world.Log.Add("door"); } } /// /// Waits for the door, then for the alarm. /// public partial class TwoWaitsScript : Arc { protected override void Run(TriggerWorld world) { first: Wait(world.Door); world.Log.Add("door"); second: Wait(world.Alarm); world.Log.Add("alarm"); } } /// /// Waits for either trigger, and logs which one it was. /// public partial class AnyTriggerScript : Arc { protected override void Run(TriggerWorld world) { first: Trigger fired = WaitAny(world.Door, world.Alarm); world.Log.Add(fired == world.Alarm ? "alarm" : "door"); } } /// /// Waits for both triggers, and logs which one came last. /// public partial class AllTriggersScript : Arc { protected override void Run(TriggerWorld world) { first: Trigger last = WaitAll(world.Door, world.Alarm); world.Log.Add(last == world.Alarm ? "alarm last" : "door last"); } } /// /// Waits for the same trigger twice in one wait. /// public partial class RepeatedTriggerScript : Arc { protected override void Run(TriggerWorld world) { first: WaitAll(world.Door, world.Door); world.Log.Add("through"); } } /// /// Waits for the door three times, with a local counting the trips. /// public partial class LoopedTriggerScript : Arc { protected override void Run(TriggerWorld world) { int count = 0; while (count < 3) { spin: Wait(world.Door); ++count; world.Log.Add("door " + count); } } } /// /// Waits for the door unless told to skip it, and then sleeps, so a restart can send it past the wait. /// public partial class RestartableTriggerScript : Arc { public bool Skip; protected override void Run(TriggerWorld world) { if (!Skip) { first: Wait(world.Door); world.Log.Add("door"); } nap: Wait(TimeSpan.FromSeconds(100)); world.Log.Add("rested"); } } /// /// Takes the trigger a wait ended on into a local it declared earlier, and into a field. /// public partial class AssignedTriggerScript : Arc { public Trigger Last; protected override void Run(TriggerWorld world) { Trigger first = null; pick: first = WaitAny(world.Door, world.Alarm); again: Last = WaitAny(world.Door, world.Alarm); world.Log.Add(first == world.Door ? "first door" : "first alarm"); world.Log.Add(Last == world.Door ? "then door" : "then alarm"); } } /// /// Keeps the trigger a wait ended on across a later pause. /// public partial class KeptTriggerScript : Arc { protected override void Run(TriggerWorld world) { first: Trigger fired = WaitAny(world.Door, world.Alarm); second: Yield(); world.Log.Add(fired == world.Alarm ? "alarm" : "door"); } } /// /// Waits in a passage that hands the trigger back. /// public partial class PassageTriggerScript : Arc { private Trigger Pick(TriggerWorld world) { inner: return WaitAny(world.Door, world.Alarm); } protected override void Run(TriggerWorld world) { outer: Trigger picked = Pick(world); world.Log.Add(picked == world.Alarm ? "alarm" : "door"); } } /// /// Offers a passage for other arcs to run, which waits for the door. /// public partial class TriggerLookoutScript : Arc { public void Watch(TriggerWorld world) { watch: Wait(world.Door); world.Log.Add("seen"); } protected override void Run(TriggerWorld world) { } } /// /// Runs the passage of another arc that waits for the door. /// public partial class TriggerRelayScript : Arc { public TriggerLookoutScript Lookout; protected override void Run(TriggerWorld world) { relay: Lookout.Watch(world); world.Log.Add("relayed"); } } /// /// Waits in a generic passage, which keeps its locals in a frame of its own. /// public partial class GenericTriggerScript : Arc { private Trigger Choose(TriggerWorld world, ItemType marker) { inner: return WaitAny(world.Door, world.Alarm); } protected override void Run(TriggerWorld world) { outer: Trigger picked = Choose(world, 5); world.Log.Add(picked == world.Alarm ? "alarm" : "door"); } } /// /// Waits for the door with a time limit, and logs whether it came. /// public partial class TimedDoorScript : Arc { public TimeSpan Limit = TimeSpan.FromSeconds(2); protected override void Run(TriggerWorld world) { first: Trigger got = Wait(world.Door, timeout: Limit); world.Log.Add(got == null ? "timed out" : "door"); } } /// /// Waits for either trigger with a time limit, and logs which one came. /// public partial class TimedAnyScript : Arc { public TimeSpan Limit = TimeSpan.FromSeconds(2); protected override void Run(TriggerWorld world) { first: Trigger fired = WaitAny(timeout: Limit, world.Door, world.Alarm); world.Log.Add(fired == null ? "timed out" : fired == world.Alarm ? "alarm" : "door"); } } /// /// Waits for both triggers with a time limit, and logs which one came last. /// public partial class TimedAllScript : Arc { public TimeSpan Limit = TimeSpan.FromSeconds(2); protected override void Run(TriggerWorld world) { first: Trigger last = WaitAll(timeout: Limit, world.Door, world.Alarm); world.Log.Add(last == null ? "timed out" : last == world.Alarm ? "alarm last" : "door last"); } } /// /// Waits for the door with a time limit, and then sleeps for a long time. /// public partial class TimedThenNapScript : Arc { public TimeSpan Limit = TimeSpan.FromSeconds(2); protected override void Run(TriggerWorld world) { first: Wait(world.Door, timeout: Limit); world.Log.Add("waited"); second: Wait(TimeSpan.FromSeconds(100)); world.Log.Add("rested"); } } /// /// Waits for the door with a time limit three times, with the arguments named out of order. /// public partial class TimedLoopScript : Arc { public TimeSpan Limit = TimeSpan.FromSeconds(2); protected override void Run(TriggerWorld world) { int count = 0; while (count < 3) { spin: Trigger got = Wait(timeout: Limit, trigger: world.Door); ++count; world.Log.Add((got == null ? "timed out " : "door ") + count); } } } /// /// Waits for either trigger with a time limit in a passage that hands the trigger back. /// public partial class TimedPassageScript : Arc { public TimeSpan Limit = TimeSpan.FromSeconds(2); private Trigger Pick(TriggerWorld world) { inner: return WaitAny(timeout: Limit, world.Door, world.Alarm); } protected override void Run(TriggerWorld world) { outer: Trigger picked = Pick(world); world.Log.Add(picked == null ? "timed out" : picked == world.Alarm ? "alarm" : "door"); } } /// /// Waits for the door with a time limit, ignoring the result. /// public partial class TimedDiscardScript : Arc { public TimeSpan Limit = TimeSpan.FromSeconds(2); protected override void Run(TriggerWorld world) { first: Wait(world.Door, timeout: Limit); world.Log.Add("through"); } } /// /// Waits for the door inside a branch and a loop that is only sometimes taken. /// public partial class BranchingTriggerScript : Arc { public bool Skip; protected override void Run(TriggerWorld world) { if (!Skip) { inside: Wait(world.Door); world.Log.Add("waited"); } world.Log.Add("done"); } } }