diff --git a/Src/PChecker/CheckerCore/Actors/Actor.cs b/Src/PChecker/CheckerCore/Actors/Actor.cs deleted file mode 100644 index 1804591e2a..0000000000 --- a/Src/PChecker/CheckerCore/Actors/Actor.cs +++ /dev/null @@ -1,1005 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; -using PChecker.Actors.EventQueues; -using PChecker.Actors.Events; -using PChecker.Actors.Exceptions; -using PChecker.Actors.Handlers; -using PChecker.Actors.Logging; -using PChecker.Actors.Managers; -using PChecker.Exceptions; -using PChecker.IO.Debugging; -using EventInfo = PChecker.Actors.Events.EventInfo; - -namespace PChecker.Actors -{ - /// - /// Type that implements an actor. Inherit from this class to declare a custom actor. - /// - public abstract class Actor - { - /// - /// Cache of actor types to a map of event types to action declarations. - /// - private static readonly ConcurrentDictionary> ActionCache = - new ConcurrentDictionary>(); - - /// - /// A set of lockable objects used to protect static initialization of the ActionCache while - /// also enabling multithreaded initialization of different Actor types. - /// - private static readonly ConcurrentDictionary ActionCacheLocks = - new ConcurrentDictionary(); - - /// - /// A cached array that contains a single event type. - /// - private static readonly Type[] SingleEventTypeArray = new Type[] { typeof(Event) }; - - /// - /// The runtime that executes this actor. - /// - internal ActorRuntime Runtime { get; private set; } - - /// - /// Unique id that identifies this actor. - /// - protected internal ActorId Id { get; private set; } - - /// - /// Manages the actor. - /// - internal IActorManager Manager { get; private set; } - - /// - /// The inbox of the actor. Incoming events are enqueued here. - /// Events are dequeued to be processed. - /// - private protected IEventQueue Inbox; - - /// - /// Map from event types to cached action delegates. - /// - private protected readonly Dictionary ActionMap; - - /// - /// The current status of the actor. It is marked volatile as - /// the runtime can read it concurrently. - /// - private protected volatile Status CurrentStatus; - - /// - /// Gets the name of the current state, if there is one. - /// - internal string CurrentStateName { get; private protected set; } - - /// - /// Checks if the actor is halted. - /// - internal bool IsHalted => CurrentStatus is Status.Halted; - - /// - /// Checks if a default handler is available. - /// - internal bool IsDefaultHandlerAvailable { get; private set; } - - /// - /// Id used to identify subsequent operations performed by this actor. This value - /// is initially either or the specified - /// upon creation. This value is automatically set to the operation group id of the - /// last dequeue or receive operation, if it is not . This - /// value can also be manually set using the property. - /// - protected internal virtual Guid OperationGroupId - { - get => Manager.OperationGroupId; - - set - { - Manager.OperationGroupId = value; - } - } - - /// - /// The installed runtime logger. - /// - protected TextWriter Logger => Runtime.Logger; - - /// - /// The installed runtime json logger. - /// - protected JsonWriter JsonLogger => Runtime.JsonLogger; - - /// - /// User-defined hashed state of the actor. Override to improve the - /// accuracy of stateful techniques during testing. - /// - protected virtual int HashedState => 0; - - /// - /// Initializes a new instance of the class. - /// - protected Actor() - { - ActionMap = new Dictionary(); - CurrentStatus = Status.Active; - CurrentStateName = default; - IsDefaultHandlerAvailable = false; - } - - /// - /// Configures the actor. - /// - internal void Configure(ActorRuntime runtime, ActorId id, IActorManager manager, IEventQueue inbox) - { - Runtime = runtime; - Id = id; - Manager = manager; - Inbox = inbox; - } - - /// - /// Initializes the actor with the specified optional event. - /// - /// Optional event used for initialization. - internal virtual async Task InitializeAsync(Event initialEvent) - { - // Invoke the custom initializer, if there is one. - await InvokeUserCallbackAsync(UserCallbackType.OnInitialize, initialEvent); - if (CurrentStatus is Status.Halting) - { - await HaltAsync(initialEvent); - } - } - - /// - /// Creates a new actor of the specified type and with the specified optional - /// . This can only be used to access - /// its payload, and cannot be handled. - /// - /// Type of the actor. - /// Optional initialization event. - /// Optional id that can be used to identify this operation. - /// The unique actor id. - protected ActorId CreateActor(Type type, Event initialEvent = null, Guid opGroupId = default) => - Runtime.CreateActor(null, type, null, initialEvent, this, opGroupId); - - /// - /// Creates a new actor of the specified type and name, and with the specified - /// optional . This can only be used to - /// access its payload, and cannot be handled. - /// - /// Type of the actor. - /// Optional name used for logging. - /// Optional initialization event. - /// Optional id that can be used to identify this operation. - /// The unique actor id. - protected ActorId CreateActor(Type type, string name, Event initialEvent = null, Guid opGroupId = default) => - Runtime.CreateActor(null, type, name, initialEvent, this, opGroupId); - - /// - /// Creates a new actor of the specified and name, using the specified - /// unbound actor id, and passes the specified optional . This event - /// can only be used to access its payload, and cannot be handled. - /// - /// Unbound actor id. - /// Type of the actor. - /// Optional name used for logging. - /// Optional initialization event. - /// Optional id that can be used to identify this operation. - protected void CreateActor(ActorId id, Type type, string name, Event initialEvent = null, Guid opGroupId = default) => - Runtime.CreateActor(id, type, name, initialEvent, this, opGroupId); - - /// - /// Sends an asynchronous to a target. - /// - /// The id of the target. - /// The event to send. - /// Optional id that can be used to identify this operation. - protected void SendEvent(ActorId id, Event e, Guid opGroupId = default) => - Runtime.SendEvent(id, e, this, opGroupId); - - /// - /// Waits to receive an of the specified type - /// that satisfies an optional predicate. - /// - /// The event type. - /// The optional predicate. - /// The received event. - protected internal Task ReceiveEventAsync(Type eventType, Func predicate = null) - { - Assert(CurrentStatus is Status.Active, "{0} invoked ReceiveEventAsync while halting.", Id); - Runtime.NotifyReceiveCalled(this); - return Inbox.ReceiveEventAsync(eventType, predicate); - } - - /// - /// Waits to receive an of the specified types. - /// - /// The event types to wait for. - /// The received event. - protected internal Task ReceiveEventAsync(params Type[] eventTypes) - { - Assert(CurrentStatus is Status.Active, "{0} invoked ReceiveEventAsync while halting.", Id); - Runtime.NotifyReceiveCalled(this); - return Inbox.ReceiveEventAsync(eventTypes); - } - - /// - /// Waits to receive an of the specified types - /// that satisfy the specified predicates. - /// - /// Event types and predicates. - /// The received event. - protected internal Task ReceiveEventAsync(params Tuple>[] events) - { - Assert(CurrentStatus is Status.Active, "{0} invoked ReceiveEventAsync while halting.", Id); - Runtime.NotifyReceiveCalled(this); - return Inbox.ReceiveEventAsync(events); - } - - /// - /// Returns a nondeterministic boolean choice, that can be - /// controlled during analysis or testing. - /// - /// The controlled nondeterministic choice. - protected bool RandomBoolean() => Runtime.GetNondeterministicBooleanChoice(2, Id.Name, Id.Type); - - /// - /// Returns a nondeterministic boolean choice, that can be - /// controlled during analysis or testing. The value is used - /// to generate a number in the range [0..maxValue), where 0 - /// triggers true. - /// - /// The max value. - /// The controlled nondeterministic choice. - protected bool RandomBoolean(int maxValue) => - Runtime.GetNondeterministicBooleanChoice(maxValue, Id.Name, Id.Type); - - /// - /// Returns a nondeterministic integer, that can be controlled during - /// analysis or testing. The value is used to generate an integer in - /// the range [0..maxValue). - /// - /// The max value. - /// The controlled nondeterministic integer. - protected int RandomInteger(int maxValue) => - Runtime.GetNondeterministicIntegerChoice(maxValue, Id.Name, Id.Type); - - /// - /// Invokes the specified monitor with the specified . - /// - /// Type of the monitor. - /// Event to send to the monitor. - protected void Monitor(Event e) => Monitor(typeof(T), e); - - /// - /// Invokes the specified monitor with the specified event. - /// - /// Type of the monitor. - /// The event to send. - protected void Monitor(Type type, Event e) - { - Assert(e != null, "{0} is sending a null event.", Id); - Runtime.Monitor(type, e, Id.Name, Id.Type, CurrentStateName); - } - - /// - /// Checks if the assertion holds, and if not, throws an exception. - /// - protected void Assert(bool predicate) => Runtime.Assert(predicate); - - /// - /// Checks if the assertion holds, and if not, throws an exception. - /// - protected void Assert(bool predicate, string s, object arg0) => - Runtime.Assert(predicate, s, arg0); - - /// - /// Checks if the assertion holds, and if not, throws an exception. - /// - protected void Assert(bool predicate, string s, object arg0, object arg1) => - Runtime.Assert(predicate, s, arg0, arg1); - - /// - /// Checks if the assertion holds, and if not, throws an exception. - /// - protected void Assert(bool predicate, string s, object arg0, object arg1, object arg2) => - Runtime.Assert(predicate, s, arg0, arg1, arg2); - - /// - /// Checks if the assertion holds, and if not, throws an exception. - /// - protected void Assert(bool predicate, string s, params object[] args) => - Runtime.Assert(predicate, s, args); - - /// - /// Raises a to halt the actor at the end of the current action. - /// - protected virtual void RaiseHaltEvent() - { - Assert(CurrentStatus is Status.Active, "{0} invoked Halt while halting.", Id); - CurrentStatus = Status.Halting; - } - - /// - /// Asynchronous callback that is invoked when the actor is initialized with an optional event. - /// - /// Optional event used for initialization. - /// Task that represents the asynchronous operation. - protected virtual Task OnInitializeAsync(Event initialEvent) => Task.CompletedTask; - - /// - /// Asynchronous callback that is invoked when the actor successfully dequeues - /// an event from its inbox. This method is not called when the dequeue happens - /// via a receive statement. - /// - /// The event that was dequeued. - protected virtual Task OnEventDequeuedAsync(Event e) => Task.CompletedTask; - - /// - /// Asynchronous callback that is invoked when the actor finishes handling a dequeued - /// event, unless the handler of the dequeued event caused the actor to halt (either - /// normally or due to an exception). The actor will either become idle or dequeue - /// the next event from its inbox. - /// - /// The event that was handled. - protected virtual Task OnEventHandledAsync(Event e) => Task.CompletedTask; - - /// - /// Asynchronous callback that is invoked when the actor receives an event that - /// it is not prepared to handle. The callback is invoked first, after which the - /// actor will necessarily throw an - /// - /// The event that was unhandled. - /// The state when the event was dequeued. - protected virtual Task OnEventUnhandledAsync(Event e, string state) => Task.CompletedTask; - - /// - /// Asynchronous callback that is invoked when the actor handles an exception. - /// - /// The exception thrown by the actor. - /// The event being handled when the exception was thrown. - /// The action that the runtime should take. - protected virtual Task OnExceptionHandledAsync(Exception ex, Event e) => Task.CompletedTask; - - /// - /// Asynchronous callback that is invoked when the actor halts. - /// - /// The event being handled when the actor halted. - /// Task that represents the asynchronous operation. - protected virtual Task OnHaltAsync(Event e) => Task.CompletedTask; - - /// - /// Enqueues the specified event and its metadata. - /// - internal EnqueueStatus Enqueue(Event e, Guid opGroupId, EventInfo info) - { - if (CurrentStatus is Status.Halted) - { - return EnqueueStatus.Dropped; - } - - return Inbox.Enqueue(e, opGroupId, info); - } - - /// - /// Runs the event handler. The handler terminates if there is no next - /// event to process or if the actor has halted. - /// - internal async Task RunEventHandlerAsync() - { - Event lastDequeuedEvent = null; - while (CurrentStatus != Status.Halted && Runtime.IsRunning) - { - (var status, var e, var opGroupId, var info) = Inbox.Dequeue(); - if (opGroupId != Guid.Empty) - { - // Inherit the operation group id of the dequeued operation, if it is non-empty. - Manager.OperationGroupId = opGroupId; - } - - if (status is DequeueStatus.Success) - { - // Notify the runtime for a new event to handle. This is only used - // during bug-finding and operation bounding, because the runtime - // has to schedule an actor when a new operation is dequeued. - Runtime.NotifyDequeuedEvent(this, e, info); - await InvokeUserCallbackAsync(UserCallbackType.OnEventDequeued, e); - lastDequeuedEvent = e; - } - else if (status is DequeueStatus.Raised) - { - // Only supported by types (e.g. StateMachine) that allow - // the user to explicitly raise events. - Runtime.NotifyHandleRaisedEvent(this, e); - } - else if (status is DequeueStatus.Default) - { - Runtime.LogWriter.LogDefaultEventHandler(Id, CurrentStateName); - - // If the default event was dequeued, then notify the runtime. - // This is only used during bug-finding, because the runtime must - // instrument a scheduling point between default event handlers. - Runtime.NotifyDefaultEventDequeued(this); - } - else if (status is DequeueStatus.NotAvailable) - { - // Terminate the handler as there is no event available. - break; - } - - if (CurrentStatus is Status.Active) - { - // Handles the next event, if the actor is not halted. - await HandleEventAsync(e); - } - - if (!Inbox.IsEventRaised && lastDequeuedEvent != null && CurrentStatus != Status.Halted) - { - // Inform the user that the actor handled the dequeued event. - await InvokeUserCallbackAsync(UserCallbackType.OnEventHandled, lastDequeuedEvent); - lastDequeuedEvent = null; - } - - if (CurrentStatus is Status.Halting) - { - // If the current status is halting, then halt the actor. - await HaltAsync(e); - } - } - } - - /// - /// Handles the specified . - /// - private protected virtual async Task HandleEventAsync(Event e) - { - if (ActionMap.TryGetValue(e.GetType(), out var cachedAction) || - ActionMap.TryGetValue(typeof(WildCardEvent), out cachedAction)) - { - Runtime.NotifyInvokedAction(this, cachedAction.MethodInfo, null, null, e); - await InvokeActionAsync(cachedAction, e); - } - else if (e is HaltEvent) - { - // If it is the halt event, then change the actor status to halting. - CurrentStatus = Status.Halting; - } - else - { - await InvokeUserCallbackAsync(UserCallbackType.OnEventUnhandled, e); - if (CurrentStatus is Status.Active) - { - // If the event cannot be handled then report an error, else halt gracefully. - var ex = new UnhandledEventException(e, default, "Unhandled Event"); - var isHalting = OnUnhandledEventExceptionHandler(ex, e); - Assert(isHalting, "{0} received event '{1}' that cannot be handled.", - Id, e.GetType().FullName); - } - } - } - - /// - /// Invokes the specified action delegate. - /// - private protected async Task InvokeActionAsync(CachedDelegate cachedAction, Event e) - { - try - { - if (cachedAction.IsAsync) - { - Task task = null; - if (cachedAction.Handler is Func taskFuncWithEvent) - { - task = taskFuncWithEvent(e); - } - else if (cachedAction.Handler is Func taskFunc) - { - task = taskFunc(); - } - - Runtime.NotifyWaitTask(this, task); - - // We have no reliable stack for awaited operations. - await task; - } - else if (cachedAction.Handler is Action actionWithEvent) - { - actionWithEvent(e); - } - else if (cachedAction.Handler is Action action) - { - action(); - } - } - catch (Exception ex) when (OnExceptionHandler(ex, cachedAction.MethodInfo.Name, e)) - { - // User handled the exception. - await OnExceptionHandledAsync(ex, e); - } - catch (Exception ex) when (!cachedAction.IsAsync && InvokeOnFailureExceptionFilter(cachedAction, ex)) - { - // Use an exception filter to call OnFailure before the stack - // has been unwound. If the exception filter does not fail-fast, - // it returns false to process the exception normally. - } - catch (Exception ex) - { - await TryHandleActionInvocationExceptionAsync(ex, cachedAction.MethodInfo.Name); - } - } - - /// - /// Invokes the specified event handler user callback. - /// - private protected async Task InvokeUserCallbackAsync(string callbackType, Event e, string currentState = default) - { - try - { - Task task = null; - if (callbackType is UserCallbackType.OnInitialize) - { - task = OnInitializeAsync(e); - } - else if (callbackType is UserCallbackType.OnEventDequeued) - { - task = OnEventDequeuedAsync(e); - } - else if (callbackType is UserCallbackType.OnEventHandled) - { - task = OnEventHandledAsync(e); - } - else if (callbackType is UserCallbackType.OnEventUnhandled) - { - task = OnEventUnhandledAsync(e, currentState); - } - - Runtime.NotifyWaitTask(this, task); - await task; - } - catch (Exception ex) when (OnExceptionHandler(ex, callbackType, e)) - { - // User handled the exception. - await OnExceptionHandledAsync(ex, e); - } - catch (Exception ex) - { - // Reports the unhandled exception. - await TryHandleActionInvocationExceptionAsync(ex, callbackType); - } - } - - /// - /// An exception filter that calls, - /// which can choose to fast-fail the app to get a full dump. - /// - /// The action being executed when the failure occurred. - /// The exception being tested. - private protected bool InvokeOnFailureExceptionFilter(CachedDelegate action, Exception ex) - { - // This is called within the exception filter so the stack has not yet been unwound. - // If the call does not fail-fast, return false to process the exception normally. - Runtime.RaiseOnFailureEvent(new ActionExceptionFilterException(action.MethodInfo.Name, ex)); - return false; - } - - /// - /// Tries to handle an exception thrown during an action invocation. - /// - private protected Task TryHandleActionInvocationExceptionAsync(Exception ex, string actionName) - { - var innerException = ex; - while (innerException is TargetInvocationException) - { - innerException = innerException.InnerException; - } - - if (innerException is AggregateException) - { - innerException = innerException.InnerException; - } - - if (innerException is ExecutionCanceledException || innerException is TaskSchedulerException) - { - CurrentStatus = Status.Halted; - Debug.WriteLine($" {innerException.GetType().Name} was thrown from {Id}."); - } - else - { - // Reports the unhandled exception. - ReportUnhandledException(innerException, actionName); - } - - return Task.CompletedTask; - } - - /// - /// Checks if the specified event is ignored. - /// - internal bool IsEventIgnored(Event e) - { - return false; - } - - /// - /// Returns the hashed state of this actor. - /// - internal virtual int GetHashedState() - { - unchecked - { - var hash = 19; - hash = (hash * 31) + GetType().GetHashCode(); - hash = (hash * 31) + Id.Value.GetHashCode(); - hash = (hash * 31) + IsHalted.GetHashCode(); - - hash = (hash * 31) + Manager.GetCachedState(); - hash = (hash * 31) + Inbox.GetCachedState(); - - if (this.HashedState != 0) - { - // Adds the user-defined hashed state. - hash = (hash * 31) + HashedState; - } - - return hash; - } - } - - /// - /// Extracts user declarations and sets up the event handlers. - /// - internal virtual void SetupEventHandlers() - { - if (!ActionCache.ContainsKey(GetType())) - { - var actorTypes = new Stack(); - for (var actorType = GetType(); typeof(Actor).IsAssignableFrom(actorType); actorType = actorType.BaseType) - { - actorTypes.Push(actorType); - } - - // process base types in reverse order, so mosts derrived type is cached first. - while (actorTypes.Count > 0) - { - SetupEventHandlers(actorTypes.Pop()); - } - } - - // Now we have all derrived types cached, we can build the combined action map for this type. - for (var actorType = GetType(); typeof(Actor).IsAssignableFrom(actorType); actorType = actorType.BaseType) - { - // Populates the map of event handlers for this actor instance. - foreach (var kvp in ActionCache[actorType]) - { - // use the most derrived action handler for a given event (ignoring any base handlers defined for the same event). - if (!ActionMap.ContainsKey(kvp.Key)) - { - // MethodInfo.Invoke catches the exception to wrap it in a TargetInvocationException. - // This unwinds the stack before the ExecuteAction exception filter is invoked, so - // call through a delegate instead (which is also much faster than Invoke). - ActionMap.Add(kvp.Key, new CachedDelegate(kvp.Value, this)); - } - } - } - } - - private void SetupEventHandlers(Type actorType) - { - // If this type has not already been setup in the ActionCache, then we need to try and grab the ActionCacheLock - // for this type. First make sure we have one and only one lockable object for this type. - var syncObject = ActionCacheLocks.GetOrAdd(actorType, _ => new object()); - - // Locking this syncObject ensures only one thread enters the initialization code to update - // the ActionCache for this specific Actor type. - lock (syncObject) - { - if (ActionCache.ContainsKey(actorType)) - { - // Note: even if we won the GetOrAdd, there is a tiny window of opportunity for another thread - // to slip in and lock the syncObject before us, so we have to check the ActionCache again - // here just in case. - } - else - { - // Events with already declared handlers. - var handledEvents = new HashSet(); - - // Map containing all action bindings. - var actionBindings = new Dictionary(); - var doAttributes = actorType.GetCustomAttributes(typeof(OnEventDoActionAttribute), false) - as OnEventDoActionAttribute[]; - - foreach (var attr in doAttributes) - { - Assert(!handledEvents.Contains(attr.Event), - "{0} declared multiple handlers for event '{1}'.", - actorType.FullName, attr.Event); - actionBindings.Add(attr.Event, new ActionEventHandlerDeclaration(attr.Action)); - handledEvents.Add(attr.Event); - } - - var map = new Dictionary(); - foreach (var action in actionBindings) - { - if (!map.ContainsKey(action.Key)) - { - map.Add(action.Key, GetActionWithName(action.Value.Name)); - } - } - - // Caches the action declarations for this actor type. - ActionCache.TryAdd(actorType, map); - } - } - } - - /// - /// Returns the set of all registered events (for code coverage). - /// It does not include events that are deferred or ignored. - /// - internal HashSet GetAllRegisteredEvents() - { - return new HashSet(from key in ActionMap.Keys select key.FullName); - } - - /// - /// Returns the action with the specified name. - /// - private protected MethodInfo GetActionWithName(string actionName) - { - MethodInfo action; - var actorType = GetType(); - - do - { - var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | - BindingFlags.Instance | BindingFlags.FlattenHierarchy; - action = actorType.GetMethod(actionName, bindingFlags, Type.DefaultBinder, SingleEventTypeArray, null); - if (action is null) - { - action = actorType.GetMethod(actionName, bindingFlags, Type.DefaultBinder, Array.Empty(), null); - } - - actorType = actorType.BaseType; - } - while (action is null && actorType != typeof(StateMachine) && actorType != typeof(Actor)); - - Assert(action != null, "Cannot detect action declaration '{0}' in '{1}'.", actionName, GetType().FullName); - AssertActionValidity(action); - return action; - } - - /// - /// Checks the validity of the specified action. - /// - private void AssertActionValidity(MethodInfo action) - { - var actionType = action.DeclaringType; - var parameters = action.GetParameters(); - Assert(parameters.Length is 0 || - (parameters.Length is 1 && parameters[0].ParameterType == typeof(Event)), - "Action '{0}' in '{1}' must either accept no parameters or a single parameter of type 'Event'.", - action.Name, actionType.Name); - - // Check if the action is an 'async' method. - if (action.GetCustomAttribute(typeof(AsyncStateMachineAttribute)) != null) - { - Assert(action.ReturnType == typeof(Task), - "Async action '{0}' in '{1}' must have 'Task' return type.", - action.Name, actionType.Name); - } - else - { - Assert(action.ReturnType == typeof(void), - "Action '{0}' in '{1}' must have 'void' return type.", - action.Name, actionType.Name); - } - } - - /// - /// Returns the formatted strint to be used with a fair nondeterministic boolean choice. - /// - private protected virtual string FormatFairRandom(string callerMemberName, string callerFilePath, int callerLineNumber) => - string.Format(CultureInfo.InvariantCulture, "{0}_{1}_{2}_{3}", - Id.Name, callerMemberName, callerFilePath, callerLineNumber.ToString()); - - /// - /// Wraps the unhandled exception inside an - /// exception, and throws it to the user. - /// - private protected virtual void ReportUnhandledException(Exception ex, string actionName) - { - Runtime.WrapAndThrowException(ex, $"{0} (action '{1}')", Id, actionName); - } - - /// - /// Invokes user callback when the actor throws an exception. - /// - /// The exception thrown by the actor. - /// The handler (outermost) that threw the exception. - /// The event being handled when the exception was thrown. - /// True if the exception was handled, else false if it should continue to get thrown. - private protected bool OnExceptionHandler(Exception ex, string methodName, Event e) - { - if (ex is ExecutionCanceledException) - { - // Internal exception used during testing. - return false; - } - - Runtime.LogWriter.LogExceptionThrown(Id, CurrentStateName, methodName, ex); - - var outcome = OnException(ex, methodName, e); - if (outcome is OnExceptionOutcome.ThrowException) - { - return false; - } - else if (outcome is OnExceptionOutcome.Halt) - { - CurrentStatus = Status.Halting; - } - - Runtime.LogWriter.LogExceptionHandled(Id, CurrentStateName, methodName, ex); - return true; - } - - /// - /// Invokes user callback when the actor receives an event that it cannot handle. - /// - /// The exception thrown by the actor. - /// The unhandled event. - /// True if the the actor should gracefully halt, else false if the exception - /// should continue to get thrown. - private protected bool OnUnhandledEventExceptionHandler(UnhandledEventException ex, Event e) - { - Runtime.LogWriter.LogExceptionThrown(Id, ex.CurrentStateName, string.Empty, ex); - - var outcome = OnException(ex, string.Empty, e); - if (outcome is OnExceptionOutcome.ThrowException) - { - return false; - } - - CurrentStatus = Status.Halting; - Runtime.LogWriter.LogExceptionHandled(Id, ex.CurrentStateName, string.Empty, ex); - return true; - } - - /// - /// User callback when the actor throws an exception. By default, - /// the actor throws the exception causing the runtime to fail. - /// - /// The exception thrown by the actor. - /// The handler (outermost) that threw the exception. - /// The event being handled when the exception was thrown. - /// The action that the runtime should take. - protected virtual OnExceptionOutcome OnException(Exception ex, string methodName, Event e) - { - return OnExceptionOutcome.ThrowException; - } - - /// - /// Halts the actor. - /// - /// The event being handled when the actor halts. - private protected Task HaltAsync(Event e) - { - CurrentStatus = Status.Halted; - - // Close the inbox, which will stop any subsequent enqueues. - Inbox.Close(); - - Runtime.LogWriter.LogHalt(Id, Inbox.Size); - - // Dispose any held resources. - Inbox.Dispose(); - - // Invoke user callback. - return OnHaltAsync(e); - } - - /// - /// Determines whether the specified object is equal to the current object. - /// - public override bool Equals(object obj) - { - if (obj is Actor m && - GetType() == m.GetType()) - { - return Id.Value == m.Id.Value; - } - - return false; - } - - /// - /// Returns the hash code for this instance. - /// - public override int GetHashCode() - { - return Id.Value.GetHashCode(); - } - - /// - /// Returns a string that represents the current actor. - /// - public override string ToString() - { - return Id.Name; - } - - /// - /// The status of the actor. - /// - private protected enum Status - { - /// - /// The actor is active. - /// - Active = 0, - - /// - /// The actor is halting. - /// - Halting, - - /// - /// The actor is halted. - /// - Halted - } - - /// - /// The type of a user callback. - /// - private protected static class UserCallbackType - { - internal const string OnInitialize = nameof(OnInitializeAsync); - internal const string OnEventDequeued = nameof(OnEventDequeuedAsync); - internal const string OnEventHandled = nameof(OnEventHandledAsync); - internal const string OnEventUnhandled = nameof(OnEventUnhandledAsync); - internal const string OnExceptionHandled = nameof(OnExceptionHandledAsync); - internal const string OnHalt = nameof(OnHaltAsync); - } - - /// - /// Attribute for declaring which action should be invoked - /// to handle a dequeued event of the specified type. - /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] - protected sealed class OnEventDoActionAttribute : Attribute - { - /// - /// The type of the dequeued event. - /// - internal Type Event; - - /// - /// The name of the action to invoke. - /// - internal string Action; - - /// - /// Initializes a new instance of the class. - /// - /// The type of the dequeued event. - /// The name of the action to invoke. - public OnEventDoActionAttribute(Type eventType, string actionName) - { - Event = eventType; - Action = actionName; - } - } - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Actors/ActorFactory.cs b/Src/PChecker/CheckerCore/Actors/ActorFactory.cs deleted file mode 100644 index 7f6929b45f..0000000000 --- a/Src/PChecker/CheckerCore/Actors/ActorFactory.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -using System.Linq.Expressions; - -namespace PChecker.Actors -{ - /// - /// Factory for creating actor instances. - /// - internal static class ActorFactory - { - /// - /// Cache storing actors constructors. - /// - private static readonly Dictionary> ActorConstructorCache = - new Dictionary>(); - - /// - /// Creates a new instance of the specified type. - /// - /// The type of the actors. - /// The created actor instance. - public static Actor Create(Type type) - { - Func constructor = null; - lock (ActorConstructorCache) - { - if (!ActorConstructorCache.TryGetValue(type, out constructor)) - { - var constructorInfo = type.GetConstructor(Type.EmptyTypes); - if (constructorInfo == null) - { - throw new Exception("Could not find empty constructor for type " + type.FullName); - } - - constructor = Expression.Lambda>( - Expression.New(constructorInfo)).Compile(); - ActorConstructorCache.Add(type, constructor); - } - } - - return constructor(); - } - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Actors/ActorRuntime.cs b/Src/PChecker/CheckerCore/Actors/ActorRuntime.cs deleted file mode 100644 index 1959d9c76e..0000000000 --- a/Src/PChecker/CheckerCore/Actors/ActorRuntime.cs +++ /dev/null @@ -1,728 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; -using PChecker.Actors.EventQueues; -using PChecker.Actors.Events; -using PChecker.Actors.Exceptions; -using PChecker.Actors.Logging; -using PChecker.Actors.Managers; -using PChecker.Random; -using PChecker.Runtime; -using PChecker.Specifications.Monitors; -using EventInfo = PChecker.Actors.Events.EventInfo; - -namespace PChecker.Actors -{ - /// - /// Runtime for creating and executing actors. - /// - internal class ActorRuntime : CoyoteRuntime, IActorRuntime - { - /// - /// Map from unique actor ids to actors. - /// - private readonly ConcurrentDictionary ActorMap; - - /// - /// Responsible for writing to all registered objects. - /// - protected internal LogWriter LogWriter { get; private set; } - - /// - /// Used to log text messages. Use - /// to replace the logger with a custom one. - /// - public override TextWriter Logger => LogWriter.Logger; - - /// - /// Used to log json trace outputs. - /// - public JsonWriter JsonLogger => LogWriter.JsonLogger; - - /// - /// Callback that is fired when a Coyote event is dropped. - /// - public event OnEventDroppedHandler OnEventDropped; - - /// - /// Initializes a new instance of the class. - /// - internal ActorRuntime(CheckerConfiguration checkerConfiguration, IRandomValueGenerator valueGenerator) - : base(checkerConfiguration, valueGenerator) - { - ActorMap = new ConcurrentDictionary(); - LogWriter = new LogWriter(checkerConfiguration); - } - - /// - /// Creates a fresh actor id that has not yet been bound to any actor. - /// - public ActorId CreateActorId(Type type, string name = null) => new ActorId(type, name, this); - - /// - /// Creates a actor id that is uniquely tied to the specified unique name. The - /// returned actor id can either be a fresh id (not yet bound to any actor), or - /// it can be bound to a previously created actor. In the second case, this actor - /// id can be directly used to communicate with the corresponding actor. - /// - public virtual ActorId CreateActorIdFromName(Type type, string name) => new ActorId(type, name, this, true); - - /// - /// Creates a new actor of the specified and with the specified - /// optional . This event can only be used to access its payload, - /// and cannot be handled. - /// - public virtual ActorId CreateActor(Type type, Event initialEvent = null, Guid opGroupId = default) => - CreateActor(null, type, null, initialEvent, null, opGroupId); - - /// - /// Creates a new actor of the specified and name, and with the - /// specified optional . This event can only be used to access - /// its payload, and cannot be handled. - /// - public virtual ActorId CreateActor(Type type, string name, Event initialEvent = null, Guid opGroupId = default) => - CreateActor(null, type, name, initialEvent, null, opGroupId); - - /// - /// Creates a new actor of the specified type, using the specified . - /// This method optionally passes an to the new actor, which can only - /// be used to access its payload, and cannot be handled. - /// - public virtual ActorId CreateActor(ActorId id, Type type, Event initialEvent = null, Guid opGroupId = default) => - CreateActor(id, type, null, initialEvent, null, opGroupId); - - /// - /// Creates a new actor of the specified and with the specified - /// optional . This event can only be used to access its payload, - /// and cannot be handled. The method returns only when the actor is initialized and - /// the (if any) is handled. - /// - public virtual Task CreateActorAndExecuteAsync(Type type, Event initialEvent = null, Guid opGroupId = default) => - CreateActorAndExecuteAsync(null, type, null, initialEvent, null, opGroupId); - - /// - /// Creates a new actor of the specified and name, and with the - /// specified optional . This event can only be used to access - /// its payload, and cannot be handled. The method returns only when the actor is - /// initialized and the (if any) is handled. - /// - public virtual Task CreateActorAndExecuteAsync(Type type, string name, Event initialEvent = null, - Guid opGroupId = default) => - CreateActorAndExecuteAsync(null, type, name, initialEvent, null, opGroupId); - - /// - /// Creates a new actor of the specified , using the specified unbound - /// actor id, and passes the specified optional . This event can only - /// be used to access its payload, and cannot be handled. The method returns only when - /// the actor is initialized and the (if any) - /// is handled. - /// - public virtual Task CreateActorAndExecuteAsync(ActorId id, Type type, Event initialEvent = null, - Guid opGroupId = default) => - CreateActorAndExecuteAsync(id, type, null, initialEvent, null, opGroupId); - - /// - /// Sends an asynchronous to an actor. - /// - public virtual void SendEvent(ActorId targetId, Event initialEvent, Guid opGroupId = default) => - SendEvent(targetId, initialEvent, null, opGroupId); - - /// - /// Sends an to an actor. Returns immediately if the target was already - /// running. Otherwise blocks until the target handles the event and reaches quiescense. - /// - public virtual Task SendEventAndExecuteAsync(ActorId targetId, Event initialEvent, - Guid opGroupId = default) => - SendEventAndExecuteAsync(targetId, initialEvent, null, opGroupId); - - /// - /// Returns the operation group id of the actor with the specified id. Returns - /// if the id is not set, or if the is not associated with this runtime. During - /// testing, the runtime asserts that the specified actor is currently executing. - /// - public virtual Guid GetCurrentOperationGroupId(ActorId currentActorId) - { - var actor = GetActorWithId(currentActorId); - return actor is null ? Guid.Empty : actor.OperationGroupId; - } - - /// - /// Creates a new of the specified . - /// - internal virtual ActorId CreateActor(ActorId id, Type type, string name, Event initialEvent, - Actor creator, Guid opGroupId) - { - var actor = CreateActor(id, type, name, creator, opGroupId); - if (actor is StateMachine) - { - LogWriter.LogCreateStateMachine(actor.Id, creator?.Id.Name, creator?.Id.Type); - } - else - { - LogWriter.LogCreateActor(actor.Id, creator?.Id.Name, creator?.Id.Type); - } - - RunActorEventHandler(actor, initialEvent, true); - return actor.Id; - } - - /// - /// Creates a new of the specified . The method - /// returns only when the actor is initialized and the (if any) - /// is handled. - /// - internal virtual async Task CreateActorAndExecuteAsync(ActorId id, Type type, string name, - Event initialEvent, Actor creator, Guid opGroupId) - { - var actor = CreateActor(id, type, name, creator, opGroupId); - if (actor is StateMachine) - { - LogWriter.LogCreateStateMachine(actor.Id, creator?.Id.Name, creator?.Id.Type); - } - else - { - LogWriter.LogCreateActor(actor.Id, creator?.Id.Name, creator?.Id.Type); - } - - await RunActorEventHandlerAsync(actor, initialEvent, true); - return actor.Id; - } - - /// - /// Creates a new of the specified . - /// - private Actor CreateActor(ActorId id, Type type, string name, Actor creator, Guid opGroupId) - { - if (!type.IsSubclassOf(typeof(Actor))) - { - Assert(false, "Type '{0}' is not an actor.", type.FullName); - } - - if (id is null) - { - id = new ActorId(type, name, this); - } - else if (id.Runtime != null && id.Runtime != this) - { - Assert(false, "Unbound actor id '{0}' was created by another runtime.", id.Value); - } - else if (id.Type != type.FullName) - { - Assert(false, "Cannot bind actor id '{0}' of type '{1}' to an actor of type '{2}'.", - id.Value, id.Type, type.FullName); - } - else - { - id.Bind(this); - } - - // The operation group id of the actor is set using the following precedence: - // (1) To the specified actor creation operation group id, if it is non-empty. - // (2) To the operation group id of the creator actor, if it exists. - // (3) To the empty operation group id. - if (opGroupId == Guid.Empty && creator != null) - { - opGroupId = creator.OperationGroupId; - } - - var actor = ActorFactory.Create(type); - IActorManager actorManager; - if (actor is StateMachine stateMachine) - { - actorManager = new StateMachineManager(this, stateMachine, opGroupId); - } - else - { - actorManager = new ActorManager(this, actor, opGroupId); - } - - IEventQueue eventQueue = new EventQueue(actorManager); - actor.Configure(this, id, actorManager, eventQueue); - actor.SetupEventHandlers(); - - if (!ActorMap.TryAdd(id, actor)) - { - var info = "This typically occurs if either the actor id was created by another runtime instance, " + - "or if a actor id from a previous runtime generation was deserialized, but the current runtime " + - "has not increased its generation value."; - Assert(false, "An actor with id '{0}' was already created in generation '{1}'. {2}", id.Value, id.Generation, info); - } - - return actor; - } - - /// - /// Sends an asynchronous to an actor. - /// - internal virtual void SendEvent(ActorId targetId, Event e, Actor sender, Guid opGroupId) - { - var enqueueStatus = EnqueueEvent(targetId, e, sender, opGroupId, out var target); - if (enqueueStatus is EnqueueStatus.EventHandlerNotRunning) - { - RunActorEventHandler(target, null, false); - } - } - - /// - /// Sends an asynchronous to an actor. Returns immediately if the target was - /// already running. Otherwise blocks until the target handles the event and reaches quiescense. - /// - internal virtual async Task SendEventAndExecuteAsync(ActorId targetId, Event e, Actor sender, - Guid opGroupId) - { - var enqueueStatus = EnqueueEvent(targetId, e, sender, opGroupId, out var target); - if (enqueueStatus is EnqueueStatus.EventHandlerNotRunning) - { - await RunActorEventHandlerAsync(target, null, false); - return true; - } - - return enqueueStatus is EnqueueStatus.Dropped; - } - - /// - /// Enqueues an event to the actor with the specified id. - /// - private EnqueueStatus EnqueueEvent(ActorId targetId, Event e, Actor sender, Guid opGroupId, out Actor target) - { - if (e is null) - { - var message = sender != null ? - string.Format("{0} is sending a null event.", sender.Id.ToString()) : - "Cannot send a null event."; - Assert(false, message); - } - - if (targetId is null) - { - var message = (sender != null) ? $"{sender.Id.ToString()} is sending event {e.ToString()} to a null actor." - : $"Cannot send event {e.ToString()} to a null actor."; - - Assert(false, message); - } - - // The operation group id of this operation is set using the following precedence: - // (1) To the specified send operation group id, if it is non-empty. - // (2) To the operation group id of the sender actor, if it exists and is non-empty. - // (3) To the empty operation group id. - if (opGroupId == Guid.Empty && sender != null) - { - opGroupId = sender.OperationGroupId; - } - - target = GetActorWithId(targetId); - if (target is null || target.IsHalted) - { - LogWriter.LogSendEvent(targetId, sender?.Id.Name, sender?.Id.Type, - (sender as StateMachine)?.CurrentStateName ?? string.Empty, e, opGroupId, isTargetHalted: true); - TryHandleDroppedEvent(e, targetId); - return EnqueueStatus.Dropped; - } - - LogWriter.LogSendEvent(targetId, sender?.Id.Name, sender?.Id.Type, - (sender as StateMachine)?.CurrentStateName ?? string.Empty, e, opGroupId, isTargetHalted: false); - - var enqueueStatus = target.Enqueue(e, opGroupId, null); - if (enqueueStatus == EnqueueStatus.Dropped) - { - TryHandleDroppedEvent(e, targetId); - } - - return enqueueStatus; - } - - /// - /// Runs a new asynchronous actor event handler. - /// This is a fire and forget invocation. - /// - private void RunActorEventHandler(Actor actor, Event initialEvent, bool isFresh) - { - Task.Run(async () => - { - try - { - if (isFresh) - { - await actor.InitializeAsync(initialEvent); - } - - await actor.RunEventHandlerAsync(); - } - catch (Exception ex) - { - IsRunning = false; - RaiseOnFailureEvent(ex); - } - finally - { - if (actor.IsHalted) - { - ActorMap.TryRemove(actor.Id, out var _); - } - } - }); - } - - /// - /// Runs a new asynchronous actor event handler. - /// - private async Task RunActorEventHandlerAsync(Actor actor, Event initialEvent, bool isFresh) - { - try - { - if (isFresh) - { - await actor.InitializeAsync(initialEvent); - } - - await actor.RunEventHandlerAsync(); - } - catch (Exception ex) - { - IsRunning = false; - RaiseOnFailureEvent(ex); - return; - } - } - - /// - internal override void TryCreateMonitor(Type type) - { - lock (Monitors) - { - if (Monitors.Any(m => m.GetType() == type)) - { - // Idempotence: only one monitor per type can exist. - return; - } - } - - Assert(type.IsSubclassOf(typeof(Monitor)), "Type '{0}' is not a subclass of Monitor.", type.FullName); - - var monitor = (Monitor)Activator.CreateInstance(type); - monitor.Initialize(this); - monitor.InitializeStateInformation(); - - lock (Monitors) - { - Monitors.Add(monitor); - } - - LogWriter.LogCreateMonitor(type.FullName); - - monitor.GotoStartState(); - } - - /// - internal override bool GetNondeterministicBooleanChoice(int maxValue, string callerName, string callerType) - { - var result = false; - if (ValueGenerator.Next(maxValue) == 0) - { - result = true; - } - - LogWriter.LogRandom(result, callerName, callerType); - return result; - } - - /// - internal override int GetNondeterministicIntegerChoice(int maxValue, string callerName, string callerType) - { - var result = ValueGenerator.Next(maxValue); - LogWriter.LogRandom(result, callerName, callerType); - return result; - } - - /// - /// Gets the actor of type with the specified id, - /// or null if no such actor exists. - /// - private TActor GetActorWithId(ActorId id) - where TActor : Actor => - id != null && ActorMap.TryGetValue(id, out var value) && - value is TActor actor ? actor : null; - - /// - /// Notifies that an actor invoked an action. - /// - internal virtual void NotifyInvokedAction(Actor actor, MethodInfo action, string handlingStateName, - string currentStateName, Event receivedEvent) - { - if (CheckerConfiguration.IsVerbose) - { - LogWriter.LogExecuteAction(actor.Id, handlingStateName, currentStateName, action.Name); - } - } - - /// - /// Notifies that an actor dequeued an . - /// - internal virtual void NotifyDequeuedEvent(Actor actor, Event e, EventInfo eventInfo) - { - if (CheckerConfiguration.IsVerbose) - { - var stateName = actor is StateMachine stateMachine ? stateMachine.CurrentStateName : string.Empty; - LogWriter.LogDequeueEvent(actor.Id, stateName, e); - } - } - - /// - /// Notifies that an actor dequeued the default . - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal virtual void NotifyDefaultEventDequeued(Actor actor) - { - } - - /// - /// Notifies that the inbox of the specified actor is about to be - /// checked to see if the default event handler should fire. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal virtual void NotifyDefaultEventHandlerCheck(Actor actor) - { - } - - /// - /// Notifies that an actor raised an . - /// - internal virtual void NotifyRaisedEvent(Actor actor, Event e, EventInfo eventInfo) - { - if (CheckerConfiguration.IsVerbose) - { - var stateName = actor is StateMachine stateMachine ? stateMachine.CurrentStateName : string.Empty; - LogWriter.LogRaiseEvent(actor.Id, stateName, e); - } - } - - /// - /// Notifies that an actor is handling a raised . - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal virtual void NotifyHandleRaisedEvent(Actor actor, Event e) - { - } - - /// - /// Notifies that an actor called - /// or one of its overloaded methods. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal virtual void NotifyReceiveCalled(Actor actor) - { - } - - /// - /// Notifies that an actor enqueued an event that it was waiting to receive. - /// - internal virtual void NotifyReceivedEvent(Actor actor, Event e, EventInfo eventInfo) - { - if (CheckerConfiguration.IsVerbose) - { - var stateName = actor is StateMachine stateMachine ? stateMachine.CurrentStateName : string.Empty; - LogWriter.LogReceiveEvent(actor.Id, stateName, e, wasBlocked: true); - } - } - - /// - /// Notifies that an actor received an event without waiting because the event - /// was already in the inbox when the actor invoked the receive statement. - /// - internal virtual void NotifyReceivedEventWithoutWaiting(Actor actor, Event e, EventInfo eventInfo) - { - if (CheckerConfiguration.IsVerbose) - { - var stateName = actor is StateMachine stateMachine ? stateMachine.CurrentStateName : string.Empty; - LogWriter.LogReceiveEvent(actor.Id, stateName, e, wasBlocked: false); - } - } - - /// - /// Notifies that an actor is waiting for the specified task to complete. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal virtual void NotifyWaitTask(Actor actor, Task task) - { - } - - /// - /// Notifies that an actor is waiting to receive an event of one of the specified types. - /// - internal virtual void NotifyWaitEvent(Actor actor, IEnumerable eventTypes) - { - if (CheckerConfiguration.IsVerbose) - { - var stateName = actor is StateMachine stateMachine ? stateMachine.CurrentStateName : string.Empty; - var eventWaitTypesArray = eventTypes.ToArray(); - if (eventWaitTypesArray.Length == 1) - { - LogWriter.LogWaitEvent(actor.Id, stateName, eventWaitTypesArray[0]); - } - else - { - LogWriter.LogWaitEvent(actor.Id, stateName, eventWaitTypesArray); - } - } - } - - /// - /// Notifies that a state machine entered a state. - /// - internal virtual void NotifyEnteredState(StateMachine stateMachine) - { - if (CheckerConfiguration.IsVerbose) - { - LogWriter.LogStateTransition(stateMachine.Id, stateMachine.CurrentStateName, isEntry: true); - } - } - - /// - /// Notifies that a state machine exited a state. - /// - internal virtual void NotifyExitedState(StateMachine stateMachine) - { - if (CheckerConfiguration.IsVerbose) - { - LogWriter.LogStateTransition(stateMachine.Id, stateMachine.CurrentStateName, isEntry: false); - } - } - - /// - /// Notifies that a state machine invoked pop. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal virtual void NotifyPopState(StateMachine stateMachine) - { - } - - /// - /// Notifies that a state machine invoked an action. - /// - internal virtual void NotifyInvokedOnEntryAction(StateMachine stateMachine, MethodInfo action, Event receivedEvent) - { - if (CheckerConfiguration.IsVerbose) - { - LogWriter.LogExecuteAction(stateMachine.Id, stateMachine.CurrentStateName, - stateMachine.CurrentStateName, action.Name); - } - } - - /// - /// Notifies that a state machine invoked an action. - /// - internal virtual void NotifyInvokedOnExitAction(StateMachine stateMachine, MethodInfo action, Event receivedEvent) - { - if (CheckerConfiguration.IsVerbose) - { - LogWriter.LogExecuteAction(stateMachine.Id, stateMachine.CurrentStateName, - stateMachine.CurrentStateName, action.Name); - } - } - - /// - /// Notifies that a monitor entered a state. - /// - internal virtual void NotifyEnteredState(Monitor monitor) - { - if (CheckerConfiguration.IsVerbose) - { - var monitorState = monitor.CurrentStateNameWithTemperature; - LogWriter.LogMonitorStateTransition(monitor.GetType().FullName, monitorState, - true, monitor.GetHotState()); - } - } - - /// - /// Notifies that a monitor exited a state. - /// - internal virtual void NotifyExitedState(Monitor monitor) - { - if (CheckerConfiguration.IsVerbose) - { - var monitorState = monitor.CurrentStateNameWithTemperature; - LogWriter.LogMonitorStateTransition(monitor.GetType().FullName, monitorState, - false, monitor.GetHotState()); - } - } - - /// - /// Notifies that a monitor invoked an action. - /// - internal virtual void NotifyInvokedAction(Monitor monitor, MethodInfo action, string stateName, Event receivedEvent) - { - if (CheckerConfiguration.IsVerbose) - { - LogWriter.LogMonitorExecuteAction(monitor.GetType().FullName, action.Name, stateName); - } - } - - /// - /// Notifies that a monitor raised an . - /// - internal virtual void NotifyRaisedEvent(Monitor monitor, Event e) - { - if (CheckerConfiguration.IsVerbose) - { - var monitorState = monitor.CurrentStateNameWithTemperature; - LogWriter.LogMonitorRaiseEvent(monitor.GetType().FullName, monitorState, e); - } - } - - /// - /// Notifies that a monitor found an error. - /// - internal void NotifyMonitorError(Monitor monitor) - { - if (CheckerConfiguration.IsVerbose) - { - var monitorState = monitor.CurrentStateNameWithTemperature; - LogWriter.LogMonitorError(monitor.GetType().FullName, monitorState, monitor.GetHotState()); - } - } - - /// - /// Tries to handle the specified dropped . - /// - internal void TryHandleDroppedEvent(Event e, ActorId id) => OnEventDropped?.Invoke(e, id); - - /// - public override TextWriter SetLogger(TextWriter logger) => LogWriter.SetLogger(logger); - - /// - /// Sets the JsonLogger in LogWriter.cs - /// - /// jsonLogger instance - public void SetJsonLogger(JsonWriter jsonLogger) => LogWriter.SetJsonLogger(jsonLogger); - - /// - /// Use this method to register an . - /// - public void RegisterLog(IActorRuntimeLog log) => LogWriter.RegisterLog(log); - - /// - /// Use this method to unregister a previously registered . - /// - public void RemoveLog(IActorRuntimeLog log) => LogWriter.RemoveLog(log); - - /// - protected override void Dispose(bool disposing) - { - if (disposing) - { - Monitors.Clear(); - ActorMap.Clear(); - } - - base.Dispose(disposing); - } - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Actors/EventQueues/EventQueue.cs b/Src/PChecker/CheckerCore/Actors/EventQueues/EventQueue.cs deleted file mode 100644 index fa35a4758f..0000000000 --- a/Src/PChecker/CheckerCore/Actors/EventQueues/EventQueue.cs +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using PChecker.Actors.Events; -using PChecker.Actors.Managers; - -namespace PChecker.Actors.EventQueues -{ - /// - /// Implements a queue of events. - /// - internal sealed class EventQueue : IEventQueue - { - /// - /// Manages the actor that owns this queue. - /// - private readonly IActorManager ActorManager; - - /// - /// The internal queue. - /// - private readonly LinkedList<(Event e, Guid opGroupId)> Queue; - - /// - /// The raised event and its metadata, or null if no event has been raised. - /// - private (Event e, Guid opGroupId) RaisedEvent; - - /// - /// Map from the types of events that the owner of the queue is waiting to receive - /// to an optional predicate. If an event of one of these types is enqueued, then - /// if there is no predicate, or if there is a predicate and evaluates to true, then - /// the event is received, else the event is deferred. - /// - private Dictionary> EventWaitTypes; - - /// - /// Task completion source that contains the event obtained using an explicit receive. - /// - private TaskCompletionSource ReceiveCompletionSource; - - /// - /// Checks if the queue is accepting new events. - /// - private bool IsClosed; - - /// - public int Size => Queue.Count; - - /// - public bool IsEventRaised => RaisedEvent != default; - - /// - /// Initializes a new instance of the class. - /// - internal EventQueue(IActorManager actorManager) - { - ActorManager = actorManager; - Queue = new LinkedList<(Event, Guid)>(); - EventWaitTypes = new Dictionary>(); - IsClosed = false; - } - - /// - public EnqueueStatus Enqueue(Event e, Guid opGroupId, EventInfo info) - { - var enqueueStatus = EnqueueStatus.EventHandlerRunning; - lock (Queue) - { - if (IsClosed) - { - return EnqueueStatus.Dropped; - } - - if (EventWaitTypes != null && - EventWaitTypes.TryGetValue(e.GetType(), out var predicate) && - (predicate is null || predicate(e))) - { - EventWaitTypes = null; - enqueueStatus = EnqueueStatus.Received; - } - else - { - Queue.AddLast((e, opGroupId)); - if (!ActorManager.IsEventHandlerRunning) - { - ActorManager.IsEventHandlerRunning = true; - enqueueStatus = EnqueueStatus.EventHandlerNotRunning; - } - } - } - - if (enqueueStatus is EnqueueStatus.Received) - { - ActorManager.OnReceiveEvent(e, opGroupId, info); - ReceiveCompletionSource.SetResult(e); - return enqueueStatus; - } - else - { - ActorManager.OnEnqueueEvent(e, opGroupId, info); - } - - return enqueueStatus; - } - - /// - public (DequeueStatus status, Event e, Guid opGroupId, EventInfo info) Dequeue() - { - // Try to get the raised event, if there is one. Raised events - // have priority over the events in the inbox. - if (RaisedEvent != default) - { - if (ActorManager.IsEventIgnored(RaisedEvent.e, RaisedEvent.opGroupId, null)) - { - // TODO: should the user be able to raise an ignored event? - // The raised event is ignored in the current state. - RaisedEvent = default; - } - else - { - (var e, var opGroupId) = RaisedEvent; - RaisedEvent = default; - return (DequeueStatus.Raised, e, opGroupId, null); - } - } - - lock (Queue) - { - // Try to dequeue the next event, if there is one. - var node = Queue.First; - while (node != null) - { - // Iterates through the events in the inbox. - if (ActorManager.IsEventIgnored(node.Value.e, node.Value.opGroupId, null)) - { - // Removes an ignored event. - var nextNode = node.Next; - Queue.Remove(node); - node = nextNode; - continue; - } - else if (ActorManager.IsEventDeferred(node.Value.e, node.Value.opGroupId, null)) - { - // Skips a deferred event. - node = node.Next; - continue; - } - - // Found next event that can be dequeued. - Queue.Remove(node); - return (DequeueStatus.Success, node.Value.e, node.Value.opGroupId, null); - } - - // No event can be dequeued, so check if there is a default event handler. - if (!ActorManager.IsDefaultHandlerAvailable()) - { - // There is no default event handler installed, so do not return an event. - // Setting IsEventHandlerRunning must happen inside the lock as it needs - // to be synchronized with the enqueue and starting a new event handler. - ActorManager.IsEventHandlerRunning = false; - return (DequeueStatus.NotAvailable, null, Guid.Empty, null); - } - } - - // TODO: check op-id of default event. - // A default event handler exists. - return (DequeueStatus.Default, DefaultEvent.Instance, Guid.Empty, null); - } - - /// - public void RaiseEvent(Event e, Guid opGroupId) - { - RaisedEvent = (e, opGroupId); - ActorManager.OnRaiseEvent(e, opGroupId, null); - } - - //// - public Task ReceiveEventAsync(Type eventType, Func predicate = null) - { - var eventWaitTypes = new Dictionary> - { - { eventType, predicate } - }; - - return ReceiveEventAsync(eventWaitTypes); - } - - /// - public Task ReceiveEventAsync(params Type[] eventTypes) - { - var eventWaitTypes = new Dictionary>(); - foreach (var type in eventTypes) - { - eventWaitTypes.Add(type, null); - } - - return ReceiveEventAsync(eventWaitTypes); - } - - /// - public Task ReceiveEventAsync(params Tuple>[] events) - { - var eventWaitTypes = new Dictionary>(); - foreach (var e in events) - { - eventWaitTypes.Add(e.Item1, e.Item2); - } - - return ReceiveEventAsync(eventWaitTypes); - } - - /// - /// Waits for an event to be enqueued based on the conditions defined in the event wait types. - /// - private Task ReceiveEventAsync(Dictionary> eventWaitTypes) - { - (Event e, Guid opGroupId) receivedEvent = default; - lock (Queue) - { - var node = Queue.First; - while (node != null) - { - // Dequeue the first event that the caller waits to receive, if there is one in the queue. - if (eventWaitTypes.TryGetValue(node.Value.e.GetType(), out var predicate) && - (predicate is null || predicate(node.Value.e))) - { - receivedEvent = node.Value; - Queue.Remove(node); - break; - } - - node = node.Next; - } - - if (receivedEvent == default) - { - ReceiveCompletionSource = new TaskCompletionSource(); - EventWaitTypes = eventWaitTypes; - } - } - - if (receivedEvent == default) - { - // Note that EventWaitTypes is racy, so should not be accessed outside - // the lock, this is why we access eventWaitTypes instead. - ActorManager.OnWaitEvent(eventWaitTypes.Keys); - return ReceiveCompletionSource.Task; - } - - ActorManager.OnReceiveEventWithoutWaiting(receivedEvent.e, receivedEvent.opGroupId, null); - return Task.FromResult(receivedEvent.e); - } - - //// - public int GetCachedState() => 0; - - /// - public void Close() - { - lock (Queue) - { - IsClosed = true; - } - } - - /// - /// Disposes the queue resources. - /// - private void Dispose(bool disposing) - { - if (!disposing) - { - return; - } - - foreach (var (e, opGroupId) in Queue) - { - ActorManager.OnDropEvent(e, opGroupId, null); - } - - Queue.Clear(); - } - - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Actors/Events/Event.cs b/Src/PChecker/CheckerCore/Actors/Events/Event.cs deleted file mode 100644 index a33f298172..0000000000 --- a/Src/PChecker/CheckerCore/Actors/Events/Event.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System.Runtime.Serialization; - -namespace PChecker.Actors.Events -{ - /// - /// Abstract class representing an event. - /// - [DataContract] - public abstract class Event - { - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Actors/Exceptions/OnEventDroppedHandler.cs b/Src/PChecker/CheckerCore/Actors/Exceptions/OnEventDroppedHandler.cs deleted file mode 100644 index a96ad02dc0..0000000000 --- a/Src/PChecker/CheckerCore/Actors/Exceptions/OnEventDroppedHandler.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using PChecker.Actors.Events; - -namespace PChecker.Actors.Exceptions -{ - /// - /// Handles the event. - /// - public delegate void OnEventDroppedHandler(Event e, ActorId target); -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Actors/IActorRuntime.cs b/Src/PChecker/CheckerCore/Actors/IActorRuntime.cs deleted file mode 100644 index c93bb2909c..0000000000 --- a/Src/PChecker/CheckerCore/Actors/IActorRuntime.cs +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Threading.Tasks; -using PChecker.Actors.Events; -using PChecker.Actors.Exceptions; -using PChecker.Actors.Logging; -using PChecker.Runtime; - -namespace PChecker.Actors -{ - /// - /// Interface that exposes runtime methods for creating and executing actors. - /// - public interface IActorRuntime : ICoyoteRuntime - { - /// - /// Callback that is fired when an event is dropped. - /// - event OnEventDroppedHandler OnEventDropped; - - /// - /// Creates a fresh actor id that has not yet been bound to any actor. - /// - /// Type of the actor. - /// Optional name used for logging. - /// The result is the actor id. - ActorId CreateActorId(Type type, string name = null); - - /// - /// Creates a actor id that is uniquely tied to the specified unique name. The - /// returned actor id can either be a fresh id (not yet bound to any actor), or - /// it can be bound to a previously created actor. In the second case, this actor - /// id can be directly used to communicate with the corresponding actor. - /// - /// Type of the actor. - /// Unique name used to create or get the actor id. - /// The result is the actor id. - ActorId CreateActorIdFromName(Type type, string name); - - /// - /// Creates a new actor of the specified and with the specified - /// optional . This event can only be used to access its payload, - /// and cannot be handled. - /// - /// Type of the actor. - /// Optional event used during initialization. - /// Optional id that can be used to identify this operation. - /// The result is the actor id. - ActorId CreateActor(Type type, Event initialEvent = null, Guid opGroupId = default); - - /// - /// Creates a new actor of the specified and name, and with the - /// specified optional . This event can only be used to access - /// its payload, and cannot be handled. - /// - /// Type of the actor. - /// Optional name used for logging. - /// Optional event used during initialization. - /// Optional id that can be used to identify this operation. - /// The result is the actor id. - ActorId CreateActor(Type type, string name, Event initialEvent = null, Guid opGroupId = default); - - /// - /// Creates a new actor of the specified type, using the specified . - /// This method optionally passes an to the new actor, which can only - /// be used to access its payload, and cannot be handled. - /// - /// Unbound actor id. - /// Type of the actor. - /// Optional event used during initialization. - /// Optional id that can be used to identify this operation. - /// The result is the actor id. - ActorId CreateActor(ActorId id, Type type, Event initialEvent = null, Guid opGroupId = default); - - /// - /// Creates a new actor of the specified and with the specified - /// optional . This event can only be used to access its payload, - /// and cannot be handled. The method returns only when the actor is initialized and - /// the (if any) is handled. - /// - /// Type of the actor. - /// Optional event used during initialization. - /// Optional id that can be used to identify this operation. - /// Task that represents the asynchronous operation. The task result is the actor id. - Task CreateActorAndExecuteAsync(Type type, Event initialEvent = null, Guid opGroupId = default); - - /// - /// Creates a new actor of the specified and name, and with the - /// specified optional . This event can only be used to access - /// its payload, and cannot be handled. The method returns only when the actor is - /// initialized and the (if any) is handled. - /// - /// Type of the actor. - /// Optional name used for logging. - /// Optional event used during initialization. - /// Optional id that can be used to identify this operation. - /// Task that represents the asynchronous operation. The task result is the actor id. - Task CreateActorAndExecuteAsync(Type type, string name, Event initialEvent = null, - Guid opGroupId = default); - - /// - /// Creates a new actor of the specified , using the specified unbound - /// actor id, and passes the specified optional . This event can only - /// be used to access its payload, and cannot be handled. The method returns only when - /// the actor is initialized and the (if any) - /// is handled. - /// - /// Unbound actor id. - /// Type of the actor. - /// Optional event used during initialization. - /// Optional id that can be used to identify this operation. - /// Task that represents the asynchronous operation. The task result is the actor id. - Task CreateActorAndExecuteAsync(ActorId id, Type type, Event initialEvent = null, - Guid opGroupId = default); - - /// - /// Sends an asynchronous to an actor. - /// - /// The id of the target. - /// The event to send. - /// Optional id that can be used to identify this operation. - void SendEvent(ActorId targetId, Event e, Guid opGroupId = default); - - /// - /// Sends an to an actor. Returns immediately if the target was already - /// running. Otherwise blocks until the target handles the event and reaches quiescense. - /// - /// The id of the target. - /// The event to send. - /// Optional id that can be used to identify this operation. - /// Task that represents the asynchronous operation. The task result is true if - /// the event was handled, false if the event was only enqueued. - Task SendEventAndExecuteAsync(ActorId targetId, Event e, Guid opGroupId = default); - - /// - /// Returns the operation group id of the actor with the specified id. Returns - /// if the id is not set, or if the is not associated with this runtime. During - /// testing, the runtime asserts that the specified actor is currently executing. - /// - /// The id of the currently executing actor. - /// The unique identifier. - Guid GetCurrentOperationGroupId(ActorId currentActorId); - - /// - /// Use this method to register an . - /// - /// The log writer to register. - void RegisterLog(IActorRuntimeLog log); - - /// - /// Use this method to unregister a previously registered . - /// - /// The previously registered log writer to unregister. - void RemoveLog(IActorRuntimeLog log); - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Actors/Logging/ActorRuntimeLogJsonFormatter.cs b/Src/PChecker/CheckerCore/Actors/Logging/ActorRuntimeLogJsonFormatter.cs deleted file mode 100644 index e1718377d3..0000000000 --- a/Src/PChecker/CheckerCore/Actors/Logging/ActorRuntimeLogJsonFormatter.cs +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using PChecker.Actors.Events; - -namespace PChecker.Actors.Logging -{ - /// - /// This class implements IActorRuntimeLog and generates log output in an XML format. - /// - public class ActorRuntimeLogJsonFormatter : IActorRuntimeLog - { - /// - /// Get or set the JsonWriter to write to. - /// - public JsonWriter Writer { get; set; } - - /// - /// Initializes a new instance of the class. - /// - protected ActorRuntimeLogJsonFormatter() - { - Writer = new JsonWriter(); - } - - /// - public virtual void OnCompleted() - { - } - - /// - public virtual void OnAssertionFailure(string error) - { - } - - /// - public virtual void OnCreateActor(ActorId id, string creatorName, string creatorType) - { - } - - /// - public virtual void OnCreateStateMachine(ActorId id, string creatorName, string creatorType) - { - } - - /// - public virtual void OnDefaultEventHandler(ActorId id, string stateName) - { - } - - /// - public virtual void OnDequeueEvent(ActorId id, string stateName, Event e) - { - } - - /// - public virtual void OnEnqueueEvent(ActorId id, Event e) - { - } - - /// - public virtual void OnExceptionHandled(ActorId id, string stateName, string actionName, Exception ex) - { - } - - /// - public virtual void OnExceptionThrown(ActorId id, string stateName, string actionName, Exception ex) - { - } - - /// - public virtual void OnExecuteAction(ActorId id, string handlingStateName, string currentStateName, - string actionName) - { - } - - /// - public virtual void OnGotoState(ActorId id, string currentStateName, string newStateName) - { - } - - /// - public virtual void OnHalt(ActorId id, int inboxSize) - { - } - - /// - public virtual void OnHandleRaisedEvent(ActorId id, string stateName, Event e) - { - } - - /// - public virtual void OnPopState(ActorId id, string currentStateName, string restoredStateName) - { - } - - /// - public virtual void OnPopStateUnhandledEvent(ActorId id, string stateName, Event e) - { - } - - /// - public virtual void OnPushState(ActorId id, string currentStateName, string newStateName) - { - } - - /// - public virtual void OnRaiseEvent(ActorId id, string stateName, Event e) - { - } - - /// - public virtual void OnReceiveEvent(ActorId id, string stateName, Event e, bool wasBlocked) - { - } - - /// - public virtual void OnSendEvent(ActorId targetActorId, string senderName, string senderType, - string senderStateName, - Event e, Guid opGroupId, bool isTargetHalted) - { - } - - /// - public virtual void OnStateTransition(ActorId id, string stateName, bool isEntry) - { - } - - /// - public virtual void OnWaitEvent(ActorId id, string stateName, Type eventType) - { - } - - /// - public virtual void OnWaitEvent(ActorId id, string stateName, params Type[] eventTypes) - { - } - - /// - public virtual void OnCreateMonitor(string monitorType) - { - } - - /// - public virtual void OnMonitorExecuteAction(string monitorType, string stateName, string actionName) - { - } - - /// - public virtual void OnMonitorProcessEvent(string monitorType, string stateName, string senderName, - string senderType, string senderStateName, Event e) - { - } - - /// - public virtual void OnMonitorRaiseEvent(string monitorType, string stateName, Event e) - { - } - - /// - public virtual void OnMonitorStateTransition(string monitorType, string stateName, bool isEntry, - bool? isInHotState) - { - } - - /// - public virtual void OnMonitorError(string monitorType, string stateName, bool? isInHotState) - { - } - - /// - public virtual void OnRandom(object result, string callerName, string callerType) - { - } - - /// - public virtual void OnStrategyDescription(string strategyName, string description) - { - } - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Actors/Managers/ActorManager.cs b/Src/PChecker/CheckerCore/Actors/Managers/ActorManager.cs deleted file mode 100644 index 3ec125adcd..0000000000 --- a/Src/PChecker/CheckerCore/Actors/Managers/ActorManager.cs +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using PChecker.Actors.Events; - -namespace PChecker.Actors.Managers -{ - /// - /// Manages an actor in production. - /// - internal class ActorManager : IActorManager - { - /// - /// The runtime that executes the actor being managed. - /// - private readonly ActorRuntime Runtime; - - /// - /// The actor being managed. - /// - private readonly Actor Instance; - - /// - public bool IsEventHandlerRunning { get; set; } - - /// - public Guid OperationGroupId { get; set; } - - /// - /// Initializes a new instance of the class. - /// - internal ActorManager(ActorRuntime runtime, Actor instance, Guid operationGroupId) - { - Runtime = runtime; - Instance = instance; - IsEventHandlerRunning = true; - OperationGroupId = operationGroupId; - } - - /// - public int GetCachedState() => 0; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsEventIgnored(Event e, Guid opGroupId, EventInfo eventInfo) => Instance.IsEventIgnored(e); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsEventDeferred(Event e, Guid opGroupId, EventInfo eventInfo) => false; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsDefaultHandlerAvailable() => Instance.IsDefaultHandlerAvailable; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void OnEnqueueEvent(Event e, Guid opGroupId, EventInfo eventInfo) => - Runtime.LogWriter.LogEnqueueEvent(Instance.Id, e); - - //// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void OnRaiseEvent(Event e, Guid opGroupId, EventInfo eventInfo) => - Runtime.LogWriter.LogRaiseEvent(Instance.Id, default, e); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void OnWaitEvent(IEnumerable eventTypes) => - Runtime.NotifyWaitEvent(Instance, eventTypes); - - /// - public void OnReceiveEvent(Event e, Guid opGroupId, EventInfo eventInfo) - { - if (opGroupId != Guid.Empty) - { - // Inherit the operation group id of the receive operation, if it is non-empty. - OperationGroupId = opGroupId; - } - - Runtime.NotifyReceivedEvent(Instance, e, eventInfo); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void OnReceiveEventWithoutWaiting(Event e, Guid opGroupId, EventInfo eventInfo) - { - if (opGroupId != Guid.Empty) - { - // Inherit the operation group id of the receive operation, if it is non-empty. - OperationGroupId = opGroupId; - } - - Runtime.NotifyReceivedEventWithoutWaiting(Instance, e, eventInfo); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void OnDropEvent(Event e, Guid opGroupId, EventInfo eventInfo) => - Runtime.TryHandleDroppedEvent(e, Instance.Id); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Assert(bool predicate, string s, object arg0) => Runtime.Assert(predicate, s, arg0); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Assert(bool predicate, string s, object arg0, object arg1) => Runtime.Assert(predicate, s, arg0, arg1); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Assert(bool predicate, string s, object arg0, object arg1, object arg2) => - Runtime.Assert(predicate, s, arg0, arg1, arg2); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Assert(bool predicate, string s, params object[] args) => Runtime.Assert(predicate, s, args); - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Actors/Managers/Mocks/MockActorManager.cs b/Src/PChecker/CheckerCore/Actors/Managers/Mocks/MockActorManager.cs deleted file mode 100644 index ad39164330..0000000000 --- a/Src/PChecker/CheckerCore/Actors/Managers/Mocks/MockActorManager.cs +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using PChecker.Actors.Events; -using PChecker.SystematicTesting; - -namespace PChecker.Actors.Managers.Mocks -{ - /// - /// Implements an actor manager that is used during testing. - /// - internal sealed class MockActorManager : IActorManager - { - /// - /// The runtime that executes the actor being managed. - /// - private readonly ControlledRuntime Runtime; - - /// - /// The actor being managed. - /// - private readonly Actor Instance; - - /// - public bool IsEventHandlerRunning { get; set; } - - /// - public Guid OperationGroupId { get; set; } - - /// - /// Program counter used for state-caching. Distinguishes - /// scheduling from non-deterministic choices. - /// - internal int ProgramCounter; - - /// - /// True if a transition statement was called in the current action, else false. - /// - internal bool IsTransitionStatementCalledInCurrentAction; - - /// - /// True if the actor is executing an on exit action, else false. - /// - internal bool IsInsideOnExit; - - /// - /// Initializes a new instance of the class. - /// - internal MockActorManager(ControlledRuntime runtime, Actor instance, Guid operationGroupId) - { - Runtime = runtime; - Instance = instance; - IsEventHandlerRunning = true; - OperationGroupId = operationGroupId; - ProgramCounter = 0; - IsTransitionStatementCalledInCurrentAction = false; - IsInsideOnExit = false; - } - - /// - public int GetCachedState() - { - unchecked - { - var hash = 19; - hash = (hash * 31) + IsEventHandlerRunning.GetHashCode(); - hash = (hash * 31) + ProgramCounter; - return hash; - } - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsEventIgnored(Event e, Guid opGroupId, EventInfo eventInfo) => Instance.IsEventIgnored(e); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsEventDeferred(Event e, Guid opGroupId, EventInfo eventInfo) => false; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsDefaultHandlerAvailable() => Instance.IsDefaultHandlerAvailable; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void OnEnqueueEvent(Event e, Guid opGroupId, EventInfo eventInfo) => - Runtime.LogWriter.LogEnqueueEvent(Instance.Id, e); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void OnRaiseEvent(Event e, Guid opGroupId, EventInfo eventInfo) => - Runtime.LogWriter.LogRaiseEvent(Instance.Id, default, e); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void OnWaitEvent(IEnumerable eventTypes) => - Runtime.NotifyWaitEvent(Instance, eventTypes); - - /// - public void OnReceiveEvent(Event e, Guid opGroupId, EventInfo eventInfo) - { - if (opGroupId != Guid.Empty) - { - // Inherit the operation group id of the receive operation, if it is non-empty. - OperationGroupId = opGroupId; - } - - Runtime.NotifyReceivedEvent(Instance, e, eventInfo); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void OnReceiveEventWithoutWaiting(Event e, Guid opGroupId, EventInfo eventInfo) - { - if (opGroupId != Guid.Empty) - { - // Inherit the operation group id of the receive operation, if it is non-empty. - OperationGroupId = opGroupId; - } - - Runtime.NotifyReceivedEventWithoutWaiting(Instance, e, eventInfo); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void OnDropEvent(Event e, Guid opGroupId, EventInfo eventInfo) - { - Runtime.TryHandleDroppedEvent(e, Instance.Id); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Assert(bool predicate, string s, object arg0) => Runtime.Assert(predicate, s, arg0); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Assert(bool predicate, string s, object arg0, object arg1) => Runtime.Assert(predicate, s, arg0, arg1); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Assert(bool predicate, string s, object arg0, object arg1, object arg2) => - Runtime.Assert(predicate, s, arg0, arg1, arg2); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Assert(bool predicate, string s, params object[] args) => Runtime.Assert(predicate, s, args); - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Actors/Managers/StateMachineManager.cs b/Src/PChecker/CheckerCore/Actors/Managers/StateMachineManager.cs deleted file mode 100644 index 91e28f0b71..0000000000 --- a/Src/PChecker/CheckerCore/Actors/Managers/StateMachineManager.cs +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using PChecker.Actors.Events; - -namespace PChecker.Actors.Managers -{ - /// - /// Manages a state machine in production. - /// - internal class StateMachineManager : IActorManager - { - /// - /// The runtime that executes the state machine being managed. - /// - private readonly ActorRuntime Runtime; - - /// - /// The state machine being managed. - /// - private readonly StateMachine Instance; - - /// - public bool IsEventHandlerRunning { get; set; } - - /// - public Guid OperationGroupId { get; set; } - - /// - /// Initializes a new instance of the class. - /// - internal StateMachineManager(ActorRuntime runtime, StateMachine instance, Guid operationGroupId) - { - Runtime = runtime; - Instance = instance; - IsEventHandlerRunning = true; - OperationGroupId = operationGroupId; - } - - /// - public int GetCachedState() => 0; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsEventIgnored(Event e, Guid opGroupId, EventInfo eventInfo) => - Instance.IsEventIgnoredInCurrentState(e); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsEventDeferred(Event e, Guid opGroupId, EventInfo eventInfo) => - Instance.IsEventDeferredInCurrentState(e); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsDefaultHandlerAvailable() => Instance.IsDefaultHandlerInstalledInCurrentState(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void OnEnqueueEvent(Event e, Guid opGroupId, EventInfo eventInfo) => - Runtime.LogWriter.LogEnqueueEvent(Instance.Id, e); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void OnRaiseEvent(Event e, Guid opGroupId, EventInfo eventInfo) => - Runtime.NotifyRaisedEvent(Instance, e, eventInfo); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void OnWaitEvent(IEnumerable eventTypes) => - Runtime.NotifyWaitEvent(Instance, eventTypes); - - /// - public void OnReceiveEvent(Event e, Guid opGroupId, EventInfo eventInfo) - { - if (opGroupId != Guid.Empty) - { - // Inherit the operation group id of the receive operation, if it is non-empty. - OperationGroupId = opGroupId; - } - - Runtime.NotifyReceivedEvent(Instance, e, eventInfo); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void OnReceiveEventWithoutWaiting(Event e, Guid opGroupId, EventInfo eventInfo) - { - if (opGroupId != Guid.Empty) - { - // Inherit the operation group id of the receive operation, if it is non-empty. - OperationGroupId = opGroupId; - } - - Runtime.NotifyReceivedEventWithoutWaiting(Instance, e, eventInfo); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void OnDropEvent(Event e, Guid opGroupId, EventInfo eventInfo) => - Runtime.TryHandleDroppedEvent(e, Instance.Id); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Assert(bool predicate, string s, object arg0) => Runtime.Assert(predicate, s, arg0); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Assert(bool predicate, string s, object arg0, object arg1) => Runtime.Assert(predicate, s, arg0, arg1); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Assert(bool predicate, string s, object arg0, object arg1, object arg2) => - Runtime.Assert(predicate, s, arg0, arg1, arg2); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Assert(bool predicate, string s, params object[] args) => Runtime.Assert(predicate, s, args); - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Actors/NameResolver.cs b/Src/PChecker/CheckerCore/Actors/NameResolver.cs deleted file mode 100644 index 501876bafd..0000000000 --- a/Src/PChecker/CheckerCore/Actors/NameResolver.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Collections.Concurrent; -using System.Globalization; - -namespace PChecker.Actors -{ - /// - /// Utility class for resolving names. - /// - internal static class NameResolver - { - /// - /// Cache of state names. - /// - private static readonly ConcurrentDictionary StateNamesCache = - new ConcurrentDictionary(); - - /// - /// Returns the qualified (i.e. ) name of the specified - /// state machine or monitor state, or the empty string if there is no such name. - /// - internal static string GetQualifiedStateName(Type state) - { - if (state is null) - { - return string.Empty; - } - - if (!StateNamesCache.TryGetValue(state, out var name)) - { - name = state.Name; - - var nextState = state; - while (nextState.DeclaringType != null) - { - if (!nextState.DeclaringType.IsSubclassOf(typeof(StateMachine.StateGroup))) - { - break; - } - - name = string.Format(CultureInfo.InvariantCulture, "{0}.{1}", nextState.DeclaringType.Name, name); - nextState = nextState.DeclaringType; - } - - StateNamesCache.GetOrAdd(state, name); - } - - return name; - } - - /// - /// Returns the state name to be used for logging purposes. - /// - internal static string GetStateNameForLogging(Type state) => state is null ? "None" : GetQualifiedStateName(state); - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Checker.cs b/Src/PChecker/CheckerCore/Checker.cs index dbb9a173a3..e14dc5025b 100644 --- a/Src/PChecker/CheckerCore/Checker.cs +++ b/Src/PChecker/CheckerCore/Checker.cs @@ -1,9 +1,8 @@ using System; -using PChecker.ExhaustiveSearch; using PChecker.IO.Debugging; using PChecker.IO.Logging; -using PChecker.Scheduling; using PChecker.SystematicTesting; +using PChecker.Testing; namespace PChecker; @@ -53,7 +52,7 @@ public static void Run(CheckerConfiguration configuration) switch (configuration.Mode) { case CheckerMode.BugFinding: - TestingProcessScheduler.Create(configuration).Run(); + TestingProcess.Create(configuration).Run(); break; case CheckerMode.Verification: case CheckerMode.Coverage: diff --git a/Src/PChecker/CheckerCore/CheckerConfiguration.cs b/Src/PChecker/CheckerCore/CheckerConfiguration.cs index 43e557cf92..b2c1d7d869 100644 --- a/Src/PChecker/CheckerCore/CheckerConfiguration.cs +++ b/Src/PChecker/CheckerCore/CheckerConfiguration.cs @@ -11,7 +11,7 @@ namespace PChecker { #pragma warning disable CA1724 // Type names should not match namespaces /// - /// The Coyote project configurations. + /// The checker project configurations. /// [DataContract] [Serializable] @@ -99,7 +99,7 @@ public class CheckerConfiguration public bool IncrementalSchedulingSeed; /// - /// If true, the Coyote tester performs a full exploration, + /// If true, the tester performs a full exploration, /// and does not stop when it finds a bug. /// [DataMember] @@ -141,7 +141,7 @@ public int MaxSchedulingSteps public bool UserExplicitlySetMaxFairSchedulingSteps; /// - /// If true, then the Coyote tester will consider an execution + /// If true, then the tester will consider an execution /// that hits the depth bound as buggy. /// [DataMember] @@ -188,13 +188,13 @@ public int MaxSchedulingSteps public bool IsVerbose { get; set; } /// - /// Enables code coverage reporting of a Coyote program. + /// Enables code coverage reporting of a program. /// [DataMember] public bool ReportCodeCoverage; /// - /// Enables activity coverage reporting of a Coyote program. + /// Enables activity coverage reporting of a program. /// [DataMember] public bool ReportActivityCoverage { get; set; } @@ -213,7 +213,7 @@ public int MaxSchedulingSteps /// /// If specified, requests a DGML graph of the schedule that contains a bug, if a bug is found. - /// This is different from a coverage activity graph, as it will also show actor instances. + /// This is different from a coverage activity graph, as it will also show state machine instances. /// [DataMember] public bool IsDgmlGraphEnabled { get; set; } @@ -236,13 +236,7 @@ public int MaxSchedulingSteps /// This is the AssemblyQualifiedName of the type to load. /// [DataMember] - public string CustomActorRuntimeLogType; - - /// - /// Enables debugging. - /// - [DataMember] - public bool EnableDebugging; + public string CustomStateMachineRuntimeLogType; /// @@ -327,7 +321,6 @@ protected CheckerConfiguration() DebugActivityCoverage = false; IsVerbose = false; - EnableDebugging = false; EnableColoredConsoleOutput = false; DisableEnvironmentExit = true; diff --git a/Src/PChecker/CheckerCore/Coverage/ActivityCoverageReporter.cs b/Src/PChecker/CheckerCore/Coverage/ActivityCoverageReporter.cs index e0b29a15c9..c17e3eb87d 100644 --- a/Src/PChecker/CheckerCore/Coverage/ActivityCoverageReporter.cs +++ b/Src/PChecker/CheckerCore/Coverage/ActivityCoverageReporter.cs @@ -5,12 +5,12 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using PChecker.Actors.Events; +using PChecker.Runtime.Events; namespace PChecker.Coverage { /// - /// The Coyote code coverage reporter. + /// The code coverage reporter. /// public class ActivityCoverageReporter { @@ -35,17 +35,6 @@ public ActivityCoverageReporter(CoverageInfo coverageInfo) BuiltInEvents.Add(typeof(DefaultEvent).FullName); } - /// - /// Emits the visualization graph. - /// - public void EmitVisualizationGraph(string graphFile) - { - if (CoverageInfo.CoverageGraph != null) - { - CoverageInfo.CoverageGraph.SaveDgml(graphFile, true); - } - } - /// /// Emits the code coverage report. /// diff --git a/Src/PChecker/CheckerCore/Coverage/ActorRuntimeLogEventCoverage.cs b/Src/PChecker/CheckerCore/Coverage/ControlledRuntimeLogEventCoverage.cs similarity index 65% rename from Src/PChecker/CheckerCore/Coverage/ActorRuntimeLogEventCoverage.cs rename to Src/PChecker/CheckerCore/Coverage/ControlledRuntimeLogEventCoverage.cs index 8d13857018..73df76499e 100644 --- a/Src/PChecker/CheckerCore/Coverage/ActorRuntimeLogEventCoverage.cs +++ b/Src/PChecker/CheckerCore/Coverage/ControlledRuntimeLogEventCoverage.cs @@ -4,28 +4,28 @@ using System; using System.Collections.Generic; using System.Runtime.Serialization; -using PChecker.Actors; -using PChecker.Actors.Events; -using PChecker.Actors.Logging; +using PChecker.Runtime.Events; +using PChecker.Runtime.Logging; +using PChecker.Runtime.StateMachines; namespace PChecker.Coverage { /// - /// This class maintains information about events received and sent from each state of each actor. + /// This class maintains information about events received and sent from each state of each state machine. /// [DataContract] public class EventCoverage { /// - /// Map from states to the list of events received by that state. The state id is fully qualified by - /// the actor id it belongs to. + /// Map from states to the list of events received by that state. The state id is fully qualified by + /// the state machine id it belongs to. /// [DataMember] private readonly Dictionary> EventsReceived = new Dictionary>(); /// /// Map from states to the list of events sent by that state. The state id is fully qualified by - /// the actor id it belongs to. + /// the state machine id it belongs to. /// [DataMember] private readonly Dictionary> EventsSent = new Dictionary>(); @@ -44,7 +44,7 @@ internal void AddEventReceived(string stateId, string eventId) /// /// Get list of events received by the given fully qualified state. /// - /// The actor qualified state name + /// The state machine qualified state name public IEnumerable GetEventsReceived(string stateId) { if (EventsReceived.TryGetValue(stateId, out var set)) @@ -69,7 +69,7 @@ internal void AddEventSent(string stateId, string eventId) /// /// Get list of events sent by the given state. /// - /// The actor qualified state name + /// The state machine qualified state name public IEnumerable GetEventsSent(string stateId) { if (EventsSent.TryGetValue(stateId, out var set)) @@ -102,12 +102,12 @@ private static void MergeHashSets(Dictionary> ours, Dict } } - internal class ActorRuntimeLogEventCoverage : IActorRuntimeLog + internal class ControlledRuntimeLogEventCoverage : IControlledRuntimeLog { private readonly EventCoverage InternalEventCoverage = new EventCoverage(); private Event Dequeued; - public ActorRuntimeLogEventCoverage() + public ControlledRuntimeLogEventCoverage() { } @@ -121,11 +121,7 @@ public void OnCompleted() { } - public void OnCreateActor(ActorId id, string creatorName, string creatorType) - { - } - - public void OnCreateStateMachine(ActorId id, string creatorName, string creatorType) + public void OnCreateStateMachine(StateMachineId id, string creatorName, string creatorType) { } @@ -133,34 +129,34 @@ public void OnCreateMonitor(string monitorType) { } - public void OnDefaultEventHandler(ActorId id, string stateName) + public void OnDefaultEventHandler(StateMachineId id, string stateName) { Dequeued = DefaultEvent.Instance; } - public void OnDequeueEvent(ActorId id, string stateName, Event e) + public void OnDequeueEvent(StateMachineId id, string stateName, Event e) { Dequeued = e; } - public void OnEnqueueEvent(ActorId id, Event e) + public void OnEnqueueEvent(StateMachineId id, Event e) { } - public void OnExceptionHandled(ActorId id, string stateName, string actionName, Exception ex) + public void OnExceptionHandled(StateMachineId id, string stateName, string actionName, Exception ex) { } - public void OnExceptionThrown(ActorId id, string stateName, string actionName, Exception ex) + public void OnExceptionThrown(StateMachineId id, string stateName, string actionName, Exception ex) { } - public void OnExecuteAction(ActorId id, string handlingStateName, string currentStateName, string actionName) + public void OnExecuteAction(StateMachineId id, string handlingStateName, string currentStateName, string actionName) { OnEventHandled(id, handlingStateName); } - private void OnEventHandled(ActorId id, string stateName) + private void OnEventHandled(StateMachineId id, string stateName) { if (Dequeued != null) { @@ -169,16 +165,16 @@ private void OnEventHandled(ActorId id, string stateName) } } - public void OnGotoState(ActorId id, string currentStateName, string newStateName) + public void OnGotoState(StateMachineId id, string currentStateName, string newStateName) { OnEventHandled(id, currentStateName); } - public void OnHalt(ActorId id, int inboxSize) + public void OnHalt(StateMachineId id, int inboxSize) { } - public void OnHandleRaisedEvent(ActorId id, string stateName, Event e) + public void OnHandleRaisedEvent(StateMachineId id, string stateName, Event e) { Dequeued = e; } @@ -211,39 +207,39 @@ public void OnRandom(object result, string callerName, string callerType) { } - public void OnPopState(ActorId id, string currentStateName, string restoredStateName) + public void OnPopState(StateMachineId id, string currentStateName, string restoredStateName) { } - public void OnPopStateUnhandledEvent(ActorId id, string stateName, Event e) + public void OnPopStateUnhandledEvent(StateMachineId id, string stateName, Event e) { } - public void OnPushState(ActorId id, string currentStateName, string newStateName) + public void OnPushState(StateMachineId id, string currentStateName, string newStateName) { OnEventHandled(id, currentStateName); } - public void OnRaiseEvent(ActorId id, string stateName, Event e) + public void OnRaiseEvent(StateMachineId id, string stateName, Event e) { var eventName = e.GetType().FullName; EventCoverage.AddEventSent(GetStateId(id.Type, stateName), eventName); } - public void OnReceiveEvent(ActorId id, string stateName, Event e, bool wasBlocked) + public void OnReceiveEvent(StateMachineId id, string stateName, Event e, bool wasBlocked) { var eventName = e.GetType().FullName; EventCoverage.AddEventReceived(GetStateId(id.Type, stateName), eventName); } - public void OnSendEvent(ActorId targetActorId, string senderName, string senderType, string senderStateName, - Event e, Guid opGroupId, bool isTargetHalted) + public void OnSendEvent(StateMachineId targetStateMachineId, string senderName, string senderType, string senderStateName, + Event e, bool isTargetHalted) { var eventName = e.GetType().FullName; EventCoverage.AddEventSent(GetStateId(senderType, senderStateName), eventName); } - public void OnStateTransition(ActorId id, string stateName, bool isEntry) + public void OnStateTransition(StateMachineId id, string stateName, bool isEntry) { } @@ -251,20 +247,20 @@ public void OnStrategyDescription(string strategyName, string description) { } - public void OnWaitEvent(ActorId id, string stateName, Type eventType) + public void OnWaitEvent(StateMachineId id, string stateName, Type eventType) { } - public void OnWaitEvent(ActorId id, string stateName, params Type[] eventTypes) + public void OnWaitEvent(StateMachineId id, string stateName, params Type[] eventTypes) { } - private static string GetStateId(string actorType, string stateName) + private static string GetStateId(string stateMachineType, string stateName) { - var id = ResolveActorTypeName(actorType); + var id = ResolvestateMachineTypeName(stateMachineType); if (string.IsNullOrEmpty(stateName)) { - if (actorType == null) + if (stateMachineType == null) { stateName = "ExternalState"; } @@ -277,35 +273,22 @@ private static string GetStateId(string actorType, string stateName) return id += "." + stateName; } - private static string ResolveActorTypeName(string actorType) + private static string ResolvestateMachineTypeName(string stateMachineType) { - if (actorType == null) + if (stateMachineType == null) { - // The sender id can be null if an event is fired from non-actor code. + // The sender id can be null if an event is fired from non-stateMachine code. return "ExternalCode"; } - return actorType; + return stateMachineType; } - private static string GetLabel(string actorId, string fullyQualifiedName) + private static string GetLabel(string stateMachineId, string fullyQualifiedName) { - if (fullyQualifiedName == null) - { - // then this is probably an Actor, not a StateMachine. For Actors we can invent a state - // name equal to the short name of the class, this then looks like a Constructor which is fine. - var pos = actorId.LastIndexOf("."); - if (pos > 0) - { - return actorId.Substring(pos + 1); - } - - return actorId; - } - - if (fullyQualifiedName.StartsWith(actorId)) + if (fullyQualifiedName.StartsWith(stateMachineId)) { - fullyQualifiedName = fullyQualifiedName.Substring(actorId.Length + 1).Trim('+'); + fullyQualifiedName = fullyQualifiedName.Substring(stateMachineId.Length + 1).Trim('+'); } return fullyQualifiedName; diff --git a/Src/PChecker/CheckerCore/Coverage/ActorRuntimeLogGraphBuilder.cs b/Src/PChecker/CheckerCore/Coverage/ControlledRuntimeLogGraphBuilder.cs similarity index 72% rename from Src/PChecker/CheckerCore/Coverage/ActorRuntimeLogGraphBuilder.cs rename to Src/PChecker/CheckerCore/Coverage/ControlledRuntimeLogGraphBuilder.cs index 752570a510..fab3dcfcd8 100644 --- a/Src/PChecker/CheckerCore/Coverage/ActorRuntimeLogGraphBuilder.cs +++ b/Src/PChecker/CheckerCore/Coverage/ControlledRuntimeLogGraphBuilder.cs @@ -7,26 +7,25 @@ using System.Runtime.Serialization; using System.Text; using System.Xml.Linq; -using PChecker.Actors; -using PChecker.Actors.Events; -using PChecker.Actors.Logging; +using PChecker.Runtime.Events; +using PChecker.Runtime.Logging; +using PChecker.Runtime.StateMachines; namespace PChecker.Coverage { /// - /// Implements the and builds a directed graph + /// Implements the and builds a directed graph /// from the recorded events and state transitions. /// - public class ActorRuntimeLogGraphBuilder : IActorRuntimeLog + public class ControlledRuntimeLogGraphBuilder : IControlledRuntimeLog { private Graph CurrentGraph; - private readonly Dictionary Dequeued = new Dictionary(); // current dequeued event. - private readonly Dictionary HaltedStates = new Dictionary(); // halted state for given actor. + private readonly Dictionary Dequeued = new Dictionary(); // current dequeued event. + private readonly Dictionary HaltedStates = new Dictionary(); // halted state for given state machine. private readonly bool MergeEventLinks; // merge events from node A to node B instead of making them separate links. private const string ExternalCodeName = "ExternalCode"; private const string ExternalStateName = "ExternalState"; private const string StateMachineCategory = "StateMachine"; - private const string ActorCategory = "Actor"; private const string MonitorCategory = "Monitor"; private class EventInfo @@ -51,7 +50,7 @@ private class PopStateEvent : Event { } - static ActorRuntimeLogGraphBuilder() + static ControlledRuntimeLogGraphBuilder() { EventAliases[typeof(GotoStateEvent).FullName] = "goto"; EventAliases[typeof(HaltEvent).FullName] = "halt"; @@ -63,9 +62,9 @@ static ActorRuntimeLogGraphBuilder() } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public ActorRuntimeLogGraphBuilder(bool mergeEventLinks) + public ControlledRuntimeLogGraphBuilder(bool mergeEventLinks) { MergeEventLinks = mergeEventLinks; CurrentGraph = new Graph(); @@ -80,9 +79,6 @@ public ActorRuntimeLogGraphBuilder(bool mergeEventLinks) /// /// Get or set the underlying logging object. /// - /// - /// See Logging for more information. - /// public TextWriter Logger { get; set; } /// @@ -102,37 +98,26 @@ public Graph Graph } /// - public void OnCreateActor(ActorId id, string creatorName, string creatorType) + public void OnCreateStateMachine(StateMachineId id, string creatorName, string creatorType) { lock (Inbox) { - var resolvedId = GetResolveActorId(id?.Name, id?.Type); - var node = Graph.GetOrCreateNode(resolvedId); - node.Category = ActorCategory; - } - } - - /// - public void OnCreateStateMachine(ActorId id, string creatorName, string creatorType) - { - lock (Inbox) - { - var resolvedId = GetResolveActorId(id?.Name, id?.Type); + var resolvedId = GetResolveStateMachineId(id?.Name, id?.Type); var node = Graph.GetOrCreateNode(resolvedId); node.Category = StateMachineCategory; } } /// - public void OnSendEvent(ActorId targetActorId, string senderName, string senderType, string senderStateName, - Event e, Guid opGroupId, bool isTargetHalted) + public void OnSendEvent(StateMachineId targetStateMachineId, string senderName, string senderType, string senderStateName, + Event e, bool isTargetHalted) { var eventName = e.GetType().FullName; - AddEvent(targetActorId.Name, targetActorId.Type, senderName, senderType, senderStateName, eventName); + AddEvent(targetStateMachineId.Name, targetStateMachineId.Type, senderName, senderType, senderStateName, eventName); } /// - public void OnRaiseEvent(ActorId id, string stateName, Event e) + public void OnRaiseEvent(StateMachineId id, string stateName, Event e) { var eventName = e.GetType().FullName; // Raising event to self. @@ -140,16 +125,16 @@ public void OnRaiseEvent(ActorId id, string stateName, Event e) } /// - public void OnEnqueueEvent(ActorId id, Event e) + public void OnEnqueueEvent(StateMachineId id, Event e) { } /// - public void OnDequeueEvent(ActorId id, string stateName, Event e) + public void OnDequeueEvent(StateMachineId id, string stateName, Event e) { lock (Inbox) { - var resolvedId = GetResolveActorId(id?.Name, id?.Type); + var resolvedId = GetResolveStateMachineId(id?.Name, id?.Type); var eventName = e.GetType().FullName; var info = PopEvent(resolvedId, eventName); if (info != null) @@ -181,9 +166,9 @@ private EventInfo PopEvent(string resolvedId, string eventName) } /// - public void OnReceiveEvent(ActorId id, string stateName, Event e, bool wasBlocked) + public void OnReceiveEvent(StateMachineId id, string stateName, Event e, bool wasBlocked) { - var resolvedId = GetResolveActorId(id?.Name, id?.Type); + var resolvedId = GetResolveStateMachineId(id?.Name, id?.Type); lock (Inbox) { if (Inbox.TryGetValue(resolvedId, out var inbox)) @@ -195,7 +180,7 @@ public void OnReceiveEvent(ActorId id, string stateName, Event e, bool wasBlocke if (info.Event == eventName) { // Yay, found it so we can draw the complete link connecting the Sender state to this state! - var category = string.IsNullOrEmpty(stateName) ? ActorCategory : StateMachineCategory; + var category = StateMachineCategory; var source = GetOrCreateChild(info.Name, info.Type, info.State); var target = GetOrCreateChild(id?.Name, id?.Type, category, stateName); GetOrCreateEventLink(source, target, info); @@ -208,17 +193,17 @@ public void OnReceiveEvent(ActorId id, string stateName, Event e, bool wasBlocke } /// - public void OnWaitEvent(ActorId id, string stateName, Type eventType) + public void OnWaitEvent(StateMachineId id, string stateName, Type eventType) { } /// - public void OnWaitEvent(ActorId id, string stateName, params Type[] eventTypes) + public void OnWaitEvent(StateMachineId id, string stateName, params Type[] eventTypes) { } /// - public void OnStateTransition(ActorId id, string stateName, bool isEntry) + public void OnStateTransition(StateMachineId id, string stateName, bool isEntry) { if (isEntry) { @@ -228,19 +213,19 @@ public void OnStateTransition(ActorId id, string stateName, bool isEntry) } /// - public void OnExecuteAction(ActorId id, string handlingStateName, string currentStateName, string actionName) + public void OnExecuteAction(StateMachineId id, string handlingStateName, string currentStateName, string actionName) { LinkTransition(typeof(DoActionEvent), id, handlingStateName, currentStateName, null); } /// - public void OnGotoState(ActorId id, string currentStateName, string newStateName) + public void OnGotoState(StateMachineId id, string currentStateName, string newStateName) { LinkTransition(typeof(GotoStateEvent), id, currentStateName, currentStateName, newStateName); } /// - public void OnHalt(ActorId id, int inboxSize) + public void OnHalt(StateMachineId id, int inboxSize) { lock (Inbox) { @@ -268,11 +253,11 @@ public void OnHalt(ActorId id, int inboxSize) } /// - public void OnDefaultEventHandler(ActorId id, string stateName) + public void OnDefaultEventHandler(StateMachineId id, string stateName) { lock (Inbox) { - var resolvedId = GetResolveActorId(id?.Name, id?.Type); + var resolvedId = GetResolveStateMachineId(id?.Name, id?.Type); var eventName = typeof(DefaultEvent).FullName; AddEvent(id.Name, id.Type, id.Name, id.Type, stateName, eventName); Dequeued[id] = PopEvent(resolvedId, eventName); @@ -280,13 +265,13 @@ public void OnDefaultEventHandler(ActorId id, string stateName) } /// - public void OnHandleRaisedEvent(ActorId id, string stateName, Event e) + public void OnHandleRaisedEvent(StateMachineId id, string stateName, Event e) { lock (Inbox) { // We used the inbox to store raised event, but it should be the first one handled since // raised events are highest priority. - var resolvedId = GetResolveActorId(id?.Name, id?.Type); + var resolvedId = GetResolveStateMachineId(id?.Name, id?.Type); lock (Inbox) { if (Inbox.TryGetValue(resolvedId, out var inbox)) @@ -307,21 +292,21 @@ public void OnHandleRaisedEvent(ActorId id, string stateName, Event e) } /// - public void OnPopStateUnhandledEvent(ActorId actorId, string currentStateName, Event e) + public void OnPopStateUnhandledEvent(StateMachineId stateMachineId, string currentStateName, Event e) { if (e is HaltEvent) { - HaltedStates[actorId] = currentStateName; + HaltedStates[stateMachineId] = currentStateName; } } /// - public void OnExceptionThrown(ActorId id, string stateName, string actionName, Exception ex) + public void OnExceptionThrown(StateMachineId id, string stateName, string actionName, Exception ex) { } /// - public void OnExceptionHandled(ActorId id, string stateName, string actionName, Exception ex) + public void OnExceptionHandled(StateMachineId id, string stateName, string actionName, Exception ex) { } @@ -460,11 +445,11 @@ public Graph SnapshotGraph(bool reset) return result; } - private string GetResolveActorId(string name, string type) + private string GetResolveStateMachineId(string name, string type) { if (type == null) { - // The sender id can be null if an event is fired from non-actor code. + // The sender id can be null if an event is fired from non-stateMachine code. return ExternalCodeName; } @@ -479,7 +464,7 @@ private string GetResolveActorId(string name, string type) private EventInfo AddEvent(string targetName, string targetType, string senderName, string senderType, string senderStateName, string eventName) { - var targetId = GetResolveActorId(targetName, targetType); + var targetId = GetResolveStateMachineId(targetName, targetType); EventInfo info = null; lock (Inbox) { @@ -503,7 +488,7 @@ private EventInfo AddEvent(string targetName, string targetType, string senderNa return info; } - private void LinkTransition(Type transitionType, ActorId id, string handlingStateName, + private void LinkTransition(Type transitionType, StateMachineId id, string handlingStateName, string currentStateName, string newStateName) { var name = id.Name; @@ -548,10 +533,10 @@ private GraphNode GetOrCreateChild(string name, string type, string stateName, s var initalStateName = stateName; - // make label relative to fully qualified actor id (it's usually a nested class). + // make label relative to fully qualified state machine id (it's usually a nested class). stateName = GetLabel(name, type, stateName); - var id = GetResolveActorId(name, type); + var id = GetResolveStateMachineId(name, type); var parent = Graph.GetOrCreateNode(id); parent.AddAttribute("Group", "Expanded"); @@ -626,13 +611,7 @@ private string GetLabel(string name, string type, string fullyQualifiedName) } AddNamespace(type); - if (string.IsNullOrEmpty(fullyQualifiedName)) - { - // then this is probably an Actor, not a StateMachine. For Actors we can invent a state - // name equal to the short name of the class, this then looks like a Constructor which is fine. - fullyQualifiedName = CollapseMachineInstances ? type : name; - } - + var len = fullyQualifiedName.Length; var index = fullyQualifiedName.LastIndexOfAny(TypeSeparators); if (index > 0) @@ -680,11 +659,8 @@ private static string GetEventCategory(string fullyQualifiedName) [DataContract] public class Graph { - internal const string DgmlNamespace = "http://schemas.microsoft.com/vs/2009/dgml"; - // These [DataMember] fields are here so we can serialize the Graph across parallel or distributed - // test processes without losing any information. There is more information here than in the serialized - // DGML which is we we can't just use Save/LoadDgml to do the same. + // test processes without losing any information. [DataMember] private readonly Dictionary InternalNodes = new Dictionary(); @@ -815,175 +791,7 @@ internal int GetUniqueLinkIndex(GraphNode source, GraphNode target, string id) return index; } - - /// - /// Serialize the graph to a DGML string. - /// - public override string ToString() - { - using (var writer = new StringWriter()) - { - WriteDgml(writer, false); - return writer.ToString(); - } - } - - internal void SaveDgml(string graphFilePath, bool includeDefaultStyles) - { - using (var writer = new StreamWriter(graphFilePath, false, Encoding.UTF8)) - { - WriteDgml(writer, includeDefaultStyles); - } - } - - /// - /// Serialize the graph to DGML. - /// - public void WriteDgml(TextWriter writer, bool includeDefaultStyles) - { - writer.WriteLine("", DgmlNamespace); - writer.WriteLine(" "); - - if (InternalNodes != null) - { - var nodes = new List(InternalNodes.Keys); - nodes.Sort(); - foreach (var id in nodes) - { - var node = InternalNodes[id]; - writer.Write(" "); - } - } - - writer.WriteLine(" "); - writer.WriteLine(" "); - - if (InternalLinks != null) - { - var links = new List(InternalLinks.Keys); - links.Sort(); - foreach (var id in links) - { - var link = InternalLinks[id]; - writer.Write(" "); - } - } - - writer.WriteLine(" "); - if (includeDefaultStyles) - { - writer.WriteLine( - @" - - - - - - - "); - } - - writer.WriteLine(""); - } - - /// - /// Load a DGML file into a new Graph object. - /// - /// Full path to the DGML file. - /// The loaded Graph object. - public static Graph LoadDgml(string graphFilePath) - { - var doc = XDocument.Load(graphFilePath); - var result = new Graph(); - var ns = doc.Root.Name.Namespace; - if (ns != DgmlNamespace) - { - throw new Exception(string.Format("File '{0}' does not contain the DGML namespace", graphFilePath)); - } - - foreach (var e in doc.Root.Element(ns + "Nodes").Elements(ns + "Node")) - { - var id = (string)e.Attribute("Id"); - var label = (string)e.Attribute("Label"); - var category = (string)e.Attribute("Category"); - - var node = new GraphNode(id, label, category); - node.AddDgmlProperties(e); - result.GetOrCreateNode(node); - } - - foreach (var e in doc.Root.Element(ns + "Links").Elements(ns + "Link")) - { - var srcId = (string)e.Attribute("Source"); - var targetId = (string)e.Attribute("Target"); - var label = (string)e.Attribute("Label"); - var category = (string)e.Attribute("Category"); - var srcNode = result.GetOrCreateNode(srcId); - var targetNode = result.GetOrCreateNode(targetId); - var indexAttr = e.Attribute("index"); - int? index = null; - if (indexAttr != null) - { - index = (int)indexAttr; - } - - var link = result.GetOrCreateLink(srcNode, targetNode, index, label, category); - link.AddDgmlProperties(e); - } - - return result; - } + /// /// Merge the given graph so that this graph becomes a superset of both graphs. @@ -1150,27 +958,6 @@ public GraphNode(string id, string label, string category) Label = label; Category = category; } - - /// - /// Add additional properties from XML element. - /// - /// An XML element representing the graph node in DGML format. - public void AddDgmlProperties(XElement e) - { - foreach (var a in e.Attributes()) - { - switch (a.Name.LocalName) - { - case "Id": - case "Label": - case "Category": - break; - default: - AddAttribute(a.Name.LocalName, a.Value); - break; - } - } - } } /// @@ -1220,27 +1007,5 @@ public GraphLink(GraphNode source, GraphNode target, string label, string catego Label = label; Category = category; } - - /// - /// Add additional properties from XML element. - /// - /// An XML element representing the graph node in DGML format. - public void AddDgmlProperties(XElement e) - { - foreach (var a in e.Attributes()) - { - switch (a.Name.LocalName) - { - case "Source": - case "Target": - case "Label": - case "Category": - break; - default: - AddAttribute(a.Name.LocalName, a.Value); - break; - } - } - } } } \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Exceptions/AssertionFailureException.cs b/Src/PChecker/CheckerCore/Exceptions/AssertionFailureException.cs index 779c439ab2..271eca30f8 100644 --- a/Src/PChecker/CheckerCore/Exceptions/AssertionFailureException.cs +++ b/Src/PChecker/CheckerCore/Exceptions/AssertionFailureException.cs @@ -6,7 +6,7 @@ namespace PChecker.Exceptions { /// - /// The exception that is thrown by the Coyote runtime upon assertion failure. + /// The exception that is thrown by the ControlledRuntime upon assertion failure. /// internal sealed class AssertionFailureException : RuntimeException { diff --git a/Src/PChecker/CheckerCore/Exceptions/RuntimeException.cs b/Src/PChecker/CheckerCore/Exceptions/RuntimeException.cs index 802bb68ea9..2b6b4d1011 100644 --- a/Src/PChecker/CheckerCore/Exceptions/RuntimeException.cs +++ b/Src/PChecker/CheckerCore/Exceptions/RuntimeException.cs @@ -8,7 +8,7 @@ namespace PChecker.Exceptions { /// - /// An exception that is thrown by the Coyote runtime. + /// An exception that is thrown by the ControlledRuntime. /// [Serializable] [DebuggerStepThrough] diff --git a/Src/PChecker/CheckerCore/ExhaustiveSearch/ExhaustiveSearch.cs b/Src/PChecker/CheckerCore/ExhaustiveEngine.cs similarity index 99% rename from Src/PChecker/CheckerCore/ExhaustiveSearch/ExhaustiveSearch.cs rename to Src/PChecker/CheckerCore/ExhaustiveEngine.cs index 86fb55f544..445392c740 100644 --- a/Src/PChecker/CheckerCore/ExhaustiveSearch/ExhaustiveSearch.cs +++ b/Src/PChecker/CheckerCore/ExhaustiveEngine.cs @@ -7,7 +7,7 @@ using PChecker.IO.Debugging; using PChecker.IO.Logging; -namespace PChecker.ExhaustiveSearch +namespace PChecker { /// /// Exhaustive engine that can run a controlled concurrency exhaustive search using diff --git a/Src/PChecker/CheckerCore/IO/Logging/ConsoleLogger.cs b/Src/PChecker/CheckerCore/IO/Logging/ConsoleLogger.cs index 027e89f7b7..b2cc0598b7 100644 --- a/Src/PChecker/CheckerCore/IO/Logging/ConsoleLogger.cs +++ b/Src/PChecker/CheckerCore/IO/Logging/ConsoleLogger.cs @@ -10,9 +10,6 @@ namespace PChecker.IO.Logging /// /// Logger that writes text to the console. /// - /// - /// See Logging for more information. - /// public sealed class ConsoleLogger : TextWriter { /// diff --git a/Src/PChecker/CheckerCore/Monitoring/CodeCoverageMonitor.cs b/Src/PChecker/CheckerCore/Monitoring/CodeCoverageMonitor.cs deleted file mode 100644 index 0f2a11d5e2..0000000000 --- a/Src/PChecker/CheckerCore/Monitoring/CodeCoverageMonitor.cs +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#if NETFRAMEWORK -using System; -using System.Diagnostics; -using System.IO; -using System.Threading; - -using Microsoft.Coyote.IO; - -namespace Microsoft.Coyote.SystematicTesting -{ - /// - /// Monitors the program being tested for code coverage. - /// - internal static class CodeCoverageMonitor - { - /// - /// CheckerConfiguration. - /// - private static CheckerConfiguration CheckerConfiguration; - - /// - /// Monitoring process is running. - /// - internal static bool IsRunning; - - /// - /// Starts the code coverage monitor. - /// - /// CheckerConfiguration - internal static void Start(CheckerConfiguration checkerConfiguration) - { - if (IsRunning) - { - throw new InvalidOperationException("Process has already started."); - } - - CheckerConfiguration = checkerConfiguration; - RunMonitorProcess(true); - IsRunning = true; - } - - /// - /// Stops the code coverage monitor. - /// - internal static void Stop() - { - if (CheckerConfiguration is null) - { - throw new InvalidOperationException("Process has not been configured."); - } - - if (!IsRunning) - { - throw new InvalidOperationException("Process is not running."); - } - - RunMonitorProcess(false); - IsRunning = false; - } - - private static void RunMonitorProcess(bool isStarting) - { - var error = string.Empty; - var exitCode = 0; - var outputFile = GetOutputName(); - var arguments = isStarting ? $"/start:coverage /output:{outputFile}" : "/shutdown"; - var timedOut = false; - using (var monitorProc = new Process()) - { - monitorProc.StartInfo.FileName = CodeCoverageInstrumentation.GetToolPath("VSPerfCmdToolPath", "VSPerfCmd"); - monitorProc.StartInfo.Arguments = arguments; - monitorProc.StartInfo.UseShellExecute = false; - monitorProc.StartInfo.RedirectStandardOutput = true; - monitorProc.StartInfo.RedirectStandardError = true; - monitorProc.Start(); - - Console.WriteLine($"... {(isStarting ? "Starting" : "Shutting down")} code coverage monitor"); - - // timedOut can only become true on shutdown (non-infinite timeout value) - timedOut = !monitorProc.WaitForExit(isStarting ? Timeout.Infinite : 5000); - if (!timedOut) - { - exitCode = monitorProc.ExitCode; - if (exitCode != 0) - { - error = monitorProc.StandardError.ReadToEnd(); - } - } - } - - if (exitCode != 0 || error.Length > 0) - { - if (error.Length == 0) - { - error = ""; - } - - Console.WriteLine($"Warning: 'VSPerfCmd {arguments}' exit code {exitCode}: {error}"); - } - - if (!isStarting) - { - if (timedOut) - { - Console.WriteLine($"Warning: VsPerfCmd timed out on shutdown"); - } - - if (File.Exists(outputFile)) - { - var fileInfo = new FileInfo(outputFile); - Console.WriteLine($"..... Created {outputFile}"); - } - else - { - Console.WriteLine($"Warning: Code coverage output file {outputFile} was not created"); - } - } - } - - /// - /// Returns the output name. - /// - private static string GetOutputName() - { - string file = Path.GetFileNameWithoutExtension(CheckerConfiguration.AssemblyToBeAnalyzed); - string directory = CodeCoverageInstrumentation.OutputDirectory; - return $"{directory}{file}.coverage"; - } - } -} -#endif \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/PRuntime/Exceptions/PrtInhabitsTypeException.cs b/Src/PChecker/CheckerCore/PRuntime/Exceptions/PrtInhabitsTypeException.cs deleted file mode 100644 index b9c9d5037e..0000000000 --- a/Src/PChecker/CheckerCore/PRuntime/Exceptions/PrtInhabitsTypeException.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; - -namespace PChecker.PRuntime.Exceptions -{ - public class PrtInhabitsTypeException : Exception - { - public PrtInhabitsTypeException() - { - } - - public PrtInhabitsTypeException(string message) : base(message) - { - } - - public PrtInhabitsTypeException(string message, Exception innerException) : base(message, innerException) - { - } - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/PRuntime/GodMachine.cs b/Src/PChecker/CheckerCore/PRuntime/GodMachine.cs deleted file mode 100644 index a629d66cd4..0000000000 --- a/Src/PChecker/CheckerCore/PRuntime/GodMachine.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using PChecker.Actors; -using PChecker.Actors.Events; - -namespace PChecker.PRuntime -{ - public class _GodMachine : StateMachine - { - private void InitOnEntry(Event e) - { - var mainMachine = (e as Config).MainMachine; - CreateActor(mainMachine, mainMachine.Name, - new PMachine.InitializeParametersEvent( - new PMachine.InitializeParameters("I_" + mainMachine.Name, null))); - } - - public class Config : Event - { - public Type MainMachine; - - public Config(Type main) - { - MainMachine = main; - } - } - - [Start] - [OnEntry(nameof(InitOnEntry))] - private class Init : State - { - } - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/PRuntime/PEvent.cs b/Src/PChecker/CheckerCore/PRuntime/PEvent.cs deleted file mode 100644 index 33af7d6790..0000000000 --- a/Src/PChecker/CheckerCore/PRuntime/PEvent.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using PChecker.Actors.Events; -using PChecker.PRuntime.Values; - -namespace PChecker.PRuntime -{ - public class PEvent : Event, IPrtValue - { - public PEvent() : base() - { - } - - public PEvent(IPrtValue payload) : base() - { - Payload = payload; - } - - public IPrtValue Payload { get; } - - public bool Equals(IPrtValue other) - { - return other != null && GetType().FullName.Equals(other.GetType().FullName); - } - - public virtual IPrtValue Clone() - { - throw new NotImplementedException(); - } - - public object ToDict() - { - return this.GetType().Name; - } - - public override bool Equals(object obj) - { - return obj is PEvent other && Equals(other); - } - - public override int GetHashCode() - { - return GetType().FullName.GetHashCode(); - } - - public override string ToString() - { - return GetType().Name; - } - } - - public class PHalt : PEvent - { - public PHalt(IPrtValue payload) : base(payload) - { - } - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/PRuntime/PLogFormatter.cs b/Src/PChecker/CheckerCore/PRuntime/PLogFormatter.cs deleted file mode 100644 index 5e70ab79c7..0000000000 --- a/Src/PChecker/CheckerCore/PRuntime/PLogFormatter.cs +++ /dev/null @@ -1,220 +0,0 @@ -using System; -using System.Linq; -using PChecker.Actors; -using PChecker.Actors.Events; -using PChecker.Actors.Logging; -using PChecker.PRuntime.Exceptions; - -namespace PChecker.PRuntime -{ - /// - /// Formatter for the runtime log. - /// - public class PLogFormatter : ActorRuntimeLogTextFormatter - { - public PLogFormatter() : base() - { - } - - private string GetShortName(string name) - { - return name.Split('.').Last(); - } - - private string GetEventNameWithPayload(Event e) - { - if (e.GetType().Name.Contains("GotoStateEvent")) - { - return e.GetType().Name; - } - var pe = (PEvent)(e); - var payload = pe.Payload == null ? "null" : pe.Payload.ToEscapedString(); - var msg = pe.Payload == null ? "" : $" with payload ({payload})"; - return $"{GetShortName(e.GetType().Name)}{msg}"; - } - - public override void OnStateTransition(ActorId id, string stateName, bool isEntry) - { - if (stateName.Contains("__InitState__") || id.Name.Contains("GodMachine")) - { - return; - } - - base.OnStateTransition(id, GetShortName(stateName), isEntry); - } - - public override void OnDefaultEventHandler(ActorId id, string stateName) - { - base.OnDefaultEventHandler(id, GetShortName(stateName)); - } - - public override void OnWaitEvent(ActorId id, string stateName, params Type[] eventTypes) - { - base.OnWaitEvent(id, GetShortName(stateName), eventTypes); - } - - public override void OnWaitEvent(ActorId id, string stateName, Type eventType) - { - base.OnWaitEvent(id, GetShortName(stateName), eventType); - } - - public override void OnMonitorStateTransition(string monitorType, string stateName, bool isEntry, bool? isInHotState) - { - if (stateName.Contains("__InitState__")) - { - return; - } - - base.OnMonitorStateTransition(monitorType: GetShortName(monitorType), stateName: GetShortName(stateName), isEntry: isEntry, isInHotState: isInHotState); - } - - public override void OnCreateActor(ActorId id, string creatorName, string creatorType) - { - if (id.Name.Contains("GodMachine") || creatorName.Contains("GodMachine")) - { - return; - } - - base.OnCreateActor(id, GetShortName(creatorName), creatorType); - } - - public override void OnMonitorProcessEvent(string monitorType, string stateName, string senderName, string senderType, - string senderStateName, Event e) - { - var text = $" {GetShortName(monitorType)} is processing event '{GetEventNameWithPayload(e)}' in state '{stateName}'."; - Logger.WriteLine(text); - } - - public override void OnDequeueEvent(ActorId id, string stateName, Event e) - { - if (stateName.Contains("__InitState__") || id.Name.Contains("GodMachine")) - { - return; - } - - stateName = GetShortName(stateName); - var eventName = GetEventNameWithPayload(e); - string text = null; - if (stateName is null) - { - text = $" '{id}' dequeued event '{eventName}'."; - } - else - { - text = $" '{id}' dequeued event '{eventName}' in state '{stateName}'."; - } - - Logger.WriteLine(text); - } - - public override void OnRaiseEvent(ActorId id, string stateName, Event e) - { - stateName = GetShortName(stateName); - var eventName = GetEventNameWithPayload(e); - if (stateName.Contains("__InitState__") || id.Name.Contains("GodMachine") || eventName.Contains("GotoStateEvent")) - { - return; - } - - string text = null; - if (stateName is null) - { - text = $" '{id}' raised event '{eventName}'."; - } - else - { - text = $" '{id}' raised event '{eventName}' in state '{stateName}'."; - } - - Logger.WriteLine(text); - } - - public override void OnEnqueueEvent(ActorId id, Event e) { } - - public override void OnReceiveEvent(ActorId id, string stateName, Event e, bool wasBlocked) - { - stateName = GetShortName(stateName); - var eventName = GetEventNameWithPayload(e); - string text = null; - var unblocked = wasBlocked ? " and unblocked" : string.Empty; - if (stateName is null) - { - text = $" '{id}' dequeued event '{eventName}'{unblocked}."; - } - else - { - text = $" '{id}' dequeued event '{eventName}'{unblocked} in state '{stateName}'."; - } - - Logger.WriteLine(text); - } - - public override void OnMonitorRaiseEvent(string monitorType, string stateName, Event e) - { - stateName = GetShortName(stateName); - var eventName = GetEventNameWithPayload(e); - var text = $" Monitor '{GetShortName(monitorType)}' raised event '{eventName}' in state '{stateName}'."; - Logger.WriteLine(text); - } - - public override void OnSendEvent(ActorId targetActorId, string senderName, string senderType, string senderStateName, Event e, Guid opGroupId, bool isTargetHalted) - { - senderStateName = GetShortName(senderStateName); - var eventName = GetEventNameWithPayload(e); - var opGroupIdMsg = opGroupId != Guid.Empty ? $" (operation group '{opGroupId}')" : string.Empty; - var isHalted = isTargetHalted ? $" which has halted" : string.Empty; - var sender = !string.IsNullOrEmpty(senderName) ? $"'{senderName}' in state '{senderStateName}'" : $"The runtime"; - var text = $" {sender} sent event '{eventName}' to '{targetActorId}'{isHalted}{opGroupIdMsg}."; - Logger.WriteLine(text); - } - - public override void OnGotoState(ActorId id, string currStateName, string newStateName) - { - if (currStateName.Contains("__InitState__") || id.Name.Contains("GodMachine")) - { - return; - } - - base.OnGotoState(id, GetShortName(currStateName), GetShortName(newStateName)); - } - - public override void OnExecuteAction(ActorId id, string handlingStateName, string currentStateName, string actionName) - { - } - - public override void OnMonitorExecuteAction(string monitorType, string stateName, string actionName) - { - } - - public override void OnExceptionHandled(ActorId id, string stateName, string actionName, Exception ex) - { - if (ex is PNonStandardReturnException) - { - return; - } - base.OnExceptionHandled(id: id, stateName: GetShortName(stateName), actionName: actionName, ex: ex); - } - - public override void OnExceptionThrown(ActorId id, string stateName, string actionName, Exception ex) - { - if (ex is PNonStandardReturnException) - { - return; - } - base.OnExceptionThrown(id: id, stateName: GetShortName(stateName), actionName: actionName, ex: ex); - } - - public override void OnCreateMonitor(string monitorType) - { - base.OnCreateMonitor(GetShortName(monitorType)); - } - - public override void OnHandleRaisedEvent(ActorId id, string stateName, Event e) - { - } - - public override void OnRandom(object result, string callerName, string callerType) - { - } - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/PRuntime/PMachine.cs b/Src/PChecker/CheckerCore/PRuntime/PMachine.cs deleted file mode 100644 index 92014533ab..0000000000 --- a/Src/PChecker/CheckerCore/PRuntime/PMachine.cs +++ /dev/null @@ -1,261 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using PChecker.Actors; -using PChecker.Actors.Events; -using PChecker.Actors.Exceptions; -using PChecker.Actors.Logging; -using PChecker.PRuntime.Exceptions; -using PChecker.PRuntime.Values; - -namespace PChecker.PRuntime -{ - public class PMachine : StateMachine - { - public List creates = new List(); - protected IPrtValue gotoPayload; - private string interfaceName; - public List receives = new List(); - public PMachineValue self; - public List sends = new List(); - - public void TryAssert(bool predicate) - { - Assert(predicate); - } - - public void TryAssert(bool predicate, string s, params object[] args) - { - Assert(predicate, s, args); - } - - protected void InitializeParametersFunction(Event e) - { - if (!(e is InitializeParametersEvent @event)) - { - throw new ArgumentException("Event type is incorrect: " + e.GetType().Name); - } - - var initParam = @event.Payload as InitializeParameters; - interfaceName = initParam.InterfaceName; - self = new PMachineValue(Id, receives.ToList()); - TryRaiseEvent(GetConstructorEvent(initParam.Payload), initParam.Payload); - } - - protected virtual Event GetConstructorEvent(IPrtValue value) - { - throw new NotImplementedException(); - } - - protected override OnExceptionOutcome OnException(Exception ex, string methodName, Event e) - { - var v = ex is UnhandledEventException; - if (!v) - { - return ex is PNonStandardReturnException - ? OnExceptionOutcome.HandledException - : base.OnException(ex, methodName, e); - } - - return (ex as UnhandledEventException).UnhandledEvent is PHalt - ? OnExceptionOutcome.Halt - : base.OnException(ex, methodName, e); - } - - public PMachineValue CreateInterface(PMachine creator, IPrtValue payload = null) - where T : PMachineValue - { - var createdInterface = PModule.linkMap[creator.interfaceName][typeof(T).Name]; - Assert(creates.Contains(createdInterface), - $"Machine {GetType().Name} cannot create interface {createdInterface}, not in its creates set"); - var createMachine = PModule.interfaceDefinitionMap[createdInterface]; - var machineId = CreateActor(createMachine, createdInterface.Substring(2), - new InitializeParametersEvent(new InitializeParameters(createdInterface, payload))); - return new PMachineValue(machineId, PInterfaces.GetPermissions(createdInterface)); - } - - public void TrySendEvent(PMachineValue target, Event ev, object payload = null) - { - Assert(ev != null, "Machine cannot send a null event"); - Assert(target != null, "Machine in send cannot be null"); - Assert(sends.Contains(ev.GetType().Name), - $"Event {ev.GetType().Name} is not in the sends set of the Machine {GetType().Name}"); - Assert(target.Permissions.Contains(ev.GetType().Name), - $"Event {ev.GetType().Name} is not in the permissions set of the target machine"); - var oneArgConstructor = ev.GetType().GetConstructors().First(x => x.GetParameters().Length > 0); - ev = (Event)oneArgConstructor.Invoke(new[] { payload }); - - AnnounceInternal(ev); - SendEvent(target.Id, ev); - } - - public void TryRaiseEvent(Event ev, object payload = null) - { - Assert(ev != null, "Machine cannot raise a null event"); - var oneArgConstructor = ev.GetType().GetConstructors().First(x => x.GetParameters().Length > 0); - ev = (Event)oneArgConstructor.Invoke(new[] { payload }); - RaiseEvent(ev); - throw new PNonStandardReturnException { ReturnKind = NonStandardReturn.Raise }; - } - - public Task TryReceiveEvent(params Type[] events) - { - return ReceiveEventAsync(events); - } - - public void TryGotoState(IPrtValue payload = null) where T : State - { - gotoPayload = payload; - RaiseGotoStateEvent(); - throw new PNonStandardReturnException { ReturnKind = NonStandardReturn.Goto }; - } - - public int TryRandomInt(int maxValue) - { - return RandomInteger(maxValue); - } - - public int TryRandomInt(int minValue, int maxValue) - { - return minValue + RandomInteger(maxValue - minValue); - } - - public bool TryRandomBool(int maxValue) - { - return RandomBoolean(maxValue); - } - - public bool TryRandomBool() - { - return RandomBoolean(); - } - - public IPrtValue TryRandom(IPrtValue param) - { - switch (param) - { - case PrtInt maxValue: - { - TryAssert(maxValue <= 10000, $"choose expects a parameter with at most 10000 choices, got {maxValue} choices instead."); - return (PrtInt)TryRandomInt(maxValue); - } - - case PrtSeq seq: - { - TryAssert(seq.Any(), "Trying to choose from an empty sequence!"); - TryAssert(seq.Count <= 10000, $"choose expects a parameter with at most 10000 choices, got {seq.Count} choices instead."); - return seq[TryRandomInt(seq.Count)]; - } - case PrtSet set: - { - TryAssert(set.Any(), "Trying to choose from an empty set!"); - TryAssert(set.Count <= 10000, $"choose expects a parameter with at most 10000 choices, got {set.Count} choices instead."); - return set.ElementAt(TryRandomInt(set.Count)); - } - case PrtMap map: - { - TryAssert(map.Any(), "Trying to choose from an empty map!"); - TryAssert(map.Keys.Count <= 10000, $"choose expects a parameter with at most 10000 choices, got {map.Keys.Count} choices instead."); - return map.Keys.ElementAt(TryRandomInt(map.Keys.Count)); - } - default: - throw new PInternalException("This is an unexpected (internal) P exception. Please report to the P Developers"); - } - } - - public void LogLine(string message) - { - Logger.WriteLine($" {message}"); - - // Log message to JSON output - JsonLogger.AddLogType(JsonWriter.LogType.Print); - JsonLogger.AddLog(message); - JsonLogger.AddToLogs(updateVcMap: false); - } - - public void Log(string message) - { - Logger.Write($"{message}"); - } - - public void Announce(Event ev, object payload = null) - { - Assert(ev != null, "Machine cannot announce a null event"); - if (ev is PHalt) - { - ev = HaltEvent.Instance; - } - - var oneArgConstructor = ev.GetType().GetConstructors().First(x => x.GetParameters().Length > 0); - var @event = (Event)oneArgConstructor.Invoke(new[] { payload }); - var pText = payload == null ? "" : $" with payload {((IPrtValue)payload).ToEscapedString()}"; - - Logger.WriteLine($" '{Id}' announced event '{ev.GetType().Name}'{pText}."); - - // Log message to JSON output - JsonLogger.AddLogType(JsonWriter.LogType.Announce); - JsonLogger.LogDetails.Id = $"{Id}"; - JsonLogger.LogDetails.Event = ev.GetType().Name; - if (payload != null) - { - JsonLogger.LogDetails.Payload = ((IPrtValue)payload).ToDict(); - } - JsonLogger.AddLog($"{Id} announced event {ev.GetType().Name}{pText}."); - JsonLogger.AddToLogs(updateVcMap: true); - - AnnounceInternal(@event); - } - - private void AnnounceInternal(Event ev) - { - Assert(ev != null, "cannot send a null event"); - if (!PModule.monitorMap.ContainsKey(interfaceName)) - { - return; - } - - foreach (var monitor in PModule.monitorMap[interfaceName]) - { - if (PModule.monitorObserves[monitor.Name].Contains(ev.GetType().Name)) - { - Monitor(monitor, ev); - } - } - } - - public class InitializeParameters : IPrtValue - { - public InitializeParameters(string interfaceName, IPrtValue payload) - { - InterfaceName = interfaceName; - Payload = payload; - } - - public string InterfaceName { get; } - public IPrtValue Payload { get; } - - public bool Equals(IPrtValue other) - { - throw new NotImplementedException(); - } - - public IPrtValue Clone() - { - throw new NotImplementedException(); - } - - public object ToDict() - { - throw new NotImplementedException(); - } - } - - public class InitializeParametersEvent : PEvent - { - public InitializeParametersEvent(InitializeParameters payload) : base(payload) - { - } - } - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/PRuntime/PMonitor.cs b/Src/PChecker/CheckerCore/PRuntime/PMonitor.cs deleted file mode 100644 index 08289f4cc3..0000000000 --- a/Src/PChecker/CheckerCore/PRuntime/PMonitor.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using PChecker.Actors.Events; -using PChecker.Actors.Logging; -using PChecker.Specifications.Monitors; - -namespace PChecker.PRuntime -{ - public class PMonitor : Monitor - { - public static List observes = new List(); - - public object gotoPayload; - - public void TryRaiseEvent(Event ev, object payload = null) - { - Assert(!(ev is DefaultEvent), "Monitor cannot raise a null event"); - var oneArgConstructor = ev.GetType().GetConstructors().First(x => x.GetParameters().Length > 0); - var @event = (Event)oneArgConstructor.Invoke(new[] { payload }); - RaiseEvent(@event); - } - - public void TryGotoState(object payload = null) where T : State - { - gotoPayload = payload; - RaiseGotoStateEvent(); - } - - public void TryAssert(bool predicate) - { - Assert(predicate); - } - - public void TryAssert(bool predicate, string s, params object[] args) - { - Assert(predicate, s, args); - } - - public void LogLine(string message) - { - Logger.WriteLine($" {message}"); - - // Log message to JSON output - JsonLogger.AddLogType(JsonWriter.LogType.Print); - JsonLogger.AddLog(message); - JsonLogger.AddToLogs(updateVcMap: false); - } - - public void Log(string message) - { - Logger.Write($"{message}"); - } - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/PRuntime/PrtValues.cs b/Src/PChecker/CheckerCore/PRuntime/PrtValues.cs deleted file mode 100644 index 6b56ffff04..0000000000 --- a/Src/PChecker/CheckerCore/PRuntime/PrtValues.cs +++ /dev/null @@ -1,56 +0,0 @@ -using PChecker.PRuntime.Values; - -namespace PChecker.PRuntime -{ - public static class PrtValues - { - public static PrtBool Box(bool value) - { - return value; - } - - public static PrtInt Box(long value) - { - return new PrtInt(value); - } - - public static PrtInt Box(int value) - { - return new PrtInt(value); - } - - public static PrtInt Box(short value) - { - return new PrtInt(value); - } - - public static PrtInt Box(byte value) - { - return new PrtInt(value); - } - - public static PrtFloat Box(double value) - { - return new PrtFloat(value); - } - - public static PrtFloat Box(float value) - { - return new PrtFloat(value); - } - - public static PrtBool SafeEquals(IPrtValue val1, IPrtValue val2) - { - return ReferenceEquals(val1, val2) || val1 != null && val1.Equals(val2); - } - - public static IPrtValue PrtCastValue(IPrtValue value, PrtType type) - { - //todo: Needs to be fixed for better error message - /*if (!PrtInhabitsType(value, type)) - throw new PrtInhabitsTypeException( - $"value {value.ToString()} is not a member of type {type.ToString()}");*/ - return value.Clone(); - } - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/PRuntime/Values/IPrtMutableValue.cs b/Src/PChecker/CheckerCore/PRuntime/Values/IPrtMutableValue.cs deleted file mode 100644 index b8b3d2c153..0000000000 --- a/Src/PChecker/CheckerCore/PRuntime/Values/IPrtMutableValue.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace PChecker.PRuntime.Values -{ - public interface IPrtMutableValue : IPrtValue - { - void Freeze(); - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/PRuntime/Values/PrtFloat.cs b/Src/PChecker/CheckerCore/PRuntime/Values/PrtFloat.cs deleted file mode 100644 index d46e38daa7..0000000000 --- a/Src/PChecker/CheckerCore/PRuntime/Values/PrtFloat.cs +++ /dev/null @@ -1,147 +0,0 @@ -using System; -using System.Runtime.CompilerServices; - -namespace PChecker.PRuntime.Values -{ - [Serializable] - public readonly struct PrtFloat : IPrtValue - { - private readonly double value; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public PrtFloat(double value) - { - this.value = value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public IPrtValue Clone() - { - return this; - } - - public override string ToString() - { - return value.ToString(); - } - - public object ToDict() - { - return value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(IPrtValue other) - { - return other is PrtFloat f && value == f.value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override bool Equals(object val) - { - return val is PrtFloat other && Equals(value, other.value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return value.GetHashCode(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator double(in PrtFloat val) - { - return val.value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator PrtFloat(float val) - { - return new PrtFloat(val); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator PrtFloat(double val) - { - return new PrtFloat(val); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator PrtFloat(PrtInt val) - { - return new PrtFloat(val); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtFloat operator +(in PrtFloat prtFloat1, in PrtFloat prtFloat2) - { - return new PrtFloat(prtFloat1.value + prtFloat2.value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtFloat operator -(in PrtFloat prtFloat1, in PrtFloat prtFloat2) - { - return new PrtFloat(prtFloat1.value - prtFloat2.value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtFloat operator *(in PrtFloat prtFloat1, in PrtFloat prtFloat2) - { - return new PrtFloat(prtFloat1.value * prtFloat2.value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtFloat operator /(in PrtFloat prtFloat1, in PrtFloat prtFloat2) - { - return new PrtFloat(prtFloat1.value / prtFloat2.value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator <(in PrtFloat prtFloat1, in PrtFloat prtFloat2) - { - return prtFloat1.value < prtFloat2.value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator >(in PrtFloat prtFloat1, in PrtFloat prtFloat2) - { - return prtFloat1.value > prtFloat2.value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator <=(in PrtFloat prtFloat1, in PrtFloat prtFloat2) - { - return prtFloat1.value <= prtFloat2.value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator >=(in PrtFloat prtFloat1, in PrtFloat prtFloat2) - { - return prtFloat1.value >= prtFloat2.value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator ==(in PrtFloat prtFloat1, in PrtFloat prtFloat2) - { - return Equals(prtFloat1.value, prtFloat2.value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator !=(in PrtFloat prtFloat1, in PrtFloat prtFloat2) - { - return Equals(prtFloat1.value, prtFloat2.value) == false; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtFloat operator +(in PrtFloat prtFloat) - { - return new PrtFloat(+prtFloat.value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtFloat operator -(in PrtFloat prtFloat) - { - return new PrtFloat(-prtFloat.value); - } - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/PRuntime/Values/PrtInt.cs b/Src/PChecker/CheckerCore/PRuntime/Values/PrtInt.cs deleted file mode 100644 index f381ec8cd6..0000000000 --- a/Src/PChecker/CheckerCore/PRuntime/Values/PrtInt.cs +++ /dev/null @@ -1,185 +0,0 @@ -using System; -using System.Runtime.CompilerServices; - -namespace PChecker.PRuntime.Values -{ - [Serializable] - public readonly struct PrtInt : IPrtValue - { - private readonly long value; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public PrtInt(long value) - { - this.value = value; - } - - public bool Equals(IPrtValue other) - { - return other is PrtInt i && value == i.value; - } - - public IPrtValue Clone() - { - return this; - } - - public override bool Equals(object val) - { - return val is PrtInt other && Equals(value, other.value); - } - - public override int GetHashCode() - { - return value.GetHashCode(); - } - - public override string ToString() - { - return value.ToString(); - } - - public object ToDict() - { - return value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator PrtInt(byte val) - { - return new PrtInt(val); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator PrtInt(short val) - { - return new PrtInt(val); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator PrtInt(int val) - { - return new PrtInt(val); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator PrtInt(long val) - { - return new PrtInt(val); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator PrtInt(in PrtFloat val) - { - return new PrtInt((long)val); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator int(in PrtInt val) - { - return (int)val.value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator long(in PrtInt val) - { - return val.value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtInt operator +(in PrtInt prtInt1, in PrtInt prtInt2) - { - return new PrtInt(prtInt1.value + prtInt2.value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtInt operator -(in PrtInt prtInt1, in PrtInt prtInt2) - { - return new PrtInt(prtInt1.value - prtInt2.value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtInt operator *(in PrtInt prtInt1, in PrtInt prtInt2) - { - return new PrtInt(prtInt1.value * prtInt2.value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtInt operator /(in PrtInt prtInt1, in PrtInt prtInt2) - { - return new PrtInt(prtInt1.value / prtInt2.value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator <(in PrtInt prtInt1, in PrtInt prtInt2) - { - return prtInt1.value < prtInt2.value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator >(in PrtInt prtInt1, in PrtInt prtInt2) - { - return prtInt1.value > prtInt2.value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator <=(in PrtInt prtInt1, in PrtInt prtInt2) - { - return prtInt1.value <= prtInt2.value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator >=(in PrtInt prtInt1, in PrtInt prtInt2) - { - return prtInt1.value >= prtInt2.value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator ==(in PrtInt prtInt1, in PrtInt prtInt2) - { - return Equals(prtInt1.value, prtInt2.value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator ==(in IPrtValue prtInt1, in PrtInt prtInt2) - { - return prtInt1 is PrtInt int1 && Equals(int1.value, prtInt2.value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator !=(in IPrtValue prtInt1, in PrtInt prtInt2) - { - return prtInt1 is PrtInt int1 && !Equals(int1.value, prtInt2.value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator ==(in PrtInt prtInt1, in IPrtValue prtInt2) - { - return prtInt2 is PrtInt int2 && Equals(prtInt1.value, int2.value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator !=(in PrtInt prtInt1, in IPrtValue prtInt2) - { - return prtInt2 is PrtInt int2 && !Equals(prtInt1.value, int2.value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator !=(in PrtInt prtInt1, in PrtInt prtInt2) - { - return Equals(prtInt1.value, prtInt2.value) == false; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtInt operator +(in PrtInt prtInt) - { - return new PrtInt(+prtInt.value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtInt operator -(in PrtInt prtInt) - { - return new PrtInt(-prtInt.value); - } - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/PRuntime/Values/PrtString.cs b/Src/PChecker/CheckerCore/PRuntime/Values/PrtString.cs deleted file mode 100644 index 92ef3fcaaf..0000000000 --- a/Src/PChecker/CheckerCore/PRuntime/Values/PrtString.cs +++ /dev/null @@ -1,197 +0,0 @@ -using System; -using System.Runtime.CompilerServices; - -namespace PChecker.PRuntime.Values -{ - [Serializable] - public readonly struct PrtString : IPrtValue - { - public bool Equals(PrtString other) - { - return string.Equals(value, other.value); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) - { - return false; - } - - return obj is PrtString other && Equals(other); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public IPrtValue Clone() - { - return this; - } - - private readonly string value; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator PrtString(string val) - { - return new PrtString(val); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator string(PrtString val) - { - return val.value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private PrtString(string value) - { - this.value = value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtString operator +(in PrtString prtString1, in PrtString prtString2) - { - return new PrtString(prtString1.value + prtString2.value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(in PrtString pValue1, in PrtString pValue2) - { - return Equals(pValue1, pValue2); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(in PrtString pValue1, in PrtString pValue2) - { - return !Equals(pValue1, pValue2); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(in PrtString pValue1, in IPrtValue pValue2) - { - return pValue2 is PrtString prtString && string.Equals(pValue1.value, prtString.value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(in PrtString pValue1, in IPrtValue pValue2) - { - return pValue2 is PrtString prtString && !string.Equals(pValue1.value, prtString.value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(in IPrtValue pValue1, in PrtString pValue2) - { - return pValue1 is PrtString prtString && string.Equals(pValue2.value, prtString.value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(in IPrtValue pValue1, in PrtString pValue2) - { - return pValue1 is PrtString prtString && !string.Equals(pValue2.value, prtString.value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator <(in PrtString prtString1, in PrtString prtString2) - { - return string.Compare(prtString1.value, prtString2.value) == -1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator <(in IPrtValue pValue1, in PrtString pValue2) - { - return pValue1 is PrtString prtString && string.Compare(prtString.value, pValue2.value) == -1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator <(in PrtString pValue1, in IPrtValue pValue2) - { - return pValue2 is PrtString prtString && string.Compare(prtString.value, pValue1.value) == -1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator >(in PrtString prtString1, in PrtString prtString2) - { - return string.Compare(prtString1.value, prtString2.value) == 1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator >(in IPrtValue pValue1, in PrtString pValue2) - { - return pValue1 is PrtString prtString && string.Compare(prtString.value, pValue2.value) == 1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator >(in PrtString pValue1, in IPrtValue pValue2) - { - return pValue2 is PrtString prtString && string.Compare(prtString.value, pValue1.value) == 1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator <=(in PrtString prtString1, in PrtString prtString2) - { - return string.Compare(prtString1.value, prtString2.value) != 1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator <=(in IPrtValue pValue1, in PrtString pValue2) - { - return pValue1 is PrtString prtString && string.Compare(prtString.value, pValue2.value) != 1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator <=(in PrtString pValue1, in IPrtValue pValue2) - { - return pValue2 is PrtString prtString && string.Compare(prtString.value, pValue1.value) != 1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator >=(in PrtString prtString1, in PrtString prtString2) - { - return string.Compare(prtString1.value, prtString2.value) != -1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator >=(in IPrtValue pValue1, in PrtString pValue2) - { - return pValue1 is PrtString prtString && string.Compare(prtString.value, pValue2.value) != -1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator >=(in PrtString pValue1, in IPrtValue pValue2) - { - return pValue2 is PrtString prtString && string.Compare(prtString.value, pValue1.value) != -1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(IPrtValue obj) - { - return obj is PrtString other && string.Equals(value, other.value); - } - - public override int GetHashCode() - { - return value.GetHashCode(); - } - - public override string ToString() - { - return value; - } - - /// - /// Like ToString, but emits a representation of a string literal, surrounded by double-quotes, - /// and where all interior double-quotes are escaped. - /// - /// - public string ToEscapedString() - { - var v = value ?? ""; - return $"\"{v.Replace("\"", "\\\"")}\""; - } - - - public object ToDict() - { - return ToString(); - } - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Random/Generator.cs b/Src/PChecker/CheckerCore/Random/Generator.cs index 358c50bc7a..e7c4f474e6 100644 --- a/Src/PChecker/CheckerCore/Random/Generator.cs +++ b/Src/PChecker/CheckerCore/Random/Generator.cs @@ -2,7 +2,7 @@ // Licensed under the MIT License. using System.Runtime.CompilerServices; -using PChecker.Runtime; +using PChecker.SystematicTesting; namespace PChecker.Random { @@ -12,23 +12,19 @@ namespace PChecker.Random /// During systematic testing, the generation of random values is controlled, which /// allows the runtime to explore combinations of choices to find bugs. /// - /// - /// See Program non-determinism - /// for more information. - /// public class Generator { /// /// The runtime associated with this random value generator. /// - internal readonly CoyoteRuntime Runtime; + internal readonly ControlledRuntime Runtime; /// /// Initializes a new instance of the class. /// private Generator() { - Runtime = CoyoteRuntime.Current; + Runtime = ControlledRuntime.Current; } /// diff --git a/Src/PChecker/CheckerCore/Random/IRandomValueGenerator.cs b/Src/PChecker/CheckerCore/Random/IRandomValueGenerator.cs index 8e3084ced9..60cd4b0847 100644 --- a/Src/PChecker/CheckerCore/Random/IRandomValueGenerator.cs +++ b/Src/PChecker/CheckerCore/Random/IRandomValueGenerator.cs @@ -6,7 +6,7 @@ namespace PChecker.Random /// /// Interface for random value generators. /// - internal interface IRandomValueGenerator + public interface IRandomValueGenerator { /// /// The seed currently used by the generator. diff --git a/Src/PChecker/CheckerCore/Runtime/CoyoteRuntime.cs b/Src/PChecker/CheckerCore/Runtime/CoyoteRuntime.cs deleted file mode 100644 index 058d314c32..0000000000 --- a/Src/PChecker/CheckerCore/Runtime/CoyoteRuntime.cs +++ /dev/null @@ -1,300 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using PChecker.Actors.Events; -using PChecker.Exceptions; -using PChecker.Random; -using Monitor = PChecker.Specifications.Monitors.Monitor; - -namespace PChecker.Runtime -{ - /// - /// Runtime for executing asynchronous operations. - /// - internal abstract class CoyoteRuntime : ICoyoteRuntime - { - /// - /// Provides access to the runtime associated with each asynchronous control flow. - /// - /// - /// In testing mode, each testing schedule uses a unique runtime instance. To safely - /// retrieve it from static methods, we store it in each asynchronous control flow. - /// - private static readonly AsyncLocal AsyncLocalInstance = new AsyncLocal(); - - /// - /// The currently executing runtime. - /// - internal static CoyoteRuntime Current => AsyncLocalInstance.Value ?? - (IsExecutionControlled ? throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, - "Uncontrolled task '{0}' invoked a runtime method. Please make sure to avoid using concurrency APIs " + - "(e.g. 'Task.Run', 'Task.Delay' or 'Task.Yield' from the 'System.Threading.Tasks' namespace) inside " + - "actor handlers or controlled tasks. If you are using external libraries that are executing concurrently, " + - "you will need to mock them during testing.", - Task.CurrentId.HasValue ? Task.CurrentId.Value.ToString() : "")) : - RuntimeFactory.InstalledRuntime); - - /// - /// If true, the program execution is controlled by the runtime to - /// explore interleavings and sources of nondeterminism, else false. - /// - internal static bool IsExecutionControlled { get; private protected set; } = false; - - /// - /// The checkerConfiguration used by the runtime. - /// - protected internal readonly CheckerConfiguration CheckerConfiguration; - - /// - /// List of monitors in the program. - /// - protected readonly List Monitors; - - /// - /// Responsible for generating random values. - /// - protected readonly IRandomValueGenerator ValueGenerator; - - /// - /// Monotonically increasing operation id counter. - /// - private long OperationIdCounter; - - /// - /// Records if the runtime is running. - /// - protected internal volatile bool IsRunning; - - /// - /// Used to log text messages. Use - /// to replace the logger with a custom one. - /// - public abstract TextWriter Logger { get; } - - /// - /// Callback that is fired when the Coyote program throws an exception which includes failed assertions. - /// - public event OnFailureHandler OnFailure; - - /// - /// Initializes a new instance of the class. - /// - protected CoyoteRuntime(CheckerConfiguration checkerConfiguration, IRandomValueGenerator valueGenerator) - { - CheckerConfiguration = checkerConfiguration; - Monitors = new List(); - ValueGenerator = valueGenerator; - OperationIdCounter = 0; - IsRunning = true; - } - - /// - /// Registers a new specification monitor of the specified . - /// - public void RegisterMonitor() - where T : Monitor => - TryCreateMonitor(typeof(T)); - - /// - /// Invokes the specified monitor with the specified . - /// - public void Monitor(Event e) - where T : Monitor - { - // If the event is null then report an error and exit. - Assert(e != null, "Cannot monitor a null event."); - Monitor(typeof(T), e, null, null, null); - } - - /// - /// Returns a nondeterministic boolean choice, that can be controlled - /// during analysis or testing. - /// - public bool RandomBoolean() => GetNondeterministicBooleanChoice(2, null, null); - - /// - /// Returns a nondeterministic boolean choice, that can be controlled - /// during analysis or testing. The value is used to generate a number - /// in the range [0..maxValue), where 0 triggers true. - /// - public bool RandomBoolean(int maxValue) => GetNondeterministicBooleanChoice(maxValue, null, null); - - /// - /// Returns a nondeterministic integer, that can be controlled during - /// analysis or testing. The value is used to generate an integer in - /// the range [0..maxValue). - /// - public int RandomInteger(int maxValue) => GetNondeterministicIntegerChoice(maxValue, null, null); - - /// - /// Returns the next available unique operation id. - /// - /// Value representing the next available unique operation id. - internal ulong GetNextOperationId() => - // Atomically increments and safely wraps the value into an unsigned long. - (ulong)Interlocked.Increment(ref OperationIdCounter) - 1; - - /// - /// Tries to create a new of the specified . - /// - internal abstract void TryCreateMonitor(Type type); - - /// - /// Invokes the specified with the specified . - /// - internal virtual void Monitor(Type type, Event e, string senderName, string senderType, string senderState) - { - Monitor monitor = null; - - lock (Monitors) - { - foreach (var m in Monitors) - { - if (m.GetType() == type) - { - monitor = m; - break; - } - } - } - - if (monitor != null) - { - lock (monitor) - { - monitor.MonitorEvent(e, senderName, senderType, senderState); - } - } - } - - /// - /// Checks if the assertion holds, and if not, throws an exception. - /// - public virtual void Assert(bool predicate) - { - if (!predicate) - { - throw new AssertionFailureException("Detected an assertion failure."); - } - } - - /// - /// Checks if the assertion holds, and if not, throws an exception. - /// - public virtual void Assert(bool predicate, string s, object arg0) - { - if (!predicate) - { - throw new AssertionFailureException(string.Format(CultureInfo.InvariantCulture, s, arg0?.ToString())); - } - } - - /// - /// Checks if the assertion holds, and if not, throws an exception. - /// - public virtual void Assert(bool predicate, string s, object arg0, object arg1) - { - if (!predicate) - { - throw new AssertionFailureException(string.Format(CultureInfo.InvariantCulture, s, arg0?.ToString(), arg1?.ToString())); - } - } - - /// - /// Checks if the assertion holds, and if not, throws an exception. - /// - public virtual void Assert(bool predicate, string s, object arg0, object arg1, object arg2) - { - if (!predicate) - { - throw new AssertionFailureException(string.Format(CultureInfo.InvariantCulture, s, arg0?.ToString(), arg1?.ToString(), arg2?.ToString())); - } - } - - /// - /// Checks if the assertion holds, and if not, throws an exception. - /// - public virtual void Assert(bool predicate, string s, params object[] args) - { - if (!predicate) - { - throw new AssertionFailureException(string.Format(CultureInfo.InvariantCulture, s, args)); - } - } - - /// - /// Returns a controlled nondeterministic boolean choice. - /// - internal abstract bool GetNondeterministicBooleanChoice(int maxValue, string callerName, string callerType); - - /// - /// Returns a controlled nondeterministic integer choice. - /// - internal abstract int GetNondeterministicIntegerChoice(int maxValue, string callerName, string callerType); - - /// - /// Assigns the specified runtime as the default for the current asynchronous control flow. - /// - internal static void AssignAsyncControlFlowRuntime(CoyoteRuntime runtime) => AsyncLocalInstance.Value = runtime; - - /// - /// Use this method to override the default for logging messages. - /// - public abstract TextWriter SetLogger(TextWriter logger); - - /// - /// Raises the event with the specified . - /// - protected internal virtual void RaiseOnFailureEvent(Exception exception) - { - OnFailure?.Invoke(exception); - } - - /// - /// Throws an exception - /// containing the specified exception. - /// - internal virtual void WrapAndThrowException(Exception exception, string s, params object[] args) - { - var msg = string.Format(CultureInfo.InvariantCulture, s, args); - var message = string.Format(CultureInfo.InvariantCulture, - "Exception '{0}' was thrown in {1}: {2}\n" + - "from location '{3}':\n" + - "The stack trace is:\n{4}", - exception.GetType(), msg, exception.Message, exception.Source, exception.StackTrace); - - throw new AssertionFailureException(message, exception); - } - - /// - /// Terminates the runtime and notifies each active actor to halt execution. - /// - public void Stop() => IsRunning = false; - - /// - /// Disposes runtime resources. - /// - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - OperationIdCounter = 0; - } - } - - /// - /// Disposes runtime resources. - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Actors/Events/DefaultEvent.cs b/Src/PChecker/CheckerCore/Runtime/Events/DefaultEvent.cs similarity index 95% rename from Src/PChecker/CheckerCore/Actors/Events/DefaultEvent.cs rename to Src/PChecker/CheckerCore/Runtime/Events/DefaultEvent.cs index bf430e673a..ef1d57e413 100644 --- a/Src/PChecker/CheckerCore/Actors/Events/DefaultEvent.cs +++ b/Src/PChecker/CheckerCore/Runtime/Events/DefaultEvent.cs @@ -3,7 +3,7 @@ using System.Runtime.Serialization; -namespace PChecker.Actors.Events +namespace PChecker.Runtime.Events { /// /// A default event that is generated by the runtime when diff --git a/Src/PChecker/CheckerCore/Runtime/Events/Event.cs b/Src/PChecker/CheckerCore/Runtime/Events/Event.cs new file mode 100644 index 0000000000..b8bbf5b178 --- /dev/null +++ b/Src/PChecker/CheckerCore/Runtime/Events/Event.cs @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Runtime.Serialization; +using PChecker.Runtime.Values; + +namespace PChecker.Runtime.Events +{ + /// + /// Class representing an event. + /// + [DataContract] + public class Event: IPValue + { + public Event() + { + } + + public Event(IPValue payload) + { + Payload = payload; + } + + public IPValue Payload { get; set; } + + public bool Equals(IPValue other) + { + return other != null && GetType().FullName.Equals(other.GetType().FullName); + } + + public virtual IPValue Clone() + { + throw new NotImplementedException(); + } + + public object ToDict() + { + return this.GetType().Name; + } + + public override bool Equals(object obj) + { + return obj is Event other && Equals(other); + } + + public override int GetHashCode() + { + return GetType().FullName.GetHashCode(); + } + + public override string ToString() + { + return GetType().Name; + } + } + + public class PHalt : Event + { + public PHalt(IPValue payload) : base(payload) + { + } + } +} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Actors/Events/EventInfo.cs b/Src/PChecker/CheckerCore/Runtime/Events/EventInfo.cs similarity index 78% rename from Src/PChecker/CheckerCore/Actors/Events/EventInfo.cs rename to Src/PChecker/CheckerCore/Runtime/Events/EventInfo.cs index d11359d704..a4de780989 100644 --- a/Src/PChecker/CheckerCore/Actors/Events/EventInfo.cs +++ b/Src/PChecker/CheckerCore/Runtime/Events/EventInfo.cs @@ -3,7 +3,7 @@ using System.Runtime.Serialization; -namespace PChecker.Actors.Events +namespace PChecker.Runtime.Events { /// /// Contains an , and its associated metadata. @@ -23,19 +23,12 @@ internal class EventInfo [DataMember] internal EventOriginInfo OriginInfo { get; private set; } - /// - /// User-defined hash of the event. The default value is 0. Override to - /// improve the accuracy of stateful techniques during testing. - /// - internal int HashedState { get; set; } - /// /// Initializes a new instance of the class. /// internal EventInfo(Event e) { EventName = e.GetType().FullName; - HashedState = 0; } /// diff --git a/Src/PChecker/CheckerCore/Actors/Events/EventOriginInfo.cs b/Src/PChecker/CheckerCore/Runtime/Events/EventOriginInfo.cs similarity index 59% rename from Src/PChecker/CheckerCore/Actors/Events/EventOriginInfo.cs rename to Src/PChecker/CheckerCore/Runtime/Events/EventOriginInfo.cs index 8aea77ed51..e8747703fe 100644 --- a/Src/PChecker/CheckerCore/Actors/Events/EventOriginInfo.cs +++ b/Src/PChecker/CheckerCore/Runtime/Events/EventOriginInfo.cs @@ -2,8 +2,9 @@ // Licensed under the MIT License. using System.Runtime.Serialization; +using PChecker.Runtime.StateMachines; -namespace PChecker.Actors.Events +namespace PChecker.Runtime.Events { /// /// Contains the origin information of an . @@ -12,16 +13,16 @@ namespace PChecker.Actors.Events internal class EventOriginInfo { /// - /// The sender actor id. + /// The sender state machine id. /// [DataMember] - internal ActorId SenderActorId { get; private set; } + internal StateMachineId SenderStateMachineId { get; private set; } /// - /// The sender actor name. + /// The sender state machine name. /// [DataMember] - internal string SenderActorName { get; private set; } + internal string SenderStateMachineName { get; private set; } /// /// The sender state name, if there is one. @@ -32,10 +33,10 @@ internal class EventOriginInfo /// /// Initializes a new instance of the class. /// - internal EventOriginInfo(ActorId senderActorId, string senderMachineName, string senderStateName) + internal EventOriginInfo(StateMachineId senderStateMachineId, string senderMachineName, string senderStateName) { - SenderActorId = senderActorId; - SenderActorName = senderMachineName; + SenderStateMachineId = senderStateMachineId; + SenderStateMachineName = senderMachineName; SenderStateName = senderStateName; } } diff --git a/Src/PChecker/CheckerCore/Actors/Events/GotoStateEvent.cs b/Src/PChecker/CheckerCore/Runtime/Events/GotoStateEvent.cs similarity index 95% rename from Src/PChecker/CheckerCore/Actors/Events/GotoStateEvent.cs rename to Src/PChecker/CheckerCore/Runtime/Events/GotoStateEvent.cs index ef8eadf02b..2e20b61447 100644 --- a/Src/PChecker/CheckerCore/Actors/Events/GotoStateEvent.cs +++ b/Src/PChecker/CheckerCore/Runtime/Events/GotoStateEvent.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.Serialization; -namespace PChecker.Actors.Events +namespace PChecker.Runtime.Events { /// /// The goto state event. diff --git a/Src/PChecker/CheckerCore/Actors/Events/HaltEvent.cs b/Src/PChecker/CheckerCore/Runtime/Events/HaltEvent.cs similarity index 94% rename from Src/PChecker/CheckerCore/Actors/Events/HaltEvent.cs rename to Src/PChecker/CheckerCore/Runtime/Events/HaltEvent.cs index e1dcc6e064..aaa47c281c 100644 --- a/Src/PChecker/CheckerCore/Actors/Events/HaltEvent.cs +++ b/Src/PChecker/CheckerCore/Runtime/Events/HaltEvent.cs @@ -3,7 +3,7 @@ using System.Runtime.Serialization; -namespace PChecker.Actors.Events +namespace PChecker.Runtime.Events { /// /// The halt event. diff --git a/Src/PChecker/CheckerCore/Actors/Events/QuiescentEvent.cs b/Src/PChecker/CheckerCore/Runtime/Events/QuiescentEvent.cs similarity index 50% rename from Src/PChecker/CheckerCore/Actors/Events/QuiescentEvent.cs rename to Src/PChecker/CheckerCore/Runtime/Events/QuiescentEvent.cs index 9b0649273c..5b9722485f 100644 --- a/Src/PChecker/CheckerCore/Actors/Events/QuiescentEvent.cs +++ b/Src/PChecker/CheckerCore/Runtime/Events/QuiescentEvent.cs @@ -2,27 +2,28 @@ // Licensed under the MIT License. using System.Runtime.Serialization; +using PChecker.Runtime.StateMachines; -namespace PChecker.Actors.Events +namespace PChecker.Runtime.Events { /// - /// Signals that an actor has reached quiescence. + /// Signals that an state machine has reached quiescence. /// [DataContract] internal sealed class QuiescentEvent : Event { /// - /// The id of the actor that has reached quiescence. + /// The id of the state machine that has reached quiescence. /// - public ActorId ActorId; + public StateMachineId StateMachineId; /// /// Initializes a new instance of the class. /// - /// The id of the actor that has reached quiescence. - public QuiescentEvent(ActorId id) + /// The id of the state machine that has reached quiescence. + public QuiescentEvent(StateMachineId id) { - ActorId = id; + StateMachineId = id; } } } \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Actors/Events/WildcardEvent.cs b/Src/PChecker/CheckerCore/Runtime/Events/WildcardEvent.cs similarity index 93% rename from Src/PChecker/CheckerCore/Actors/Events/WildcardEvent.cs rename to Src/PChecker/CheckerCore/Runtime/Events/WildcardEvent.cs index bba77fd07d..ab8e869ab6 100644 --- a/Src/PChecker/CheckerCore/Actors/Events/WildcardEvent.cs +++ b/Src/PChecker/CheckerCore/Runtime/Events/WildcardEvent.cs @@ -3,7 +3,7 @@ using System.Runtime.Serialization; -namespace PChecker.Actors.Events +namespace PChecker.Runtime.Events { /// /// The wild card event. diff --git a/Src/PChecker/CheckerCore/PRuntime/Exceptions/PIllegalCoercionException.cs b/Src/PChecker/CheckerCore/Runtime/Exceptions/PIllegalCoercionException.cs similarity index 90% rename from Src/PChecker/CheckerCore/PRuntime/Exceptions/PIllegalCoercionException.cs rename to Src/PChecker/CheckerCore/Runtime/Exceptions/PIllegalCoercionException.cs index bea5bb9003..d57692888a 100644 --- a/Src/PChecker/CheckerCore/PRuntime/Exceptions/PIllegalCoercionException.cs +++ b/Src/PChecker/CheckerCore/Runtime/Exceptions/PIllegalCoercionException.cs @@ -1,6 +1,6 @@ using System; -namespace PChecker.PRuntime.Exceptions +namespace PChecker.Runtime.Exceptions { public class PIllegalCoercionException : Exception { diff --git a/Src/PChecker/CheckerCore/PRuntime/Exceptions/PInternalException.cs b/Src/PChecker/CheckerCore/Runtime/Exceptions/PInternalException.cs similarity index 90% rename from Src/PChecker/CheckerCore/PRuntime/Exceptions/PInternalException.cs rename to Src/PChecker/CheckerCore/Runtime/Exceptions/PInternalException.cs index eb52b9c48e..b137fb8191 100644 --- a/Src/PChecker/CheckerCore/PRuntime/Exceptions/PInternalException.cs +++ b/Src/PChecker/CheckerCore/Runtime/Exceptions/PInternalException.cs @@ -1,6 +1,6 @@ using System; -namespace PChecker.PRuntime.Exceptions +namespace PChecker.Runtime.Exceptions { public class PInternalException : Exception { diff --git a/Src/PChecker/CheckerCore/PRuntime/Exceptions/PNonStandardReturnException.cs b/Src/PChecker/CheckerCore/Runtime/Exceptions/PNonStandardReturnException.cs similarity index 93% rename from Src/PChecker/CheckerCore/PRuntime/Exceptions/PNonStandardReturnException.cs rename to Src/PChecker/CheckerCore/Runtime/Exceptions/PNonStandardReturnException.cs index 482d4cec51..4e99576472 100644 --- a/Src/PChecker/CheckerCore/PRuntime/Exceptions/PNonStandardReturnException.cs +++ b/Src/PChecker/CheckerCore/Runtime/Exceptions/PNonStandardReturnException.cs @@ -1,6 +1,6 @@ using System; -namespace PChecker.PRuntime.Exceptions +namespace PChecker.Runtime.Exceptions { public enum NonStandardReturn { diff --git a/Src/PChecker/CheckerCore/PRuntime/Exceptions/PUnReachableCodeException.cs b/Src/PChecker/CheckerCore/Runtime/Exceptions/PUnReachableCodeException.cs similarity index 90% rename from Src/PChecker/CheckerCore/PRuntime/Exceptions/PUnReachableCodeException.cs rename to Src/PChecker/CheckerCore/Runtime/Exceptions/PUnReachableCodeException.cs index 1d2316f77c..cbfc5873c9 100644 --- a/Src/PChecker/CheckerCore/PRuntime/Exceptions/PUnReachableCodeException.cs +++ b/Src/PChecker/CheckerCore/Runtime/Exceptions/PUnReachableCodeException.cs @@ -1,6 +1,6 @@ using System; -namespace PChecker.PRuntime.Exceptions +namespace PChecker.Runtime.Exceptions { public class PUnreachableCodeException : Exception { diff --git a/Src/PChecker/CheckerCore/Runtime/ICoyoteRuntime.cs b/Src/PChecker/CheckerCore/Runtime/ICoyoteRuntime.cs deleted file mode 100644 index 72795194c8..0000000000 --- a/Src/PChecker/CheckerCore/Runtime/ICoyoteRuntime.cs +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.IO; -using PChecker.Actors.Events; -using PChecker.Exceptions; -using PChecker.Specifications.Monitors; - -namespace PChecker.Runtime -{ - /// - /// Interface that exposes base runtime methods for Coyote. - /// - public interface ICoyoteRuntime : IDisposable - { - /// - /// Used to log messages. Use - /// to replace the logger with a custom one. - /// - /// - /// See Logging for more information. - /// - TextWriter Logger { get; } - - /// - /// Callback that is fired when the runtime throws an exception which includes failed assertions. - /// - event OnFailureHandler OnFailure; - - /// - /// Registers a new specification monitor of the specified . - /// - /// Type of the monitor. - void RegisterMonitor() - where T : Monitor; - - /// - /// Invokes the specified monitor with the specified . - /// - /// Type of the monitor. - /// Event to send to the monitor. - void Monitor(Event e) - where T : Monitor; - - /// - /// Returns a nondeterministic boolean choice, that can be controlled - /// during analysis or testing. - /// - /// The nondeterministic boolean choice. - /// - /// See Program non-determinism - /// for more information. - /// - bool RandomBoolean(); - - /// - /// Returns a nondeterministic boolean choice, that can be controlled - /// during analysis or testing. The value is used to generate a number - /// in the range [0..maxValue), where 0 triggers true. - /// - /// The max value. - /// The nondeterministic boolean choice. - /// - /// See Program non-determinism - /// for more information. - /// - bool RandomBoolean(int maxValue); - - /// - /// Returns a nondeterministic integer choice, that can be - /// controlled during analysis or testing. The value is used - /// to generate an integer in the range [0..maxValue). - /// - /// The max value. - /// The nondeterministic integer choice. - /// - /// See Program non-determinism - /// for more information. - /// - int RandomInteger(int maxValue); - - /// - /// Checks if the assertion holds, and if not, throws an exception. - /// - /// The predicate to check. - void Assert(bool predicate); - - /// - /// Checks if the assertion holds, and if not, throws an exception. - /// - /// The predicate to check. - /// The message to print if the assertion fails. - /// The first argument. - void Assert(bool predicate, string s, object arg0); - - /// - /// Checks if the assertion holds, and if not, throws an exception. - /// - /// The predicate to check. - /// The message to print if the assertion fails. - /// The first argument. - /// The second argument. - void Assert(bool predicate, string s, object arg0, object arg1); - - /// - /// Checks if the assertion holds, and if not, throws an exception. - /// - /// The predicate to check. - /// The message to print if the assertion fails. - /// The first argument. - /// The second argument. - /// The third argument. - void Assert(bool predicate, string s, object arg0, object arg1, object arg2); - - /// - /// Checks if the assertion holds, and if not, throws an exception. - /// - /// The predicate to check. - /// The message to print if the assertion fails. - /// The message arguments. - void Assert(bool predicate, string s, params object[] args); - - /// - /// Use this method to override the default for logging messages. - /// - /// The logger to install. - /// The previously installed logger. - TextWriter SetLogger(TextWriter logger); - - /// - /// Terminates the runtime and notifies each active actor to halt execution. - /// - void Stop(); - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Actors/Logging/IActorRuntimeLog.cs b/Src/PChecker/CheckerCore/Runtime/Logging/IControlledRuntimeLog.cs similarity index 61% rename from Src/PChecker/CheckerCore/Actors/Logging/IActorRuntimeLog.cs rename to Src/PChecker/CheckerCore/Runtime/Logging/IControlledRuntimeLog.cs index ed4cb0b958..b765d62f5c 100644 --- a/Src/PChecker/CheckerCore/Actors/Logging/IActorRuntimeLog.cs +++ b/Src/PChecker/CheckerCore/Runtime/Logging/IControlledRuntimeLog.cs @@ -2,170 +2,163 @@ // Licensed under the MIT License. using System; -using PChecker.Actors.Events; +using PChecker.Runtime.Events; +using PChecker.Runtime.StateMachines; -namespace PChecker.Actors.Logging +namespace PChecker.Runtime.Logging { /// /// Interface that allows an external module to track what - /// is happening in the . + /// is happening in the . /// - public interface IActorRuntimeLog + public interface IControlledRuntimeLog { - /// - /// Invoked when the specified actor has been created. - /// - /// The id of the actor that has been created. - /// The name of the creator, or null. - /// The type of the creator, or null. - void OnCreateActor(ActorId id, string creatorName, string creatorType); - /// /// Invoked when the specified state machine has been created. /// /// The id of the state machine that has been created. /// The name of the creator, or null. /// The type of the creator, or null. - void OnCreateStateMachine(ActorId id, string creatorName, string creatorType); + void OnCreateStateMachine(StateMachineId id, string creatorName, string creatorType); /// - /// Invoked when the specified actor executes an action. + /// Invoked when the specified state machine executes an action. /// - /// The id of the actor executing the action. + /// The id of the state machine executing the action. /// The state that declared this action (can be different from currentStateName in the case of pushed states. - /// The state name, if the actor is a state machine and a state exists, else null. + /// The state name, if the state machine is a state machine and a state exists, else null. /// The name of the action being executed. - void OnExecuteAction(ActorId id, string handlingStateName, string currentStateName, string actionName); + void OnExecuteAction(StateMachineId id, string handlingStateName, string currentStateName, string actionName); /// - /// Invoked when the specified event is sent to a target actor. + /// Invoked when the specified event is sent to a target state machine. /// - /// The id of the target actor. + /// The id of the target state machine. /// The name of the sender, if any. /// The type of the sender, if any. /// The state name, if the sender is a state machine, else null. /// The event being sent. /// The id used to identify the send operation. - /// Is the target actor halted. - void OnSendEvent(ActorId targetActorId, string senderName, string senderType, string senderStateName, - Event e, Guid opGroupId, bool isTargetHalted); + /// Is the target state machine halted. + void OnSendEvent(StateMachineId targetStateMachineId, string senderName, string senderType, string senderStateName, + Event e, bool isTargetHalted); /// /// Invoked when the specified state machine raises an event. /// - /// The id of the actor raising the event. + /// The id of the state machine raising the event. /// The name of the current state. /// The event being raised. - void OnRaiseEvent(ActorId id, string stateName, Event e); + void OnRaiseEvent(StateMachineId id, string stateName, Event e); /// - /// Invoked when the specified event is about to be enqueued to an actor. + /// Invoked when the specified event is about to be enqueued to an state machine. /// - /// The id of the actor that the event is being enqueued to. + /// The id of the state machine that the event is being enqueued to. /// The event being enqueued. - void OnEnqueueEvent(ActorId id, Event e); + void OnEnqueueEvent(StateMachineId id, Event e); /// - /// Invoked when the specified event is dequeued by an actor. + /// Invoked when the specified event is dequeued by an state machine. /// - /// The id of the actor that the event is being dequeued by. - /// The state name, if the actor is a state machine and a state exists, else null. + /// The id of the state machine that the event is being dequeued by. + /// The state name, if the state machine is a state machine and a state exists, else null. /// The event being dequeued. - void OnDequeueEvent(ActorId id, string stateName, Event e); + void OnDequeueEvent(StateMachineId id, string stateName, Event e); /// - /// Invoked when the specified event is received by an actor. + /// Invoked when the specified event is received by an state machine. /// - /// The id of the actor that received the event. - /// The state name, if the actor is a state machine and a state exists, else null. + /// The id of the state machine that received the event. + /// The state name, if the state machine is a state machine and a state exists, else null. /// The the event being received. - /// The actor was waiting for one or more specific events, + /// The state machine was waiting for one or more specific events, /// and was one of them - void OnReceiveEvent(ActorId id, string stateName, Event e, bool wasBlocked); + void OnReceiveEvent(StateMachineId id, string stateName, Event e, bool wasBlocked); /// - /// Invoked when the specified actor waits to receive an event of a specified type. + /// Invoked when the specified state machine waits to receive an event of a specified type. /// - /// The id of the actor that is entering the wait state. - /// The state name, if the actor is a state machine and a state exists, else null. + /// The id of the state machine that is entering the wait state. + /// The state name, if the state machine is a state machine and a state exists, else null. /// The type of the event being waited for. - void OnWaitEvent(ActorId id, string stateName, Type eventType); + void OnWaitEvent(StateMachineId id, string stateName, Type eventType); /// - /// Invoked when the specified actor waits to receive an event of one of the specified types. + /// Invoked when the specified state machine waits to receive an event of one of the specified types. /// - /// The id of the actor that is entering the wait state. - /// The state name, if the actor is a state machine and a state exists, else null. + /// The id of the state machine that is entering the wait state. + /// The state name, if the state machine is a state machine and a state exists, else null. /// The types of the events being waited for, if any. - void OnWaitEvent(ActorId id, string stateName, params Type[] eventTypes); + void OnWaitEvent(StateMachineId id, string stateName, params Type[] eventTypes); /// /// Invoked when the specified state machine enters or exits a state. /// - /// The id of the actor entering or exiting the state. + /// The id of the state machine entering or exiting the state. /// The name of the state being entered or exited. /// If true, this is called for a state entry; otherwise, exit. - void OnStateTransition(ActorId id, string stateName, bool isEntry); + void OnStateTransition(StateMachineId id, string stateName, bool isEntry); /// /// Invoked when the specified state machine performs a goto transition to the specified state. /// - /// The id of the actor. + /// The id of the state machine. /// The name of the current state. /// The target state of the transition. - void OnGotoState(ActorId id, string currentStateName, string newStateName); + void OnGotoState(StateMachineId id, string currentStateName, string newStateName); /// - /// Invoked when the specified actor is idle (there is nothing to dequeue) and the default + /// Invoked when the specified state machine is idle (there is nothing to dequeue) and the default /// event handler is about to be executed. /// - /// The id of the actor that the state will execute in. - /// The state name, if the actor is a state machine and a state exists, else null. - void OnDefaultEventHandler(ActorId id, string stateName); + /// The id of the state machine that the state will execute in. + /// The state name, if the state machine is a state machine and a state exists, else null. + void OnDefaultEventHandler(StateMachineId id, string stateName); /// - /// Invoked when the specified actor has been halted. + /// Invoked when the specified state machine has been halted. /// - /// The id of the actor that has been halted. + /// The id of the state machine that has been halted. /// Approximate size of the inbox. - void OnHalt(ActorId id, int inboxSize); + void OnHalt(StateMachineId id, int inboxSize); /// - /// Invoked when the specified actor handled a raised event. + /// Invoked when the specified state machine handled a raised event. /// - /// The id of the actor handling the event. - /// The state name, if the actor is a state machine and a state exists, else null. + /// The id of the state machine handling the event. + /// The state name, if the state machine is a state machine and a state exists, else null. /// The event being handled. - void OnHandleRaisedEvent(ActorId id, string stateName, Event e); + void OnHandleRaisedEvent(StateMachineId id, string stateName, Event e); /// /// Invoked when the specified event cannot be handled in the current state, its exit /// handler is executed and then the state is popped and any previous "current state" /// is reentered. This handler is called when that pop has been done. /// - /// The id of the actor that the pop executed in. - /// The state name, if the actor is a state machine and a state exists, else null. + /// The id of the state machine that the pop executed in. + /// The state name, if the state machine is a state machine and a state exists, else null. /// The event that cannot be handled. - void OnPopStateUnhandledEvent(ActorId id, string stateName, Event e); + void OnPopStateUnhandledEvent(StateMachineId id, string stateName, Event e); /// - /// Invoked when the specified actor throws an exception. + /// Invoked when the specified state machine throws an exception. /// - /// The id of the actor that threw the exception. - /// The state name, if the actor is a state machine and a state exists, else null. + /// The id of the state machine that threw the exception. + /// The state name, if the state machine is a state machine and a state exists, else null. /// The name of the action being executed. /// The exception. - void OnExceptionThrown(ActorId id, string stateName, string actionName, Exception ex); + void OnExceptionThrown(StateMachineId id, string stateName, string actionName, Exception ex); /// /// Invoked when the specified OnException method is used to handle a thrown exception. /// - /// The id of the actor that threw the exception. - /// The state name, if the actor is a state machine and a state exists, else null. + /// The id of the state machine that threw the exception. + /// The state name, if the state machine is a state machine and a state exists, else null. /// The name of the action being executed. /// The exception. - void OnExceptionHandled(ActorId id, string stateName, string actionName, Exception ex); + void OnExceptionHandled(StateMachineId id, string stateName, string actionName, Exception ex); /// diff --git a/Src/PChecker/CheckerCore/Actors/Logging/JsonWriter.cs b/Src/PChecker/CheckerCore/Runtime/Logging/JsonWriter.cs similarity index 95% rename from Src/PChecker/CheckerCore/Actors/Logging/JsonWriter.cs rename to Src/PChecker/CheckerCore/Runtime/Logging/JsonWriter.cs index 2802f9e715..a546bae0f2 100644 --- a/Src/PChecker/CheckerCore/Actors/Logging/JsonWriter.cs +++ b/Src/PChecker/CheckerCore/Runtime/Logging/JsonWriter.cs @@ -6,7 +6,7 @@ using System.Security.Cryptography; using System.Text; -namespace PChecker.Actors.Logging +namespace PChecker.Runtime.Logging { /// /// Class for handling generating the vector clock for a log entry @@ -15,7 +15,7 @@ internal class VectorClockGenerator { /// /// Nested class for handling FIFO send receive requests. - /// NOTE: In the case of sending to a the same machine with the same event and same payload. + /// NOTE: In the case of sending to the same machine with the same event and same payload. /// private class FifoSendReceiveMapping { @@ -349,23 +349,23 @@ public LogEntry() /// Enum representing the possible attributes in the details dictionary, /// which represents the data associated with a specific log type. All of /// the following are available or expanded parameters associated with an - /// IActorRuntime method. Naming for them is mostly the same except some + /// ControlledRuntime method. Naming for them is mostly the same except some /// are changed for simplicity. - /// I.e., for OnRaiseEvent(ActorId id, string, stateName, Event e), it + /// I.e., for OnRaiseEvent(StateMachineId id, string, stateName, Event e), it /// will have attributes id, state (simplified from stateName, event /// (simplified from eventName within Event e), and payload (in Event e). /// public class LogDetails { /// - /// The text log from PLogFormatter. Removes the log tags. + /// The text log from PCheckerLogTextFormatter. Removes the log tags. /// I.e., no <SomeLog> in the beginning. /// Available for all log types. /// public string? Log { get; set; } /// - /// The actor id. + /// The state machine id. /// public string? Id { get; set; } @@ -437,7 +437,7 @@ public class LogDetails public int? HaltInboxSize { get; set; } /// - /// Boolean representing whether an actor was waiting for one or more events + /// Boolean representing whether an state machine was waiting for one or more events /// Available for log type ReceiveEvent. /// public bool? WasBlocked { get; set; } @@ -449,7 +449,7 @@ public class LogDetails public string? Sender { get; set; } /// - /// Id of target actor. + /// Id of target state machine. /// Available for log type SendEvent. /// public string? Target { get; set; } @@ -461,7 +461,7 @@ public class LogDetails public string? OpGroupId { get; set; } /// - /// Boolean representing whether the target actor was halted. + /// Boolean representing whether the target state machine was halted. /// Available for log type SendEvent. /// public bool? IsTargetHalted { get; set; } @@ -557,8 +557,8 @@ public JsonWriter() /// /// Enum representing the different log types the JSON error trace logs. - /// Referenced from PLogFormatter.cs and ActorRuntimeLogTextFormatter.cs - /// to see what those formatter logs. Check IActorRuntimeLog.cs to see + /// Referenced from PCheckerLogTextFormatter.cs and PCheckerLogTextFormatter.cs + /// to see what those formatter logs. Check IControlledRuntimeLog.cs to see /// each log types' description and when they are invoked. /// public enum LogType @@ -568,11 +568,6 @@ public enum LogType /// AssertionFailure, - /// - /// Invoked when the specified actor has been created. - /// - CreateActor, - /// /// Invoked when the specified state machine has been created. /// @@ -584,13 +579,13 @@ public enum LogType CreateMonitor, /// - /// Invoked when the specified actor is idle (there is nothing to dequeue) and the default + /// Invoked when the specified state machine is idle (there is nothing to dequeue) and the default /// event handler is about to be executed. /// DefaultEventHandler, /// - /// Invoked when the specified event is dequeued by an actor. + /// Invoked when the specified event is dequeued by an state machine. /// DequeueEvent, @@ -600,7 +595,7 @@ public enum LogType ExceptionHandled, /// - /// Invoked when the specified actor throws an exception. + /// Invoked when the specified state machine throws an exception. /// ExceptionThrown, @@ -610,7 +605,7 @@ public enum LogType GotoState, /// - /// Invoked when the specified actor has been halted. + /// Invoked when the specified state machine has been halted. /// Halt, @@ -652,12 +647,12 @@ public enum LogType RaiseEvent, /// - /// Invoked when the specified event is received by an actor. + /// Invoked when the specified event is received by an state machine. /// ReceiveEvent, /// - /// Invoked when the specified event is sent to a target actor. + /// Invoked when the specified event is sent to a target state machine. /// SendEvent, @@ -672,12 +667,12 @@ public enum LogType StrategyDescription, /// - /// Invoked when the specified actor waits to receive an event of a specified type. + /// Invoked when the specified state machine waits to receive an event of a specified type. /// WaitEvent, /// - /// Invoked when the specified actor waits to receive multiple events of a specified type. + /// Invoked when the specified state machine waits to receive multiple events of a specified type. /// WaitMultipleEvents, diff --git a/Src/PChecker/CheckerCore/Actors/Logging/LogWriter.cs b/Src/PChecker/CheckerCore/Runtime/Logging/LogWriter.cs similarity index 72% rename from Src/PChecker/CheckerCore/Actors/Logging/LogWriter.cs rename to Src/PChecker/CheckerCore/Runtime/Logging/LogWriter.cs index aad60d8aab..16a968e33f 100644 --- a/Src/PChecker/CheckerCore/Actors/Logging/LogWriter.cs +++ b/Src/PChecker/CheckerCore/Runtime/Logging/LogWriter.cs @@ -5,21 +5,22 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using PChecker.Actors.Events; using PChecker.IO.Logging; +using PChecker.Runtime.Events; +using PChecker.Runtime.StateMachines; -namespace PChecker.Actors.Logging +namespace PChecker.Runtime.Logging { /// /// Manages the installed and all registered - /// objects. + /// objects. /// - internal sealed class LogWriter + public sealed class LogWriter { /// /// The set of registered log writers. /// - private readonly HashSet Logs; + private readonly HashSet Logs; /// /// Used to log messages. @@ -36,7 +37,7 @@ internal sealed class LogWriter /// internal LogWriter(CheckerConfiguration checkerConfiguration) { - Logs = new HashSet(); + Logs = new HashSet(); if (checkerConfiguration.IsVerbose) { @@ -48,30 +49,13 @@ internal LogWriter(CheckerConfiguration checkerConfiguration) } } - /// - /// Logs that the specified actor has been created. - /// - /// The id of the actor that has been created. - /// The name of the creator, or null. - /// The type of the creator, or null. - public void LogCreateActor(ActorId id, string creatorName, string creatorType) - { - if (Logs.Count > 0) - { - foreach (var log in Logs) - { - log.OnCreateActor(id, creatorName, creatorType); - } - } - } - /// /// Logs that the specified state machine has been created. /// /// The id of the state machine that has been created. /// The name of the creator, or null. /// The type of the creator, or null. - public void LogCreateStateMachine(ActorId id, string creatorName, string creatorType) + public void LogCreateStateMachine(StateMachineId id, string creatorName, string creatorType) { if (Logs.Count > 0) { @@ -83,13 +67,13 @@ public void LogCreateStateMachine(ActorId id, string creatorName, string creator } /// - /// Logs that the specified actor executes an action. + /// Logs that the specified state machine executes an action. /// - /// The id of the actor executing the action. + /// The id of the state machine executing the action. /// The state that declared this action (can be different from currentStateName in the case of PushStates. - /// The state name, if the actor is a state machine and a state exists, else null. + /// The state name, if the state machine is a state machine and a state exists, else null. /// The name of the action being executed. - public void LogExecuteAction(ActorId id, string handlingStateName, string currentStateName, string actionName) + public void LogExecuteAction(StateMachineId id, string handlingStateName, string currentStateName, string actionName) { if (Logs.Count > 0) { @@ -101,34 +85,34 @@ public void LogExecuteAction(ActorId id, string handlingStateName, string curren } /// - /// Logs that the specified event is sent to a target actor. + /// Logs that the specified event is sent to a target state machine. /// - /// The id of the target actor. + /// The id of the target state machine. /// The name of the sender, if any. /// The type of the sender, if any. /// The state name, if the sender is a state machine, else null. /// The event being sent. /// The id used to identify the send operation. - /// Is the target actor halted. - public void LogSendEvent(ActorId targetActorId, string senderName, string senderType, string senderState, - Event e, Guid opGroupId, bool isTargetHalted) + /// Is the target state machine halted. + public void LogSendEvent(StateMachineId targetStateMachineId, string senderName, string senderType, string senderState, + Event e, bool isTargetHalted) { if (Logs.Count > 0) { foreach (var log in Logs) { - log.OnSendEvent(targetActorId, senderName, senderType, senderState, e, opGroupId, isTargetHalted); + log.OnSendEvent(targetStateMachineId, senderName, senderType, senderState, e, isTargetHalted); } } } /// - /// Logs that the specified actor raises an event. + /// Logs that the specified state machine raises an event. /// - /// The id of the actor raising the event. - /// The state name, if the actor is a state machine and a state exists, else null. + /// The id of the state machine raising the event. + /// The state name, if the state machine is a state machine and a state exists, else null. /// The event being raised. - public void LogRaiseEvent(ActorId id, string stateName, Event e) + public void LogRaiseEvent(StateMachineId id, string stateName, Event e) { if (Logs.Count > 0) { @@ -140,11 +124,11 @@ public void LogRaiseEvent(ActorId id, string stateName, Event e) } /// - /// Logs that the specified event is about to be enqueued to an actor. + /// Logs that the specified event is about to be enqueued to an state machine. /// - /// The id of the actor that the event is being enqueued to. + /// The id of the state machine that the event is being enqueued to. /// The event being enqueued. - public void LogEnqueueEvent(ActorId id, Event e) + public void LogEnqueueEvent(StateMachineId id, Event e) { if (Logs.Count > 0) { @@ -156,12 +140,12 @@ public void LogEnqueueEvent(ActorId id, Event e) } /// - /// Logs that the specified event is dequeued by an actor. + /// Logs that the specified event is dequeued by an state machine. /// - /// The id of the actor that the event is being dequeued by. - /// The state name, if the actor is a state machine and a state exists, else null. + /// The id of the state machine that the event is being dequeued by. + /// The state name, if the state machine is a state machine and a state exists, else null. /// The event being dequeued. - public void LogDequeueEvent(ActorId id, string stateName, Event e) + public void LogDequeueEvent(StateMachineId id, string stateName, Event e) { if (Logs.Count > 0) { @@ -173,14 +157,14 @@ public void LogDequeueEvent(ActorId id, string stateName, Event e) } /// - /// Logs that the specified event is received by an actor. + /// Logs that the specified event is received by an state machine. /// - /// The id of the actor that received the event. - /// The state name, if the actor is a state machine and a state exists, else null. + /// The id of the state machine that received the event. + /// The state name, if the state machine is a state machine and a state exists, else null. /// The event being received. /// The state machine was waiting for one or more specific events, /// and was one of them. - public void LogReceiveEvent(ActorId id, string stateName, Event e, bool wasBlocked) + public void LogReceiveEvent(StateMachineId id, string stateName, Event e, bool wasBlocked) { if (Logs.Count > 0) { @@ -192,12 +176,12 @@ public void LogReceiveEvent(ActorId id, string stateName, Event e, bool wasBlock } /// - /// Logs that the specified actor waits to receive an event of a specified type. + /// Logs that the specified state machine waits to receive an event of a specified type. /// - /// The id of the actor that is entering the wait state. - /// The state name, if the actor is a state machine and a state exists, else null. + /// The id of the state machine that is entering the wait state. + /// The state name, if the state machine is a state machine and a state exists, else null. /// The type of the event being waited for. - public void LogWaitEvent(ActorId id, string stateName, Type eventType) + public void LogWaitEvent(StateMachineId id, string stateName, Type eventType) { if (Logs.Count > 0) { @@ -209,12 +193,12 @@ public void LogWaitEvent(ActorId id, string stateName, Type eventType) } /// - /// Logs that the specified actor waits to receive an event of one of the specified types. + /// Logs that the specified state machine waits to receive an event of one of the specified types. /// - /// The id of the actor that is entering the wait state. - /// The state name, if the actor is a state machine and a state exists, else null. + /// The id of the state machine that is entering the wait state. + /// The state name, if the state machine is a state machine and a state exists, else null. /// The types of the events being waited for, if any. - public void LogWaitEvent(ActorId id, string stateName, params Type[] eventTypes) + public void LogWaitEvent(StateMachineId id, string stateName, params Type[] eventTypes) { if (Logs.Count > 0) { @@ -245,10 +229,10 @@ public void LogRandom(object result, string callerName, string callerType) /// /// Logs that the specified state machine enters or exits a state. /// - /// The id of the actor entering or exiting the state. + /// The id of the state machine entering or exiting the state. /// The name of the state being entered or exited. /// If true, this is called for a state entry; otherwise, exit. - public void LogStateTransition(ActorId id, string stateName, bool isEntry) + public void LogStateTransition(StateMachineId id, string stateName, bool isEntry) { if (Logs.Count > 0) { @@ -262,10 +246,10 @@ public void LogStateTransition(ActorId id, string stateName, bool isEntry) /// /// Logs that the specified state machine performs a goto state transition. /// - /// The id of the actor. + /// The id of the state machine. /// The name of the current state. /// The target state of the transition. - public void LogGotoState(ActorId id, string currentStateName, string newStateName) + public void LogGotoState(StateMachineId id, string currentStateName, string newStateName) { if (Logs.Count > 0) { @@ -277,11 +261,11 @@ public void LogGotoState(ActorId id, string currentStateName, string newStateNam } /// - /// Logs that the specified actor has halted. + /// Logs that the specified state machine has halted. /// - /// The id of the actor that has been halted. + /// The id of the state machine that has been halted. /// Approximate size of the inbox. - public void LogHalt(ActorId id, int inboxSize) + public void LogHalt(StateMachineId id, int inboxSize) { if (Logs.Count > 0) { @@ -293,12 +277,12 @@ public void LogHalt(ActorId id, int inboxSize) } /// - /// Logs that the specified actor is idle (there is nothing to dequeue) and the default + /// Logs that the specified state machine is idle (there is nothing to dequeue) and the default /// event handler is about to be executed. /// - /// The id of the actor that the state will execute in. - /// The state name, if the actor is a state machine and a state exists, else null. - public void LogDefaultEventHandler(ActorId id, string stateName) + /// The id of the state machine that the state will execute in. + /// The state name, if the state machine is a state machine and a state exists, else null. + public void LogDefaultEventHandler(StateMachineId id, string stateName) { if (Logs.Count > 0) { @@ -312,10 +296,10 @@ public void LogDefaultEventHandler(ActorId id, string stateName) /// /// Logs that the specified state machine handled a raised event. /// - /// The id of the actor handling the event. + /// The id of the state machine handling the event. /// The name of the current state. /// The event being handled. - public void LogHandleRaisedEvent(ActorId id, string stateName, Event e) + public void LogHandleRaisedEvent(StateMachineId id, string stateName, Event e) { if (Logs.Count > 0) { @@ -331,10 +315,10 @@ public void LogHandleRaisedEvent(ActorId id, string stateName, Event e) /// handler is executed and then the state is popped and any previous "current state" /// is reentered. This handler is called when that pop has been done. /// - /// The id of the actor that the pop executed in. - /// The state name, if the actor is a state machine and a state exists, else null. + /// The id of the state machine that the pop executed in. + /// The state name, if the state machine is a state machine and a state exists, else null. /// The event that cannot be handled. - public void LogPopStateUnhandledEvent(ActorId id, string stateName, Event e) + public void LogPopStateUnhandledEvent(StateMachineId id, string stateName, Event e) { if (Logs.Count > 0) { @@ -346,13 +330,13 @@ public void LogPopStateUnhandledEvent(ActorId id, string stateName, Event e) } /// - /// Logs that the specified actor throws an exception. + /// Logs that the specified state machine throws an exception. /// - /// The id of the actor that threw the exception. - /// The state name, if the actor is a state machine and a state exists, else null. + /// The id of the state machine that threw the exception. + /// The state name, if the state machine is a state machine and a state exists, else null. /// The name of the action being executed. /// The exception. - public void LogExceptionThrown(ActorId id, string stateName, string actionName, Exception ex) + public void LogExceptionThrown(StateMachineId id, string stateName, string actionName, Exception ex) { if (Logs.Count > 0) { @@ -366,11 +350,11 @@ public void LogExceptionThrown(ActorId id, string stateName, string actionName, /// /// Logs that the specified OnException method is used to handle a thrown exception. /// - /// The id of the actor that threw the exception. - /// The state name, if the actor is a state machine and a state exists, else null. + /// The id of the state machine that threw the exception. + /// The state name, if the state machine is a state machine and a state exists, else null. /// The name of the action being executed. /// The exception. - public void LogExceptionHandled(ActorId id, string stateName, string actionName, Exception ex) + public void LogExceptionHandled(StateMachineId id, string stateName, string actionName, Exception ex) { if (Logs.Count > 0) { @@ -532,12 +516,12 @@ internal void LogCompletion() } /// - /// Returns all registered logs of type , + /// Returns all registered logs of type , /// if there are any. /// - public IEnumerable GetLogsOfType() - where TActorRuntimeLog : IActorRuntimeLog => - Logs.OfType(); + public IEnumerable GetLogsOfType() + where TStateMachineRuntimeLog : IControlledRuntimeLog => + Logs.OfType(); /// /// Use this method to override the default for logging messages. @@ -549,7 +533,7 @@ internal TextWriter SetLogger(TextWriter logger) { Logger = TextWriter.Null; - var textLog = GetLogsOfType().FirstOrDefault(); + var textLog = GetLogsOfType().FirstOrDefault(); if (textLog != null) { textLog.Logger = Logger; @@ -573,9 +557,9 @@ internal TextWriter SetLogger(TextWriter logger) /// The jsonLogger instance created from runtime before running tests. internal void SetJsonLogger(JsonWriter jsonLogger) => JsonLogger = jsonLogger; - private ActorRuntimeLogTextFormatter GetOrCreateTextLog() + private PCheckerLogTextFormatter GetOrCreateTextLog() { - var textLog = GetLogsOfType().FirstOrDefault(); + var textLog = GetLogsOfType().FirstOrDefault(); if (textLog == null) { if (Logger == null) @@ -583,7 +567,7 @@ private ActorRuntimeLogTextFormatter GetOrCreateTextLog() Logger = new ConsoleLogger(); } - textLog = new ActorRuntimeLogTextFormatter + textLog = new PCheckerLogTextFormatter { Logger = Logger }; @@ -595,9 +579,9 @@ private ActorRuntimeLogTextFormatter GetOrCreateTextLog() } /// - /// Use this method to register an . + /// Use this method to register an . /// - internal void RegisterLog(IActorRuntimeLog log) + internal void RegisterLog(IControlledRuntimeLog log) { if (log == null) { @@ -605,9 +589,9 @@ internal void RegisterLog(IActorRuntimeLog log) } // Make sure we only have one text logger - if (log is ActorRuntimeLogTextFormatter a) + if (log is PCheckerLogTextFormatter a) { - var textLog = GetLogsOfType().FirstOrDefault(); + var textLog = GetLogsOfType().FirstOrDefault(); if (textLog != null) { Logs.Remove(textLog); @@ -619,9 +603,9 @@ internal void RegisterLog(IActorRuntimeLog log) } } - // If log is or of subclass ActorRuntimeLogJsonFormatter (i.e. when log is PJsonFormatter), + // If log is or of subclass PCheckerLogJsonFormatter (i.e. when log is PCheckerLogJsonFormatter), // update the Writer reference to the JsonLogger instance defined within LogWriter.cs - if (log is ActorRuntimeLogJsonFormatter tempJsonFormatter) + if (log is PCheckerLogJsonFormatter tempJsonFormatter) { tempJsonFormatter.Writer = JsonLogger; } @@ -630,9 +614,9 @@ internal void RegisterLog(IActorRuntimeLog log) } /// - /// Use this method to unregister a previously registered . + /// Use this method to unregister a previously registered . /// - internal void RemoveLog(IActorRuntimeLog log) + internal void RemoveLog(IControlledRuntimeLog log) { if (log != null) { diff --git a/Src/PChecker/CheckerCore/PRuntime/PJsonFormatter.cs b/Src/PChecker/CheckerCore/Runtime/Logging/PCheckerLogJsonFormatter.cs similarity index 76% rename from Src/PChecker/CheckerCore/PRuntime/PJsonFormatter.cs rename to Src/PChecker/CheckerCore/Runtime/Logging/PCheckerLogJsonFormatter.cs index f654ff132b..c37b679a3c 100644 --- a/Src/PChecker/CheckerCore/PRuntime/PJsonFormatter.cs +++ b/Src/PChecker/CheckerCore/Runtime/Logging/PCheckerLogJsonFormatter.cs @@ -1,24 +1,35 @@ -// Copyright (c) Microsoft Corporation. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System; using System.Linq; using System.Threading.Tasks; -using PChecker.Actors; -using PChecker.Actors.Events; -using PChecker.Actors.Logging; -using PChecker.PRuntime.Exceptions; +using PChecker.Runtime.Events; +using PChecker.Runtime.Exceptions; +using PChecker.Runtime.StateMachines; -namespace PChecker.PRuntime +namespace PChecker.Runtime.Logging { /// - /// This class implements IActorRuntimeLog and generates log output in an XML format. + /// This class implements IControlledRuntimeLog and generates log output in an XML format. /// - public class PJsonFormatter : ActorRuntimeLogJsonFormatter + public class PCheckerLogJsonFormatter : IControlledRuntimeLog { + /// + /// Get or set the JsonWriter to write to. + /// + public JsonWriter Writer { get; set; } + + /// + /// Initializes a new instance of the class. + /// + protected PCheckerLogJsonFormatter() + { + Writer = new JsonWriter(); + } /// - /// Removes the '<' and '>' tags for a log text. + /// Removes the "<" and ">" tags for a log text. /// /// The text log /// New string with the tag removed or just the string itself if there is no tag. @@ -38,7 +49,7 @@ private static string RemoveLogTag(string log) } /// - /// Method taken from PLogFormatter.cs file. Takes in a string and only get the + /// Method taken from PCheckerLogTextFormatter.cs file. Takes in a string and only get the /// last element of the string separated by a period. /// I.e. /// Input: PImplementation.TestWithSingleClient(2) @@ -49,9 +60,9 @@ private static string RemoveLogTag(string log) private static string GetShortName(string name) => name?.Split('.').Last(); /// - /// Method taken from PLogFormatter.cs file. Takes in Event e and returns string + /// Method taken from PCheckerLogTextFormatter.cs file. Takes in Event e and returns string /// with details about the event such as event name and its payload. Slightly modified - /// from the method in PLogFormatter.cs in that payload is parsed with the CleanPayloadString + /// from the method in PCheckerLogTextFormatter.cs in that payload is parsed with the CleanPayloadString /// method right above. /// /// Event input. @@ -63,7 +74,7 @@ private static string GetEventNameWithPayload(Event e) return e.GetType().Name; } - var pe = (PEvent)(e); + var pe = (Event)(e); var payload = pe.Payload == null ? "null" : pe.Payload.ToEscapedString(); var msg = pe.Payload == null ? "" : $" with payload ({payload})"; return $"{GetShortName(e.GetType().Name)}{msg}"; @@ -81,15 +92,15 @@ private static object GetEventPayloadInJson(Event e) return null; } - var pe = (PEvent)(e); + var pe = (Event)(e); return pe.Payload?.ToDict(); } - public override void OnCompleted() + public void OnCompleted() { } - public override void OnAssertionFailure(string error) + public void OnAssertionFailure(string error) { error = RemoveLogTag(error); @@ -98,33 +109,10 @@ public override void OnAssertionFailure(string error) Writer.AddLog(error); Writer.AddToLogs(); } - - public override void OnCreateActor(ActorId id, string creatorName, string creatorType) - { - if (id.Name.Contains("GodMachine") || creatorName.Contains("GodMachine")) - { - return; - } - - var source = creatorName ?? $"task '{Task.CurrentId}'"; - var log = $"{id} was created by {source}."; - - Writer.AddLogType(JsonWriter.LogType.CreateActor); - Writer.LogDetails.Id = id.ToString(); - Writer.LogDetails.CreatorName = source; - Writer.LogDetails.CreatorType = creatorType; - Writer.AddLog(log); - Writer.AddToLogs(updateVcMap: true); - } - + /// - public override void OnCreateStateMachine(ActorId id, string creatorName, string creatorType) + public void OnCreateStateMachine(StateMachineId id, string creatorName, string creatorType) { - if (id.Name.Contains("GodMachine") || creatorName.Contains("GodMachine")) - { - return; - } - var source = creatorName ?? $"task '{Task.CurrentId}'"; var log = $"{id} was created by {source}."; @@ -136,7 +124,7 @@ public override void OnCreateStateMachine(ActorId id, string creatorName, string Writer.AddToLogs(updateVcMap: true); } - public override void OnDefaultEventHandler(ActorId id, string stateName) + public void OnDefaultEventHandler(StateMachineId id, string stateName) { stateName = GetShortName(stateName); @@ -151,13 +139,8 @@ public override void OnDefaultEventHandler(ActorId id, string stateName) Writer.AddToLogs(updateVcMap: true); } - public override void OnDequeueEvent(ActorId id, string stateName, Event e) + public void OnDequeueEvent(StateMachineId id, string stateName, Event e) { - if (stateName.Contains("__InitState__") || id.Name.Contains("GodMachine")) - { - return; - } - var eventName = GetEventNameWithPayload(e); var log = stateName is null ? $"'{id}' dequeued event '{eventName}'." @@ -172,11 +155,13 @@ public override void OnDequeueEvent(ActorId id, string stateName, Event e) Writer.AddToLogs(updateVcMap: true); } - public override void OnEnqueueEvent(ActorId id, Event e) + /// + public void OnEnqueueEvent(StateMachineId id, Event e) { } - public override void OnExceptionHandled(ActorId id, string stateName, string actionName, Exception ex) + /// + public void OnExceptionHandled(StateMachineId id, string stateName, string actionName, Exception ex) { if (ex is PNonStandardReturnException) { @@ -196,7 +181,8 @@ public override void OnExceptionHandled(ActorId id, string stateName, string act Writer.AddToLogs(updateVcMap: true); } - public override void OnExceptionThrown(ActorId id, string stateName, string actionName, Exception ex) + /// + public void OnExceptionThrown(StateMachineId id, string stateName, string actionName, Exception ex) { if (ex is PNonStandardReturnException) { @@ -215,18 +201,15 @@ public override void OnExceptionThrown(ActorId id, string stateName, string acti Writer.AddLog(log); Writer.AddToLogs(updateVcMap: true); } - - public override void OnExecuteAction(ActorId id, string handlingStateName, string currentStateName, string actionName) + + /// + public void OnExecuteAction(StateMachineId id, string handlingStateName, string currentStateName, string actionName) { } - public override void OnGotoState(ActorId id, string currentStateName, string newStateName) + /// + public void OnGotoState(StateMachineId id, string currentStateName, string newStateName) { - if (currentStateName.Contains("__InitState__") || id.Name.Contains("GodMachine")) - { - return; - } - currentStateName = GetShortName(currentStateName); newStateName = GetShortName(newStateName); @@ -241,7 +224,8 @@ public override void OnGotoState(ActorId id, string currentStateName, string new Writer.AddToLogs(updateVcMap: true); } - public override void OnHalt(ActorId id, int inboxSize) + /// + public void OnHalt(StateMachineId id, int inboxSize) { var log = $"{id} halted with {inboxSize} events in its inbox."; @@ -251,12 +235,14 @@ public override void OnHalt(ActorId id, int inboxSize) Writer.AddLog(log); Writer.AddToLogs(updateVcMap: true); } - - public override void OnHandleRaisedEvent(ActorId id, string stateName, Event e) + + /// + public void OnHandleRaisedEvent(StateMachineId id, string stateName, Event e) { } - public override void OnPopState(ActorId id, string currentStateName, string restoredStateName) + /// + public void OnPopState(StateMachineId id, string currentStateName, string restoredStateName) { currentStateName = string.IsNullOrEmpty(currentStateName) ? "[not recorded]" : currentStateName; var reenteredStateName = restoredStateName ?? string.Empty; @@ -270,7 +256,8 @@ public override void OnPopState(ActorId id, string currentStateName, string rest Writer.AddToLogs(updateVcMap: true); } - public override void OnPopStateUnhandledEvent(ActorId id, string stateName, Event e) + /// + public void OnPopStateUnhandledEvent(StateMachineId id, string stateName, Event e) { var log = $"{id} popped state {stateName} due to unhandled event '{e.GetType().Name}'."; @@ -282,7 +269,8 @@ public override void OnPopStateUnhandledEvent(ActorId id, string stateName, Even Writer.AddToLogs(updateVcMap: true); } - public override void OnPushState(ActorId id, string currentStateName, string newStateName) + /// + public void OnPushState(StateMachineId id, string currentStateName, string newStateName) { var log = $"{id} pushed from state '{currentStateName}' to state '{newStateName}'."; @@ -294,13 +282,13 @@ public override void OnPushState(ActorId id, string currentStateName, string new Writer.AddToLogs(updateVcMap: true); } - public override void OnRaiseEvent(ActorId id, string stateName, Event e) + /// + public void OnRaiseEvent(StateMachineId id, string stateName, Event e) { stateName = GetShortName(stateName); string eventName = GetEventNameWithPayload(e); - if (stateName.Contains("__InitState__") || id.Name.Contains("GodMachine") || - eventName.Contains("GotoStateEvent")) + if (eventName.Contains("GotoStateEvent")) { return; } @@ -318,7 +306,8 @@ public override void OnRaiseEvent(ActorId id, string stateName, Event e) Writer.AddToLogs(updateVcMap: true); } - public override void OnReceiveEvent(ActorId id, string stateName, Event e, bool wasBlocked) + /// + public void OnReceiveEvent(StateMachineId id, string stateName, Event e, bool wasBlocked) { stateName = GetShortName(stateName); string eventName = GetEventNameWithPayload(e); @@ -337,37 +326,32 @@ public override void OnReceiveEvent(ActorId id, string stateName, Event e, bool Writer.AddToLogs(updateVcMap: true); } - public override void OnSendEvent(ActorId targetActorId, string senderName, string senderType, string senderStateName, - Event e, Guid opGroupId, bool isTargetHalted) + /// + public void OnSendEvent(StateMachineId targetStateMachineId, string senderName, string senderType, string senderStateName, + Event e, bool isTargetHalted) { senderStateName = GetShortName(senderStateName); string eventName = GetEventNameWithPayload(e); - var opGroupIdMsg = opGroupId != Guid.Empty ? $" (operation group '{opGroupId}')" : string.Empty; var isHalted = isTargetHalted ? $" which has halted" : string.Empty; var sender = !string.IsNullOrEmpty(senderName) ? $"'{senderName}' in state '{senderStateName}'" : $"The runtime"; - var log = $"{sender} sent event '{eventName}' to '{targetActorId}'{isHalted}{opGroupIdMsg}."; + var log = $"{sender} sent event '{eventName}' to '{targetStateMachineId}'{isHalted}."; Writer.AddLogType(JsonWriter.LogType.SendEvent); Writer.LogDetails.Sender = !string.IsNullOrEmpty(senderName) ? senderName : "Runtime"; Writer.LogDetails.State = senderStateName; Writer.LogDetails.Event = GetShortName(e.GetType().Name); - Writer.LogDetails.Target = targetActorId.ToString(); - Writer.LogDetails.OpGroupId = opGroupId.ToString(); + Writer.LogDetails.Target = targetStateMachineId.ToString(); Writer.LogDetails.IsTargetHalted = isTargetHalted; Writer.LogDetails.Payload = GetEventPayloadInJson(e); Writer.AddLog(log); Writer.AddToLogs(updateVcMap: true); } - public override void OnStateTransition(ActorId id, string stateName, bool isEntry) + /// + public void OnStateTransition(StateMachineId id, string stateName, bool isEntry) { - if (stateName.Contains("__InitState__") || id.Name.Contains("GodMachine")) - { - return; - } - stateName = GetShortName(stateName); var direction = isEntry ? "enters" : "exits"; var log = $"{id} {direction} state '{stateName}'."; @@ -380,7 +364,8 @@ public override void OnStateTransition(ActorId id, string stateName, bool isEntr Writer.AddToLogs(updateVcMap: true); } - public override void OnWaitEvent(ActorId id, string stateName, Type eventType) + /// + public void OnWaitEvent(StateMachineId id, string stateName, Type eventType) { stateName = GetShortName(stateName); @@ -396,7 +381,8 @@ public override void OnWaitEvent(ActorId id, string stateName, Type eventType) Writer.AddToLogs(updateVcMap: true); } - public override void OnWaitEvent(ActorId id, string stateName, params Type[] eventTypes) + /// + public void OnWaitEvent(StateMachineId id, string stateName, params Type[] eventTypes) { stateName = GetShortName(stateName); string eventNames; @@ -444,7 +430,8 @@ public override void OnWaitEvent(ActorId id, string stateName, params Type[] eve Writer.AddToLogs(updateVcMap: true); } - public override void OnCreateMonitor(string monitorType) + /// + public void OnCreateMonitor(string monitorType) { monitorType = GetShortName(monitorType); var log = $"{monitorType} was created."; @@ -455,11 +442,13 @@ public override void OnCreateMonitor(string monitorType) Writer.AddToLogs(updateVcMap: true); } - public override void OnMonitorExecuteAction(string monitorType, string stateName, string actionName) + /// + public void OnMonitorExecuteAction(string monitorType, string stateName, string actionName) { } - public override void OnMonitorProcessEvent(string monitorType, string stateName, string senderName, + /// + public void OnMonitorProcessEvent(string monitorType, string stateName, string senderName, string senderType, string senderStateName, Event e) { monitorType = GetShortName(monitorType); @@ -475,7 +464,8 @@ public override void OnMonitorProcessEvent(string monitorType, string stateName, Writer.AddToLogs(updateVcMap: true); } - public override void OnMonitorRaiseEvent(string monitorType, string stateName, Event e) + /// + public void OnMonitorRaiseEvent(string monitorType, string stateName, Event e) { stateName = GetShortName(stateName); monitorType = GetShortName(monitorType); @@ -491,7 +481,8 @@ public override void OnMonitorRaiseEvent(string monitorType, string stateName, E Writer.AddToLogs(updateVcMap: true); } - public override void OnMonitorStateTransition(string monitorType, string stateName, bool isEntry, bool? isInHotState) + /// + public void OnMonitorStateTransition(string monitorType, string stateName, bool isEntry, bool? isInHotState) { monitorType = GetShortName(monitorType); @@ -514,15 +505,18 @@ public override void OnMonitorStateTransition(string monitorType, string stateNa Writer.AddToLogs(updateVcMap: true); } - public override void OnMonitorError(string monitorType, string stateName, bool? isInHotState) + /// + public void OnMonitorError(string monitorType, string stateName, bool? isInHotState) { } - - public override void OnRandom(object result, string callerName, string callerType) + + /// + public void OnRandom(object result, string callerName, string callerType) { } - public override void OnStrategyDescription(string strategyName, string description) + /// + public void OnStrategyDescription(string strategyName, string description) { var desc = string.IsNullOrEmpty(description) ? $" Description: {description}" : string.Empty; var log = $"Found bug using '{strategyName}' strategy.{desc}"; diff --git a/Src/PChecker/CheckerCore/Actors/Logging/ActorRuntimeLogTextFormatter.cs b/Src/PChecker/CheckerCore/Runtime/Logging/PCheckerLogTextFormatter.cs similarity index 53% rename from Src/PChecker/CheckerCore/Actors/Logging/ActorRuntimeLogTextFormatter.cs rename to Src/PChecker/CheckerCore/Runtime/Logging/PCheckerLogTextFormatter.cs index 1fd02e2ac3..cee2413c94 100644 --- a/Src/PChecker/CheckerCore/Actors/Logging/ActorRuntimeLogTextFormatter.cs +++ b/Src/PChecker/CheckerCore/Runtime/Logging/PCheckerLogTextFormatter.cs @@ -3,16 +3,19 @@ using System; using System.IO; +using System.Linq; using System.Threading.Tasks; -using PChecker.Actors.Events; using PChecker.IO.Logging; +using PChecker.Runtime.Events; +using PChecker.Runtime.Exceptions; +using PChecker.Runtime.StateMachines; -namespace PChecker.Actors.Logging +namespace PChecker.Runtime.Logging { /// - /// This class implements IActorRuntimeLog and generates output in a a human readable text format. + /// Formatter for the runtime log. /// - public class ActorRuntimeLogTextFormatter : IActorRuntimeLog + public class PCheckerLogTextFormatter : IControlledRuntimeLog { /// /// Get or set the TextWriter to write to. @@ -20,52 +23,62 @@ public class ActorRuntimeLogTextFormatter : IActorRuntimeLog public TextWriter Logger { get; set; } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public ActorRuntimeLogTextFormatter() + public PCheckerLogTextFormatter() { Logger = new ConsoleLogger(); } + private string GetShortName(string name) + { + return name.Split('.').Last(); + } + + private string GetEventNameWithPayload(Event e) + { + if (e.GetType().Name.Contains("GotoStateEvent")) + { + return e.GetType().Name; + } + var pe = (Event)(e); + var payload = pe.Payload == null ? "null" : pe.Payload.ToEscapedString(); + var msg = pe.Payload == null ? "" : $" with payload ({payload})"; + return $"{GetShortName(e.GetType().Name)}{msg}"; + } + /// - public virtual void OnAssertionFailure(string error) + public void OnAssertionFailure(string error) { Logger.WriteLine(error); } /// - public virtual void OnCreateActor(ActorId id, string creatorName, string creatorType) + public void OnCreateStateMachine(StateMachineId id, string creatorName, string creatorType) { - if (id.Name.Contains("GodMachine") || creatorName.Contains("GodMachine")) - { - return; - } var source = creatorName ?? $"task '{Task.CurrentId}'"; var text = $" {id} was created by {source}."; Logger.WriteLine(text); } - + /// - public void OnCreateStateMachine(ActorId id, string creatorName, string creatorType) + public void OnStateTransition(StateMachineId id, string stateName, bool isEntry) { - if (id.Name.Contains("GodMachine") || creatorName.Contains("GodMachine")) - { - return; - } - var source = creatorName ?? $"task '{Task.CurrentId}'"; - var text = $" {id} was created by {source}."; + var direction = isEntry ? "enters" : "exits"; + var text = $" {id} {direction} state '{stateName}'."; Logger.WriteLine(text); } /// - public virtual void OnCreateMonitor(string monitorType) + public void OnPopStateUnhandledEvent(StateMachineId id, string stateName, Event e) { - var text = $" {monitorType} was created."; + var eventName = e.GetType().Name; + var text = $" {id} popped state {stateName} due to unhandled event '{eventName}'."; Logger.WriteLine(text); } /// - public virtual void OnDefaultEventHandler(ActorId id, string stateName) + public void OnDefaultEventHandler(StateMachineId id, string stateName) { string text; if (stateName is null) @@ -81,296 +94,270 @@ public virtual void OnDefaultEventHandler(ActorId id, string stateName) } /// - public virtual void OnDequeueEvent(ActorId id, string stateName, Event e) + public void OnWaitEvent(StateMachineId id, string stateName, params Type[] eventTypes) { - var eventName = e.GetType().FullName; string text; - if (stateName is null) + string eventNames; + if (eventTypes.Length == 0) { - text = $" {id} dequeued event '{eventName}'."; + eventNames = "''"; } - else + else if (eventTypes.Length == 1) { - text = $" {id} dequeued event '{eventName}' in state '{stateName}'."; + eventNames = "'" + eventTypes[0].Name + "'"; } + else if (eventTypes.Length == 2) + { + eventNames = "'" + eventTypes[0].Name + "' or '" + eventTypes[1].Name + "'"; + } + else if (eventTypes.Length == 3) + { + eventNames = "'" + eventTypes[0].Name + "', '" + eventTypes[1].Name + "' or '" + eventTypes[2].Name + "'"; + } + else + { + var eventNameArray = new string[eventTypes.Length - 1]; + for (var i = 0; i < eventTypes.Length - 2; i++) + { + eventNameArray[i] = eventTypes[i].Name; + } - Logger.WriteLine(text); - } - - /// - public virtual void OnEnqueueEvent(ActorId id, Event e) - { - var eventName = e.GetType().FullName; - var text = $" {id} enqueued event '{eventName}'."; - Logger.WriteLine(text); - } + eventNames = "'" + string.Join("', '", eventNameArray) + "' or '" + eventTypes[eventTypes.Length - 1].Name + "'"; + } - /// - public virtual void OnExceptionHandled(ActorId id, string stateName, string actionName, Exception ex) - { - string text; if (stateName is null) { - text = $" {id} running action '{actionName}' chose to handle exception '{ex.GetType().Name}'."; + text = $" {id} is waiting to dequeue an event of type {eventNames}."; } else { - text = $" {id} running action '{actionName}' in state '{stateName}' chose to handle exception '{ex.GetType().Name}'."; + text = $" {id} is waiting to dequeue an event of type {eventNames} in state '{stateName}'."; } Logger.WriteLine(text); } /// - public virtual void OnExceptionThrown(ActorId id, string stateName, string actionName, Exception ex) + public void OnWaitEvent(StateMachineId id, string stateName, Type eventType) { string text; if (stateName is null) { - text = $" {id} running action '{actionName}' threw exception '{ex.GetType().Name}'."; + text = $" {id} is waiting to dequeue an event of type '{eventType.FullName}'."; } else { - text = $" {id} running action '{actionName}' in state '{stateName}' threw exception '{ex.GetType().Name}'."; + text = $" {id} is waiting to dequeue an event of type '{eventType.FullName}' in state '{stateName}'."; } - + Logger.WriteLine(text); } /// - public virtual void OnExecuteAction(ActorId id, string handlingStateName, string currentStateName, string actionName) + public void OnMonitorStateTransition(string monitorType, string stateName, bool isEntry, bool? isInHotState) { - string text; - if (currentStateName is null) - { - text = $" {id} invoked action '{actionName}'."; - } - else if (handlingStateName != currentStateName) - { - text = $" {id} invoked action '{actionName}' in state '{currentStateName}' where action was declared by state '{handlingStateName}'."; - } - else + if (stateName.Contains("__InitState__")) { - text = $" {id} invoked action '{actionName}' in state '{currentStateName}'."; + return; } + var liveness = isInHotState.HasValue ? (isInHotState.Value ? "hot " : "cold ") : string.Empty; + var direction = isEntry ? "enters" : "exits"; + var text = $" {monitorType} {direction} {liveness}state '{stateName}'."; Logger.WriteLine(text); } - + /// - public virtual void OnGotoState(ActorId id, string currentStateName, string newStateName) + public void OnMonitorProcessEvent(string monitorType, string stateName, string senderName, string senderType, + string senderStateName, Event e) { - var text = $" {id} is transitioning from state '{currentStateName}' to state '{newStateName}'."; + var text = $" {GetShortName(monitorType)} is processing event '{GetEventNameWithPayload(e)}' in state '{stateName}'."; Logger.WriteLine(text); } /// - public virtual void OnHalt(ActorId id, int inboxSize) + public void OnDequeueEvent(StateMachineId id, string stateName, Event e) { - var text = $" {id} halted with {inboxSize} events in its inbox."; + stateName = GetShortName(stateName); + var eventName = GetEventNameWithPayload(e); + string text = null; + if (stateName is null) + { + text = $" '{id}' dequeued event '{eventName}'."; + } + else + { + text = $" '{id}' dequeued event '{eventName}' in state '{stateName}'."; + } + Logger.WriteLine(text); } /// - public virtual void OnHandleRaisedEvent(ActorId id, string stateName, Event e) + public void OnRaiseEvent(StateMachineId id, string stateName, Event e) { - } + stateName = GetShortName(stateName); + var eventName = GetEventNameWithPayload(e); + if (eventName.Contains("GotoStateEvent")) + { + return; + } + + string text = null; + if (stateName is null) + { + text = $" '{id}' raised event '{eventName}'."; + } + else + { + text = $" '{id}' raised event '{eventName}' in state '{stateName}'."; + } - /// - public virtual void OnMonitorExecuteAction(string monitorType, string stateName, string actionName) - { - var text = $" {monitorType} executed action '{actionName}' in state '{stateName}'."; Logger.WriteLine(text); } /// - public virtual void OnMonitorProcessEvent(string monitorType, string stateName, string senderName, - string senderType, string senderStateName, Event e) - { - var text = $" {monitorType} is processing event '{e.GetType().Name}' in state '{stateName}'."; - Logger.WriteLine(text); - } + public void OnEnqueueEvent(StateMachineId id, Event e) { } /// - public virtual void OnMonitorRaiseEvent(string monitorType, string stateName, Event e) + public void OnReceiveEvent(StateMachineId id, string stateName, Event e, bool wasBlocked) { - var eventName = e.GetType().FullName; - var text = $" {monitorType} raised event '{eventName}' in state '{stateName}'."; + stateName = GetShortName(stateName); + var eventName = GetEventNameWithPayload(e); + string text = null; + var unblocked = wasBlocked ? " and unblocked" : string.Empty; + if (stateName is null) + { + text = $" '{id}' dequeued event '{eventName}'{unblocked}."; + } + else + { + text = $" '{id}' dequeued event '{eventName}'{unblocked} in state '{stateName}'."; + } + Logger.WriteLine(text); } /// - public virtual void OnMonitorStateTransition(string monitorType, string stateName, bool isEntry, bool? isInHotState) + public void OnMonitorRaiseEvent(string monitorType, string stateName, Event e) { - var liveness = isInHotState.HasValue ? (isInHotState.Value ? "hot " : "cold ") : string.Empty; - var direction = isEntry ? "enters" : "exits"; - var text = $" {monitorType} {direction} {liveness}state '{stateName}'."; + stateName = GetShortName(stateName); + var eventName = GetEventNameWithPayload(e); + var text = $" Monitor '{GetShortName(monitorType)}' raised event '{eventName}' in state '{stateName}'."; Logger.WriteLine(text); } /// - public virtual void OnMonitorError(string monitorType, string stateName, bool? isInHotState) + public void OnSendEvent(StateMachineId targetStateMachineId, string senderName, string senderType, string senderStateName, Event e, bool isTargetHalted) { + senderStateName = GetShortName(senderStateName); + var eventName = GetEventNameWithPayload(e); + var isHalted = isTargetHalted ? $" which has halted" : string.Empty; + var sender = !string.IsNullOrEmpty(senderName) ? $"'{senderName}' in state '{senderStateName}'" : $"The runtime"; + var text = $" {sender} sent event '{eventName}' to '{targetStateMachineId}'{isHalted}."; + Logger.WriteLine(text); } /// - public virtual void OnPopState(ActorId id, string currentStateName, string restoredStateName) + public void OnGotoState(StateMachineId id, string currStateName, string newStateName) { - currentStateName = string.IsNullOrEmpty(currentStateName) ? "[not recorded]" : currentStateName; - var reenteredStateName = restoredStateName ?? string.Empty; - var text = $" {id} popped state '{currentStateName}' and reentered state '{reenteredStateName}'."; + var text = $" {id} is transitioning from state '{currStateName}' to state '{newStateName}'."; Logger.WriteLine(text); } /// - public virtual void OnPopStateUnhandledEvent(ActorId id, string stateName, Event e) + public void OnExecuteAction(StateMachineId id, string handlingStateName, string currentStateName, string actionName) { - var eventName = e.GetType().FullName; - var text = $" {id} popped state {stateName} due to unhandled event '{eventName}'."; - Logger.WriteLine(text); } /// - public virtual void OnPushState(ActorId id, string currentStateName, string newStateName) + public void OnMonitorExecuteAction(string monitorType, string stateName, string actionName) { - var text = $" {id} pushed from state '{currentStateName}' to state '{newStateName}'."; - Logger.WriteLine(text); } /// - public virtual void OnRaiseEvent(ActorId id, string stateName, Event e) + public void OnExceptionHandled(StateMachineId id, string stateName, string actionName, Exception ex) { - var eventName = e.GetType().FullName; + if (ex is PNonStandardReturnException) + { + return; + } string text; if (stateName is null) { - text = $" {id} raised event '{eventName}'."; + text = $" {id} running action '{actionName}' chose to handle exception '{ex.GetType().Name}'."; } else { - text = $" {id} raised event '{eventName}' in state '{stateName}'."; + text = $" {id} running action '{actionName}' in state '{stateName}' chose to handle exception '{ex.GetType().Name}'."; } Logger.WriteLine(text); } /// - public virtual void OnReceiveEvent(ActorId id, string stateName, Event e, bool wasBlocked) + public void OnExceptionThrown(StateMachineId id, string stateName, string actionName, Exception ex) { - var eventName = e.GetType().FullName; + if (ex is PNonStandardReturnException) + { + return; + } string text; - var unblocked = wasBlocked ? " and unblocked" : string.Empty; if (stateName is null) { - text = $" {id} dequeued event '{eventName}'{unblocked}."; + text = $" {id} running action '{actionName}' threw exception '{ex.GetType().Name}'."; } else { - text = $" {id} dequeued event '{eventName}'{unblocked} in state '{stateName}'."; + text = $" {id} running action '{actionName}' in state '{stateName}' threw exception '{ex.GetType().Name}'."; } Logger.WriteLine(text); } /// - public virtual void OnSendEvent(ActorId targetActorId, string senderName, string senderType, string senderStateName, - Event e, Guid opGroupId, bool isTargetHalted) + public void OnCreateMonitor(string monitorType) { - var opGroupIdMsg = opGroupId != Guid.Empty ? $" (operation group '{opGroupId}')" : string.Empty; - var isHalted = isTargetHalted ? $" which has halted" : string.Empty; - var sender = senderName != null ? $"{senderName} in state '{senderStateName}'" : $"task '{Task.CurrentId}'"; - var eventName = e.GetType().FullName; - var text = $" {sender} sent event '{eventName}' to {targetActorId}{isHalted}{opGroupIdMsg}."; + var text = $" {monitorType} was created."; Logger.WriteLine(text); } /// - public virtual void OnStateTransition(ActorId id, string stateName, bool isEntry) + public void OnHandleRaisedEvent(StateMachineId id, string stateName, Event e) { - var direction = isEntry ? "enters" : "exits"; - var text = $" {id} {direction} state '{stateName}'."; - Logger.WriteLine(text); } /// - public virtual void OnStrategyDescription(string strategyName, string description) + public void OnRandom(object result, string callerName, string callerType) { - var desc = string.IsNullOrEmpty(description) ? $" Description: {description}" : string.Empty; - var text = $" Found bug using '{strategyName}' strategy.{desc}"; + var source = callerName ?? $"Task '{Task.CurrentId}'"; + var text = $" {source} nondeterministically chose '{result}'."; Logger.WriteLine(text); } - + /// - public virtual void OnWaitEvent(ActorId id, string stateName, Type eventType) + public void OnHalt(StateMachineId id, int inboxSize) { - string text; - if (stateName is null) - { - text = $" {id} is waiting to dequeue an event of type '{eventType.FullName}'."; - } - else - { - text = $" {id} is waiting to dequeue an event of type '{eventType.FullName}' in state '{stateName}'."; - } - + var text = $" {id} halted with {inboxSize} events in its inbox."; Logger.WriteLine(text); } - + /// - public virtual void OnWaitEvent(ActorId id, string stateName, params Type[] eventTypes) + public void OnMonitorError(string monitorType, string stateName, bool? isInHotState) { - string text; - string eventNames; - if (eventTypes.Length == 0) - { - eventNames = "''"; - } - else if (eventTypes.Length == 1) - { - eventNames = "'" + eventTypes[0].Name + "'"; - } - else if (eventTypes.Length == 2) - { - eventNames = "'" + eventTypes[0].Name + "' or '" + eventTypes[1].Name + "'"; - } - else if (eventTypes.Length == 3) - { - eventNames = "'" + eventTypes[0].Name + "', '" + eventTypes[1].Name + "' or '" + eventTypes[2].Name + "'"; - } - else - { - var eventNameArray = new string[eventTypes.Length - 1]; - for (var i = 0; i < eventTypes.Length - 2; i++) - { - eventNameArray[i] = eventTypes[i].Name; - } - - eventNames = "'" + string.Join("', '", eventNameArray) + "' or '" + eventTypes[eventTypes.Length - 1].Name + "'"; - } - - if (stateName is null) - { - text = $" {id} is waiting to dequeue an event of type {eventNames}."; - } - else - { - text = $" {id} is waiting to dequeue an event of type {eventNames} in state '{stateName}'."; - } - - Logger.WriteLine(text); } /// - public virtual void OnRandom(object result, string callerName, string callerType) + public void OnCompleted() { - var source = callerName ?? $"Task '{Task.CurrentId}'"; - var text = $" {source} nondeterministically chose '{result}'."; - Logger.WriteLine(text); } - + /// - public virtual void OnCompleted() + public void OnStrategyDescription(string strategyName, string description) { + var desc = string.IsNullOrEmpty(description) ? $" Description: {description}" : string.Empty; + var text = $" Found bug using '{strategyName}' strategy.{desc}"; + Logger.WriteLine(text); } } } \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Actors/Logging/ActorRuntimeLogXmlFormatter.cs b/Src/PChecker/CheckerCore/Runtime/Logging/PCheckerLogXmlFormatter.cs similarity index 82% rename from Src/PChecker/CheckerCore/Actors/Logging/ActorRuntimeLogXmlFormatter.cs rename to Src/PChecker/CheckerCore/Runtime/Logging/PCheckerLogXmlFormatter.cs index ebc7fb18d1..c8cc3dad2f 100644 --- a/Src/PChecker/CheckerCore/Actors/Logging/ActorRuntimeLogXmlFormatter.cs +++ b/Src/PChecker/CheckerCore/Runtime/Logging/PCheckerLogXmlFormatter.cs @@ -5,19 +5,20 @@ using System.Text; using System.Threading.Tasks; using System.Xml; -using PChecker.Actors.Events; +using PChecker.Runtime.Events; +using PChecker.Runtime.StateMachines; -namespace PChecker.Actors.Logging +namespace PChecker.Runtime.Logging { /// - /// This class implements IActorRuntimeLog and generates log output in an XML format. + /// This class implements IControlledRuntimeLog and generates log output in an XML format. /// - internal class ActorRuntimeLogXmlFormatter : IActorRuntimeLog + internal class PCheckerLogXmlFormatter : IControlledRuntimeLog { private readonly XmlWriter Writer; private bool Closed; - public ActorRuntimeLogXmlFormatter(XmlWriter writer) + public PCheckerLogXmlFormatter(XmlWriter writer) { Writer = writer; Writer.WriteStartElement("Log"); @@ -44,33 +45,9 @@ public void OnAssertionFailure(string error) Writer.WriteElementString("AssertionFailure", error); } - - public void OnCreateActor(ActorId id, string creatorName, string creatorType) - { - if (Closed) - { - return; - } - - Writer.WriteStartElement("CreateActor"); - Writer.WriteAttributeString("id", id.ToString()); - - if (creatorName != null && creatorType != null) - { - Writer.WriteAttributeString("creatorName", creatorName); - Writer.WriteAttributeString("creatorType", creatorType); - } - else - { - Writer.WriteAttributeString("creatorName", Task.CurrentId.ToString()); - Writer.WriteAttributeString("creatorType", "task"); - } - - Writer.WriteEndElement(); - } - + /// - public void OnCreateStateMachine(ActorId id, string creatorName, string creatorType) + public void OnCreateStateMachine(StateMachineId id, string creatorName, string creatorType) { if (Closed) { @@ -94,7 +71,7 @@ public void OnCreateStateMachine(ActorId id, string creatorName, string creatorT Writer.WriteEndElement(); } - public void OnDefaultEventHandler(ActorId id, string stateName) + public void OnDefaultEventHandler(StateMachineId id, string stateName) { if (Closed) { @@ -111,7 +88,7 @@ public void OnDefaultEventHandler(ActorId id, string stateName) Writer.WriteEndElement(); } - public void OnDequeueEvent(ActorId id, string stateName, Event e) + public void OnDequeueEvent(StateMachineId id, string stateName, Event e) { if (Closed) { @@ -129,7 +106,7 @@ public void OnDequeueEvent(ActorId id, string stateName, Event e) Writer.WriteEndElement(); } - public void OnEnqueueEvent(ActorId id, Event e) + public void OnEnqueueEvent(StateMachineId id, Event e) { if (Closed) { @@ -142,7 +119,7 @@ public void OnEnqueueEvent(ActorId id, Event e) Writer.WriteEndElement(); } - public void OnExceptionHandled(ActorId id, string stateName, string actionName, Exception ex) + public void OnExceptionHandled(StateMachineId id, string stateName, string actionName, Exception ex) { if (Closed) { @@ -162,7 +139,7 @@ public void OnExceptionHandled(ActorId id, string stateName, string actionName, Writer.WriteEndElement(); } - public void OnExceptionThrown(ActorId id, string stateName, string actionName, Exception ex) + public void OnExceptionThrown(StateMachineId id, string stateName, string actionName, Exception ex) { if (Closed) { @@ -178,7 +155,7 @@ public void OnExceptionThrown(ActorId id, string stateName, string actionName, E Writer.WriteEndElement(); } - public void OnExecuteAction(ActorId id, string handlingStateName, string currentStateName, string actionName) + public void OnExecuteAction(StateMachineId id, string handlingStateName, string currentStateName, string actionName) { if (Closed) { @@ -200,7 +177,7 @@ public void OnExecuteAction(ActorId id, string handlingStateName, string current Writer.WriteEndElement(); } - public void OnGotoState(ActorId id, string currentStateName, string newStateName) + public void OnGotoState(StateMachineId id, string currentStateName, string newStateName) { if (Closed) { @@ -214,7 +191,7 @@ public void OnGotoState(ActorId id, string currentStateName, string newStateName Writer.WriteEndElement(); } - public void OnHalt(ActorId id, int inboxSize) + public void OnHalt(StateMachineId id, int inboxSize) { if (Closed) { @@ -227,7 +204,7 @@ public void OnHalt(ActorId id, int inboxSize) Writer.WriteEndElement(); } - public void OnHandleRaisedEvent(ActorId id, string stateName, Event e) + public void OnHandleRaisedEvent(StateMachineId id, string stateName, Event e) { if (Closed) { @@ -235,7 +212,7 @@ public void OnHandleRaisedEvent(ActorId id, string stateName, Event e) } } - public void OnPopState(ActorId id, string currentStateName, string restoredStateName) + public void OnPopState(StateMachineId id, string currentStateName, string restoredStateName) { if (Closed) { @@ -249,7 +226,7 @@ public void OnPopState(ActorId id, string currentStateName, string restoredState Writer.WriteEndElement(); } - public void OnPopStateUnhandledEvent(ActorId id, string stateName, Event e) + public void OnPopStateUnhandledEvent(StateMachineId id, string stateName, Event e) { if (Closed) { @@ -263,7 +240,7 @@ public void OnPopStateUnhandledEvent(ActorId id, string stateName, Event e) Writer.WriteEndElement(); } - public void OnPushState(ActorId id, string currentStateName, string newStateName) + public void OnPushState(StateMachineId id, string currentStateName, string newStateName) { if (Closed) { @@ -277,7 +254,7 @@ public void OnPushState(ActorId id, string currentStateName, string newStateName Writer.WriteEndElement(); } - public void OnRaiseEvent(ActorId id, string stateName, Event e) + public void OnRaiseEvent(StateMachineId id, string stateName, Event e) { if (Closed) { @@ -295,7 +272,7 @@ public void OnRaiseEvent(ActorId id, string stateName, Event e) Writer.WriteEndElement(); } - public void OnReceiveEvent(ActorId id, string stateName, Event e, bool wasBlocked) + public void OnReceiveEvent(StateMachineId id, string stateName, Event e, bool wasBlocked) { if (Closed) { @@ -315,8 +292,8 @@ public void OnReceiveEvent(ActorId id, string stateName, Event e, bool wasBlocke Writer.WriteEndElement(); } - public void OnSendEvent(ActorId targetActorId, string senderName, string senderType, string senderStateName, - Event e, Guid opGroupId, bool isTargetHalted) + public void OnSendEvent(StateMachineId targetStateMachineId, string senderName, string senderType, string senderStateName, + Event e, bool isTargetHalted) { if (Closed) { @@ -324,7 +301,7 @@ public void OnSendEvent(ActorId targetActorId, string senderName, string senderT } Writer.WriteStartElement("Send"); - Writer.WriteAttributeString("target", targetActorId.ToString()); + Writer.WriteAttributeString("target", targetStateMachineId.ToString()); if (senderName != null && senderType != null) { @@ -336,16 +313,12 @@ public void OnSendEvent(ActorId targetActorId, string senderName, string senderT Writer.WriteAttributeString("senderState", senderStateName); Writer.WriteAttributeString("event", e.GetType().FullName); - if (opGroupId != Guid.Empty) - { - Writer.WriteAttributeString("event", opGroupId.ToString()); - } Writer.WriteAttributeString("isTargetHalted", isTargetHalted.ToString()); Writer.WriteEndElement(); } - public void OnStateTransition(ActorId id, string stateName, bool isEntry) + public void OnStateTransition(StateMachineId id, string stateName, bool isEntry) { if (Closed) { @@ -359,7 +332,7 @@ public void OnStateTransition(ActorId id, string stateName, bool isEntry) Writer.WriteEndElement(); } - public void OnWaitEvent(ActorId id, string stateName, Type eventType) + public void OnWaitEvent(StateMachineId id, string stateName, Type eventType) { if (Closed) { @@ -377,7 +350,7 @@ public void OnWaitEvent(ActorId id, string stateName, Type eventType) Writer.WriteEndElement(); } - public void OnWaitEvent(ActorId id, string stateName, params Type[] eventTypes) + public void OnWaitEvent(StateMachineId id, string stateName, params Type[] eventTypes) { if (Closed) { diff --git a/Src/PChecker/CheckerCore/PRuntime/PInterfaces.cs b/Src/PChecker/CheckerCore/Runtime/PInterfaces.cs similarity index 91% rename from Src/PChecker/CheckerCore/PRuntime/PInterfaces.cs rename to Src/PChecker/CheckerCore/Runtime/PInterfaces.cs index de3c2d878c..67ff44f964 100644 --- a/Src/PChecker/CheckerCore/PRuntime/PInterfaces.cs +++ b/Src/PChecker/CheckerCore/Runtime/PInterfaces.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using System.Linq; -using PChecker.PRuntime.Exceptions; -using PChecker.PRuntime.Values; +using PChecker.Runtime.Exceptions; +using PChecker.Runtime.Values; -namespace PChecker.PRuntime +namespace PChecker.Runtime { public class PInterfaces { diff --git a/Src/PChecker/CheckerCore/PRuntime/PModule.cs b/Src/PChecker/CheckerCore/Runtime/PModule.cs similarity index 83% rename from Src/PChecker/CheckerCore/PRuntime/PModule.cs rename to Src/PChecker/CheckerCore/Runtime/PModule.cs index 16cc35ceeb..623e96c661 100644 --- a/Src/PChecker/CheckerCore/PRuntime/PModule.cs +++ b/Src/PChecker/CheckerCore/Runtime/PModule.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; -using PChecker.Actors; +using PChecker.SystematicTesting; -namespace PChecker.PRuntime +namespace PChecker.Runtime { public class PModule { @@ -13,6 +13,6 @@ public class PModule public static IDictionary> linkMap = new Dictionary>(); - public static IActorRuntime runtime; + public static ControlledRuntime runtime; } } \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/PRuntime/PrtTypes.cs b/Src/PChecker/CheckerCore/Runtime/PTypes.cs similarity index 72% rename from Src/PChecker/CheckerCore/PRuntime/PrtTypes.cs rename to Src/PChecker/CheckerCore/Runtime/PTypes.cs index 681640a4fd..e8e103d17b 100644 --- a/Src/PChecker/CheckerCore/PRuntime/PrtTypes.cs +++ b/Src/PChecker/CheckerCore/Runtime/PTypes.cs @@ -3,9 +3,9 @@ using System.Diagnostics; using System.Linq; -namespace PChecker.PRuntime +namespace PChecker.Runtime { - public abstract class PrtType + public abstract class PType { public override string ToString() { @@ -13,7 +13,7 @@ public override string ToString() } } - public class PrtNullType : PrtType + public class PNullType : PType { public override string ToString() { @@ -21,7 +21,7 @@ public override string ToString() } } - public class PrtAnyType : PrtType + public class PAnyType : PType { public override string ToString() { @@ -29,7 +29,7 @@ public override string ToString() } } - public class PrtMachineType : PrtType + public class PMachineType : PType { public override string ToString() { @@ -37,7 +37,7 @@ public override string ToString() } } - public class PrtIntType : PrtType + public class PIntType : PType { public override string ToString() { @@ -45,7 +45,7 @@ public override string ToString() } } - public class PrtFloatType : PrtType + public class PFloatType : PType { public override string ToString() { @@ -53,12 +53,12 @@ public override string ToString() } } - public class PrtEnumType : PrtType + public class PEnumType : PType { public Dictionary enumConstants; public string name; - public PrtEnumType(string typeName, params object[] args) + public PEnumType(string typeName, params object[] args) { name = typeName; enumConstants = new Dictionary(); @@ -81,12 +81,12 @@ public override string ToString() } } - public class PrtPermissionType : PrtType + public class PPermissionType : PType { public string name; public List permissions; - public PrtPermissionType(string name, IEnumerable perm) + public PPermissionType(string name, IEnumerable perm) { this.name = name; permissions = perm.ToList(); @@ -98,7 +98,7 @@ public override string ToString() } } - public class PrtBoolType : PrtType + public class PBoolType : PType { public override string ToString() { @@ -106,7 +106,7 @@ public override string ToString() } } - public class PrtStringType : PrtType + public class PStringType : PType { public override string ToString() { @@ -114,7 +114,7 @@ public override string ToString() } } - public class PrtEventType : PrtType + public class PEventType : PType { public override string ToString() { @@ -122,12 +122,12 @@ public override string ToString() } } - public class PrtMapType : PrtType + public class PMapType : PType { - public PrtType keyType; - public PrtType valType; + public PType keyType; + public PType valType; - public PrtMapType(PrtType k, PrtType v) + public PMapType(PType k, PType v) { keyType = k; valType = v; @@ -139,11 +139,11 @@ public override string ToString() } } - public class PrtSeqType : PrtType + public class PSeqType : PType { - public PrtType elemType; + public PType elemType; - public PrtSeqType(PrtType s) + public PSeqType(PType s) { elemType = s; } @@ -154,11 +154,11 @@ public override string ToString() } } - public class PrtSetType : PrtType + public class PSetType : PType { - public PrtType elemType; + public PType elemType; - public PrtSetType(PrtType s) + public PSetType(PType s) { elemType = s; } @@ -169,22 +169,22 @@ public override string ToString() } } - public class PrtTupleType : PrtType + public class PTupleType : PType { - public List fieldTypes; + public List fieldTypes; - public PrtTupleType() + public PTupleType() { /* This constructor is added only to prevent the other constructor from being called - when an instance of PrtNamedTupleType is created. + when an instance of PNamedTupleType is created. */ } - public PrtTupleType(params PrtType[] fields) + public PTupleType(params PType[] fields) { Debug.Assert(fields.Any()); - fieldTypes = new List(); + fieldTypes = new List(); foreach (var f in fields) { fieldTypes.Add(f); @@ -204,22 +204,22 @@ public override string ToString() } } - public class PrtNamedTupleType : PrtTupleType + public class PNamedTupleType : PTupleType { public List fieldNames; - public PrtNamedTupleType(params object[] args) + public PNamedTupleType(params object[] args) { Debug.Assert(args.Length > 0); fieldNames = new List(); - fieldTypes = new List(); + fieldTypes = new List(); var index = 0; while (index < args.Length) { fieldNames.Add((string)args[index]); index++; - fieldTypes.Add((PrtType)args[index]); + fieldTypes.Add((PType)args[index]); index++; } } diff --git a/Src/PChecker/CheckerCore/Runtime/RuntimeFactory.cs b/Src/PChecker/CheckerCore/Runtime/RuntimeFactory.cs deleted file mode 100644 index 55091af174..0000000000 --- a/Src/PChecker/CheckerCore/Runtime/RuntimeFactory.cs +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using PChecker.Actors; -using PChecker.Random; - -namespace PChecker.Runtime -{ - /// - /// Provides methods for creating a runtime. - /// - public static class RuntimeFactory - { - /// - /// The installed runtime instance. - /// - internal static CoyoteRuntime InstalledRuntime { get; private set; } = CreateWithConfiguration(default); - - /// - /// Protects access to the installed runtime. - /// - private static readonly object SyncObject = new object(); - - /// - /// Creates a new Coyote runtime. - /// - /// The created task runtime. - /// - /// Only one task runtime can be created per process. If you create a new task - /// runtime it replaces the previously installed one. - /// - public static ICoyoteRuntime Create() => CreateAndInstall(default); - - /// - /// Creates a new Coyote runtime with the specified . - /// - /// The runtime checkerConfiguration to use. - /// The created task runtime. - /// - /// Only one task runtime can be created per process. If you create a new task - /// runtime it replaces the previously installed one. - /// - public static ICoyoteRuntime Create(CheckerConfiguration checkerConfiguration) => CreateAndInstall(checkerConfiguration); - - /// - /// Creates a new Coyote runtime with the specified and sets - /// it as the installed runtime, or returns the installed runtime if it already exists. - /// - private static CoyoteRuntime CreateAndInstall(CheckerConfiguration checkerConfiguration) - { - lock (SyncObject) - { - // Assign the newly created runtime as the installed runtime. - return InstalledRuntime = CreateWithConfiguration(checkerConfiguration); - } - } - - /// - /// Creates a new Coyote runtime with the specified . - /// - private static CoyoteRuntime CreateWithConfiguration(CheckerConfiguration checkerConfiguration) - { - if (checkerConfiguration is null) - { - checkerConfiguration = CheckerConfiguration.Create(); - } - - var valueGenerator = new RandomValueGenerator(checkerConfiguration); - return new ActorRuntime(checkerConfiguration, valueGenerator); - } - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Specifications/CachedDelegate.cs b/Src/PChecker/CheckerCore/Runtime/Specifications/CachedDelegate.cs similarity index 95% rename from Src/PChecker/CheckerCore/Specifications/CachedDelegate.cs rename to Src/PChecker/CheckerCore/Runtime/Specifications/CachedDelegate.cs index e6fae4cda5..f1fa273c44 100644 --- a/Src/PChecker/CheckerCore/Specifications/CachedDelegate.cs +++ b/Src/PChecker/CheckerCore/Runtime/Specifications/CachedDelegate.cs @@ -3,9 +3,9 @@ using System; using System.Reflection; -using PChecker.Actors.Events; +using PChecker.Runtime.Events; -namespace PChecker.Specifications.Monitors +namespace PChecker.Runtime.Specifications { /// /// A monitor delegate that has been cached to optimize performance of invocations. diff --git a/Src/PChecker/CheckerCore/Specifications/Monitor.cs b/Src/PChecker/CheckerCore/Runtime/Specifications/Monitor.cs similarity index 95% rename from Src/PChecker/CheckerCore/Specifications/Monitor.cs rename to Src/PChecker/CheckerCore/Runtime/Specifications/Monitor.cs index acf62c8dc9..79e3a79456 100644 --- a/Src/PChecker/CheckerCore/Specifications/Monitor.cs +++ b/Src/PChecker/CheckerCore/Runtime/Specifications/Monitor.cs @@ -10,23 +10,20 @@ using System.Linq.Expressions; using System.Reflection; using System.Threading.Tasks; -using PChecker.Actors; -using PChecker.Actors.Events; -using PChecker.Actors.Handlers; -using PChecker.Actors.Logging; -using PChecker.Actors.StateTransitions; using PChecker.Exceptions; - -namespace PChecker.Specifications.Monitors +using PChecker.Runtime.Events; +using PChecker.Runtime.Exceptions; +using PChecker.Runtime.Logging; +using PChecker.Runtime.StateMachines.Handlers; +using PChecker.Runtime.StateMachines.StateTransitions; +using PChecker.SystematicTesting; + +namespace PChecker.Runtime.Specifications { /// /// Abstract class representing a specification monitor. /// - /// - /// See Specifications Overview - /// for more information. - /// - public abstract class Monitor + public class Monitor { /// /// Map from monitor types to a set of all possible states types. @@ -48,7 +45,7 @@ public abstract class Monitor /// /// A set of lockable objects used to protect static initialization of the ActionCache while - /// also enabling multithreaded initialization of different Actor types. + /// also enabling multithreaded initialization of different StateMachine types. /// private static readonly ConcurrentDictionary ActionCacheLocks = new ConcurrentDictionary(); @@ -61,7 +58,7 @@ public abstract class Monitor /// /// The runtime that executes this monitor. /// - private ActorRuntime Runtime; + private ControlledRuntime Runtime; /// /// The active monitor state. @@ -90,6 +87,16 @@ public abstract class Monitor /// liveness bug has been found. /// private int LivenessTemperature; + + /// + /// List containing all the event types that are observed by this monitor. + /// + public static List observes = new List(); + + /// + /// Temporarily holds data that might be needed during a state transition. + /// + public object gotoPayload; /// /// Gets the name of this monitor. @@ -99,9 +106,6 @@ public abstract class Monitor /// /// The logger installed to the runtime. /// - /// - /// See Logging for more information. - /// protected TextWriter Logger => Runtime.Logger; /// @@ -130,7 +134,7 @@ protected internal Type CurrentState /// internal string CurrentStateName { - get => NameResolver.GetQualifiedStateName(CurrentState); + get => CurrentState.Name; } /// @@ -172,7 +176,7 @@ protected Monitor() /// Initializes this monitor. /// /// The runtime that executes this monitor. - internal void Initialize(ActorRuntime runtime) + internal void Initialize(ControlledRuntime runtime) { Runtime = runtime; } @@ -182,17 +186,39 @@ internal void Initialize(ActorRuntime runtime) /// /// /// This event is not handled until the action that calls this method returns control back - /// to the Coyote runtime. It is handled before any other events are dequeued from the inbox. + /// to the ControlledRuntime. It is handled before any other events are dequeued from the inbox. /// Only one of the following can be called per action: /// , . /// An Assert is raised if you accidentally try and do two of these operations in a single action. /// /// The event to raise. - protected void RaiseEvent(Event e) + public void RaiseEvent(Event e) { Assert(e != null, "{0} is raising a null event.", GetType().FullName); CheckDanglingTransition(); PendingTransition = new Transition(Transition.Type.Raise, default, e); + throw new PNonStandardReturnException { ReturnKind = NonStandardReturn.Raise }; + } + + /// + /// Writes PrintLog messages to logger. + /// + public void LogLine(string message) + { + Logger.WriteLine($" {message}"); + + // Log message to JSON output + JsonLogger.AddLogType(JsonWriter.LogType.Print); + JsonLogger.AddLog(message); + JsonLogger.AddToLogs(updateVcMap: false); + } + + /// + /// Writes message to logger. + /// + public void Log(string message) + { + Logger.Write($"{message}"); } /// @@ -208,15 +234,18 @@ protected void RaiseEvent(Event e) /// this.RaiseEvent(new E()); /// /// This event is not handled until the action that calls this method returns control back - /// to the Coyote runtime. It is handled before any other events are dequeued from the inbox. + /// to the ControlledRuntime. It is handled before any other events are dequeued from the inbox. /// Only one of the following can be called per action: /// , . /// An Assert is raised if you accidentally try and do two of these operations in a single action. /// /// Type of the state. - protected void RaiseGotoStateEvent() - where S : State => + public void RaiseGotoStateEvent(object payload = null) where S : State + { + gotoPayload = payload; RaiseGotoStateEvent(typeof(S)); + throw new PNonStandardReturnException { ReturnKind = NonStandardReturn.Goto }; + } /// /// Raise a special event that performs a goto state operation at the end of the current action. @@ -231,13 +260,13 @@ protected void RaiseGotoStateEvent() /// this.RaiseEvent(new E()); /// /// This event is not handled until the action that calls this method returns control back - /// to the Coyote runtime. It is handled before any other events are dequeued from the inbox. + /// to the ControlledRuntime. It is handled before any other events are dequeued from the inbox. /// Only one of the following can be called per action: /// , . /// An Assert is raised if you accidentally try and do two of these operations in a single action. /// /// Type of the state. - protected void RaiseGotoStateEvent(Type state) + public void RaiseGotoStateEvent(Type state) { // If the state is not a state of the monitor, then report an error and exit. Assert(StateTypeMap[GetType()].Any(val => val.DeclaringType.Equals(state.DeclaringType) && val.Name.Equals(state.Name)), @@ -249,7 +278,7 @@ protected void RaiseGotoStateEvent(Type state) /// /// Checks if the assertion holds, and if not, throws an exception. /// - protected void Assert(bool predicate) + public void Assert(bool predicate) { if (!predicate) { @@ -261,7 +290,7 @@ protected void Assert(bool predicate) /// /// Checks if the assertion holds, and if not, throws an exception. /// - protected void Assert(bool predicate, string s, params object[] args) + public void Assert(bool predicate, string s, params object[] args) { if (!predicate) { @@ -459,6 +488,11 @@ private void ExecuteAction(CachedDelegate cachedAction, Event e) innerException = innerException.InnerException; } + if (innerException is PNonStandardReturnException) + { + return; + } + if (innerException is AggregateException) { innerException = innerException.InnerException; @@ -702,7 +736,7 @@ internal void InitializeStateInformation() var syncObject = ActionCacheLocks.GetOrAdd(monitorType, _ => new object()); // Locking this syncObject ensures only one thread enters the initialization code to update - // the ActionCache for this specific Actor type. + // the ActionCache for this specific StateMachine type. lock (syncObject) { if (MonitorActionMap.ContainsKey(monitorType)) @@ -950,7 +984,7 @@ internal HashSet GetAllStates() var allStates = new HashSet(); foreach (var state in StateMap[GetType()]) { - allStates.Add(NameResolver.GetQualifiedStateName(state.GetType())); + allStates.Add(state.GetType().Name); } return allStates; @@ -968,7 +1002,7 @@ internal HashSet> GetAllStateEventPairs() { foreach (var binding in state.EventHandlers) { - pairs.Add(Tuple.Create(NameResolver.GetQualifiedStateName(state.GetType()), binding.Key.FullName)); + pairs.Add(Tuple.Create(state.GetType().Name, binding.Key.FullName)); } } @@ -979,7 +1013,7 @@ internal HashSet> GetAllStateEventPairs() /// Defines the transition that is the /// result of executing an event handler. Transitions are created by using /// , or . - /// The Transition is processed by the Coyote runtime when + /// The Transition is processed by the ControlledRuntime when /// an event handling method returns a Transition object. /// This means such a method can only do one such Transition per method call. /// If the method wants to do a conditional transition it can return diff --git a/Src/PChecker/CheckerCore/Actors/EventQueues/DequeueStatus.cs b/Src/PChecker/CheckerCore/Runtime/StateMachines/EventQueues/DequeueStatus.cs similarity index 92% rename from Src/PChecker/CheckerCore/Actors/EventQueues/DequeueStatus.cs rename to Src/PChecker/CheckerCore/Runtime/StateMachines/EventQueues/DequeueStatus.cs index 6482634a40..4cce8d1b24 100644 --- a/Src/PChecker/CheckerCore/Actors/EventQueues/DequeueStatus.cs +++ b/Src/PChecker/CheckerCore/Runtime/StateMachines/EventQueues/DequeueStatus.cs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -namespace PChecker.Actors.EventQueues +namespace PChecker.Runtime.StateMachines.EventQueues { /// /// The status returned as the result of a dequeue operation. diff --git a/Src/PChecker/CheckerCore/Actors/EventQueues/EnqueueStatus.cs b/Src/PChecker/CheckerCore/Runtime/StateMachines/EventQueues/EnqueueStatus.cs similarity index 94% rename from Src/PChecker/CheckerCore/Actors/EventQueues/EnqueueStatus.cs rename to Src/PChecker/CheckerCore/Runtime/StateMachines/EventQueues/EnqueueStatus.cs index 57aab56ab6..33ea456768 100644 --- a/Src/PChecker/CheckerCore/Actors/EventQueues/EnqueueStatus.cs +++ b/Src/PChecker/CheckerCore/Runtime/StateMachines/EventQueues/EnqueueStatus.cs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -namespace PChecker.Actors.EventQueues +namespace PChecker.Runtime.StateMachines.EventQueues { /// /// The status returned as the result of an enqueue operation. diff --git a/Src/PChecker/CheckerCore/Actors/EventQueues/Mocks/MockEventQueue.cs b/Src/PChecker/CheckerCore/Runtime/StateMachines/EventQueues/EventQueue.cs similarity index 69% rename from Src/PChecker/CheckerCore/Actors/EventQueues/Mocks/MockEventQueue.cs rename to Src/PChecker/CheckerCore/Runtime/StateMachines/EventQueues/EventQueue.cs index 8142398e5a..7db5bb7440 100644 --- a/Src/PChecker/CheckerCore/Actors/EventQueues/Mocks/MockEventQueue.cs +++ b/Src/PChecker/CheckerCore/Runtime/StateMachines/EventQueues/EventQueue.cs @@ -3,37 +3,36 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; -using PChecker.Actors.Events; -using PChecker.Actors.Managers; +using PChecker.Runtime.Events; +using PChecker.Runtime.StateMachines.Managers; -namespace PChecker.Actors.EventQueues.Mocks +namespace PChecker.Runtime.StateMachines.EventQueues { /// /// Implements a queue of events that is used during testing. /// - internal sealed class MockEventQueue : IEventQueue + internal sealed class EventQueue : IEventQueue { /// - /// Manages the actor that owns this queue. + /// Manages the state machine that owns this queue. /// - private readonly IActorManager ActorManager; + private readonly IStateMachineManager StateMachineManager; /// - /// The actor that owns this queue. + /// The state machine that owns this queue. /// - private readonly Actor Actor; + private readonly StateMachine StateMachine; /// /// The internal queue that contains events with their metadata. /// - private readonly LinkedList<(Event e, Guid opGroupId, EventInfo info)> Queue; + private readonly LinkedList<(Event e, EventInfo info)> Queue; /// /// The raised event and its metadata, or null if no event has been raised. /// - private (Event e, Guid opGroupId, EventInfo info) RaisedEvent; + private (Event e, EventInfo info) RaisedEvent; /// /// Map from the types of events that the owner of the queue is waiting to receive @@ -64,19 +63,19 @@ internal sealed class MockEventQueue : IEventQueue public bool IsEventRaised => RaisedEvent != default; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - internal MockEventQueue(IActorManager actorManager, Actor actor) + internal EventQueue(IStateMachineManager stateMachineManager, StateMachine stateMachine) { - ActorManager = actorManager; - Actor = actor; - Queue = new LinkedList<(Event, Guid, EventInfo)>(); + StateMachineManager = stateMachineManager; + StateMachine = stateMachine; + Queue = new LinkedList<(Event, EventInfo)>(); EventWaitTypes = new Dictionary>(); IsClosed = false; } /// - public EnqueueStatus Enqueue(Event e, Guid opGroupId, EventInfo info) + public EnqueueStatus Enqueue(Event e, EventInfo info) { if (IsClosed) { @@ -87,15 +86,15 @@ public EnqueueStatus Enqueue(Event e, Guid opGroupId, EventInfo info) (predicate is null || predicate(e))) { EventWaitTypes.Clear(); - ActorManager.OnReceiveEvent(e, opGroupId, info); + StateMachineManager.OnReceiveEvent(e, info); ReceiveCompletionSource.SetResult(e); return EnqueueStatus.EventHandlerRunning; } - ActorManager.OnEnqueueEvent(e, opGroupId, info); - Queue.AddLast((e, opGroupId, info)); + StateMachineManager.OnEnqueueEvent(e, info); + Queue.AddLast((e, info)); - if (!ActorManager.IsEventHandlerRunning) + if (!StateMachineManager.IsEventHandlerRunning) { if (TryDequeueEvent(true).e is null) { @@ -103,7 +102,7 @@ public EnqueueStatus Enqueue(Event e, Guid opGroupId, EventInfo info) } else { - ActorManager.IsEventHandlerRunning = true; + StateMachineManager.IsEventHandlerRunning = true; return EnqueueStatus.EventHandlerNotRunning; } } @@ -112,13 +111,13 @@ public EnqueueStatus Enqueue(Event e, Guid opGroupId, EventInfo info) } /// - public (DequeueStatus status, Event e, Guid opGroupId, EventInfo info) Dequeue() + public (DequeueStatus status, Event e, EventInfo info) Dequeue() { // Try to get the raised event, if there is one. Raised events // have priority over the events in the inbox. if (RaisedEvent != default) { - if (ActorManager.IsEventIgnored(RaisedEvent.e, RaisedEvent.opGroupId, RaisedEvent.info)) + if (StateMachineManager.IsEventIgnored(RaisedEvent.e, RaisedEvent.info)) { // TODO: should the user be able to raise an ignored event? // The raised event is ignored in the current state. @@ -128,46 +127,45 @@ public EnqueueStatus Enqueue(Event e, Guid opGroupId, EventInfo info) { var raisedEvent = RaisedEvent; RaisedEvent = default; - return (DequeueStatus.Raised, raisedEvent.e, raisedEvent.opGroupId, raisedEvent.info); + return (DequeueStatus.Raised, raisedEvent.e, raisedEvent.info); } } - var hasDefaultHandler = ActorManager.IsDefaultHandlerAvailable(); + var hasDefaultHandler = StateMachineManager.IsDefaultHandlerAvailable(); if (hasDefaultHandler) { - Actor.Runtime.NotifyDefaultEventHandlerCheck(Actor); + StateMachine.Runtime.NotifyDefaultEventHandlerCheck(StateMachine); } // Try to dequeue the next event, if there is one. - var (e, opGroupId, info) = TryDequeueEvent(); + var (e, info) = TryDequeueEvent(); if (e != null) { // Found next event that can be dequeued. - return (DequeueStatus.Success, e, opGroupId, info); + return (DequeueStatus.Success, e, info); } // No event can be dequeued, so check if there is a default event handler. if (!hasDefaultHandler) { // There is no default event handler installed, so do not return an event. - ActorManager.IsEventHandlerRunning = false; - return (DequeueStatus.NotAvailable, null, Guid.Empty, null); + StateMachineManager.IsEventHandlerRunning = false; + return (DequeueStatus.NotAvailable, null, null); } // TODO: check op-id of default event. // A default event handler exists. - var stateName = Actor is StateMachine stateMachine ? - NameResolver.GetStateNameForLogging(stateMachine.CurrentState) : string.Empty; - var eventOrigin = new EventOriginInfo(Actor.Id, Actor.GetType().FullName, stateName); - return (DequeueStatus.Default, DefaultEvent.Instance, Guid.Empty, new EventInfo(DefaultEvent.Instance, eventOrigin)); + var stateName = StateMachine.CurrentState.GetType().Name; + var eventOrigin = new EventOriginInfo(StateMachine.Id, StateMachine.GetType().FullName, stateName); + return (DequeueStatus.Default, DefaultEvent.Instance, new EventInfo(DefaultEvent.Instance, eventOrigin)); } /// /// Dequeues the next event and its metadata, if there is one available, else returns null. /// - private (Event e, Guid opGroupId, EventInfo info) TryDequeueEvent(bool checkOnly = false) + private (Event e, EventInfo info) TryDequeueEvent(bool checkOnly = false) { - (Event, Guid, EventInfo) nextAvailableEvent = default; + (Event, EventInfo) nextAvailableEvent = default; // Iterates through the events and metadata in the inbox. var node = Queue.First; @@ -176,7 +174,7 @@ public EnqueueStatus Enqueue(Event e, Guid opGroupId, EventInfo info) var nextNode = node.Next; var currentEvent = node.Value; - if (ActorManager.IsEventIgnored(currentEvent.e, currentEvent.opGroupId, currentEvent.info)) + if (StateMachineManager.IsEventIgnored(currentEvent.e, currentEvent.info)) { if (!checkOnly) { @@ -189,7 +187,7 @@ public EnqueueStatus Enqueue(Event e, Guid opGroupId, EventInfo info) } // Skips a deferred event. - if (!ActorManager.IsEventDeferred(currentEvent.e, currentEvent.opGroupId, currentEvent.info)) + if (!StateMachineManager.IsEventDeferred(currentEvent.e, currentEvent.info)) { nextAvailableEvent = currentEvent; if (!checkOnly) @@ -207,14 +205,13 @@ public EnqueueStatus Enqueue(Event e, Guid opGroupId, EventInfo info) } /// - public void RaiseEvent(Event e, Guid opGroupId) + public void RaiseEvent(Event e) { - var stateName = Actor is StateMachine stateMachine ? - NameResolver.GetStateNameForLogging(stateMachine.CurrentState) : string.Empty; - var eventOrigin = new EventOriginInfo(Actor.Id, Actor.GetType().FullName, stateName); + var stateName = StateMachine.CurrentState.GetType().Name; + var eventOrigin = new EventOriginInfo(StateMachine.Id, StateMachine.GetType().FullName, stateName); var info = new EventInfo(e, eventOrigin); - RaisedEvent = (e, opGroupId, info); - ActorManager.OnRaiseEvent(e, opGroupId, info); + RaisedEvent = (e, info); + StateMachineManager.OnRaiseEvent(e, info); } /// @@ -257,9 +254,9 @@ public Task ReceiveEventAsync(params Tuple>[] eve /// private Task ReceiveEventAsync(Dictionary> eventWaitTypes) { - Actor.Runtime.NotifyReceiveCalled(Actor); + StateMachine.Runtime.NotifyReceiveCalled(StateMachine); - (Event e, Guid opGroupId, EventInfo info) receivedEvent = default; + (Event e, EventInfo info) receivedEvent = default; var node = Queue.First; while (node != null) { @@ -279,11 +276,11 @@ private Task ReceiveEventAsync(Dictionary> eventW { ReceiveCompletionSource = new TaskCompletionSource(); EventWaitTypes = eventWaitTypes; - ActorManager.OnWaitEvent(EventWaitTypes.Keys); + StateMachineManager.OnWaitEvent(EventWaitTypes.Keys); return ReceiveCompletionSource.Task; } - ActorManager.OnReceiveEventWithoutWaiting(receivedEvent.e, receivedEvent.opGroupId, receivedEvent.info); + StateMachineManager.OnReceiveEventWithoutWaiting(receivedEvent.e, receivedEvent.info); return Task.FromResult(receivedEvent.e); } @@ -293,14 +290,9 @@ public int GetCachedState() unchecked { var hash = 19; - foreach (var (_, _, info) in Queue) + foreach (var (_, info) in Queue) { hash = (hash * 31) + info.EventName.GetHashCode(); - if (info.HashedState != 0) - { - // Adds the user-defined hashed event state. - hash = (hash * 31) + info.HashedState; - } } return hash; @@ -323,9 +315,9 @@ private void Dispose(bool disposing) return; } - foreach (var (e, opGroupId, info) in Queue) + foreach (var (e, info) in Queue) { - ActorManager.OnDropEvent(e, opGroupId, info); + StateMachineManager.OnDropEvent(e, info); } Queue.Clear(); diff --git a/Src/PChecker/CheckerCore/Actors/EventQueues/IEventQueue.cs b/Src/PChecker/CheckerCore/Runtime/StateMachines/EventQueues/IEventQueue.cs similarity index 86% rename from Src/PChecker/CheckerCore/Actors/EventQueues/IEventQueue.cs rename to Src/PChecker/CheckerCore/Runtime/StateMachines/EventQueues/IEventQueue.cs index 20026e59c9..a74b05edf1 100644 --- a/Src/PChecker/CheckerCore/Actors/EventQueues/IEventQueue.cs +++ b/Src/PChecker/CheckerCore/Runtime/StateMachines/EventQueues/IEventQueue.cs @@ -3,9 +3,9 @@ using System; using System.Threading.Tasks; -using PChecker.Actors.Events; +using PChecker.Runtime.Events; -namespace PChecker.Actors.EventQueues +namespace PChecker.Runtime.StateMachines.EventQueues { /// /// Interface of a queue of events. @@ -25,17 +25,17 @@ internal interface IEventQueue : IDisposable /// /// Enqueues the specified event and its optional metadata. /// - EnqueueStatus Enqueue(Event e, Guid opGroupId, EventInfo info); + EnqueueStatus Enqueue(Event e, EventInfo info); /// /// Dequeues the next event, if there is one available. /// - (DequeueStatus status, Event e, Guid opGroupId, EventInfo info) Dequeue(); + (DequeueStatus status, Event e, EventInfo info) Dequeue(); /// /// Enqueues the specified raised event. /// - void RaiseEvent(Event e, Guid opGroupId); + void RaiseEvent(Event e); /// /// Waits to receive an event of the specified type that satisfies an optional predicate. diff --git a/Src/PChecker/CheckerCore/Actors/Exceptions/ActionExceptionFilterException.cs b/Src/PChecker/CheckerCore/Runtime/StateMachines/Exceptions/ActionExceptionFilterException.cs similarity index 92% rename from Src/PChecker/CheckerCore/Actors/Exceptions/ActionExceptionFilterException.cs rename to Src/PChecker/CheckerCore/Runtime/StateMachines/Exceptions/ActionExceptionFilterException.cs index dcb74df948..ae80a77ea0 100644 --- a/Src/PChecker/CheckerCore/Actors/Exceptions/ActionExceptionFilterException.cs +++ b/Src/PChecker/CheckerCore/Runtime/StateMachines/Exceptions/ActionExceptionFilterException.cs @@ -4,10 +4,10 @@ using System; using PChecker.Exceptions; -namespace PChecker.Actors.Exceptions +namespace PChecker.Runtime.StateMachines.Exceptions { /// - /// Exception that is thrown by the runtime upon an action failure. + /// Exception that is thrown by the runtime upon an action failure. /// internal sealed class ActionExceptionFilterException : RuntimeException { diff --git a/Src/PChecker/CheckerCore/Runtime/StateMachines/Exceptions/OnEventDroppedHandler.cs b/Src/PChecker/CheckerCore/Runtime/StateMachines/Exceptions/OnEventDroppedHandler.cs new file mode 100644 index 0000000000..84f27b5bb2 --- /dev/null +++ b/Src/PChecker/CheckerCore/Runtime/StateMachines/Exceptions/OnEventDroppedHandler.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using PChecker.Runtime.Events; + +namespace PChecker.Runtime.StateMachines.Exceptions +{ + /// + /// Handles the event. + /// + public delegate void OnEventDroppedHandler(Event e, StateMachineId target); +} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Actors/Exceptions/OnExceptionOutcome.cs b/Src/PChecker/CheckerCore/Runtime/StateMachines/Exceptions/OnExceptionOutcome.cs similarity index 52% rename from Src/PChecker/CheckerCore/Actors/Exceptions/OnExceptionOutcome.cs rename to Src/PChecker/CheckerCore/Runtime/StateMachines/Exceptions/OnExceptionOutcome.cs index dfa5bea2e3..bfa30b0396 100644 --- a/Src/PChecker/CheckerCore/Actors/Exceptions/OnExceptionOutcome.cs +++ b/Src/PChecker/CheckerCore/Runtime/StateMachines/Exceptions/OnExceptionOutcome.cs @@ -1,25 +1,25 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -namespace PChecker.Actors.Exceptions +namespace PChecker.Runtime.StateMachines.Exceptions { /// - /// The outcome when an throws an exception. + /// The outcome when an throws an exception. /// public enum OnExceptionOutcome { /// - /// The actor throws the exception causing the runtime to fail. + /// The state machine throws the exception causing the runtime to fail. /// ThrowException = 0, /// - /// The actor handles the exception and resumes execution. + /// The state machine handles the exception and resumes execution. /// HandledException = 1, /// - /// The actor handles the exception and halts. + /// The state machine handles the exception and halts. /// Halt = 2 } diff --git a/Src/PChecker/CheckerCore/Actors/Exceptions/UnhandledEventException.cs b/Src/PChecker/CheckerCore/Runtime/StateMachines/Exceptions/UnhandledEventException.cs similarity index 79% rename from Src/PChecker/CheckerCore/Actors/Exceptions/UnhandledEventException.cs rename to Src/PChecker/CheckerCore/Runtime/StateMachines/Exceptions/UnhandledEventException.cs index 97a1891bab..f4a43cf2ec 100644 --- a/Src/PChecker/CheckerCore/Actors/Exceptions/UnhandledEventException.cs +++ b/Src/PChecker/CheckerCore/Runtime/StateMachines/Exceptions/UnhandledEventException.cs @@ -1,13 +1,13 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using PChecker.Actors.Events; using PChecker.Exceptions; +using PChecker.Runtime.Events; -namespace PChecker.Actors.Exceptions +namespace PChecker.Runtime.StateMachines.Exceptions { /// - /// Signals that an received an unhandled event. + /// Signals that an received an unhandled event. /// public sealed class UnhandledEventException : RuntimeException { @@ -17,7 +17,7 @@ public sealed class UnhandledEventException : RuntimeException public Event UnhandledEvent; /// - /// The name of the current state, if the actor that threw the exception + /// The name of the current state, if the state machine that threw the exception /// is a and a state exists, else null. /// public string CurrentStateName; @@ -26,7 +26,7 @@ public sealed class UnhandledEventException : RuntimeException /// Initializes a new instance of the class. /// /// The event that was unhandled. - /// The name of the current state, if the actor that threw the exception + /// The name of the current state, if the state machine that threw the exception /// is a state machine and a state exists, else null. /// The exception message. internal UnhandledEventException(Event unhandledEvent, string currentStateName, string message) diff --git a/Src/PChecker/CheckerCore/Actors/Handlers/ActionEventHandlerDeclaration.cs b/Src/PChecker/CheckerCore/Runtime/StateMachines/Handlers/ActionEventHandlerDeclaration.cs similarity index 93% rename from Src/PChecker/CheckerCore/Actors/Handlers/ActionEventHandlerDeclaration.cs rename to Src/PChecker/CheckerCore/Runtime/StateMachines/Handlers/ActionEventHandlerDeclaration.cs index eb8a3aa1dc..191317907e 100644 --- a/Src/PChecker/CheckerCore/Actors/Handlers/ActionEventHandlerDeclaration.cs +++ b/Src/PChecker/CheckerCore/Runtime/StateMachines/Handlers/ActionEventHandlerDeclaration.cs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -namespace PChecker.Actors.Handlers +namespace PChecker.Runtime.StateMachines.Handlers { /// /// Defines an action event handler declaration. diff --git a/Src/PChecker/CheckerCore/Actors/Handlers/CachedDelegate.cs b/Src/PChecker/CheckerCore/Runtime/StateMachines/Handlers/CachedDelegate.cs similarity index 89% rename from Src/PChecker/CheckerCore/Actors/Handlers/CachedDelegate.cs rename to Src/PChecker/CheckerCore/Runtime/StateMachines/Handlers/CachedDelegate.cs index 1d69e9511b..3fbd9b6c00 100644 --- a/Src/PChecker/CheckerCore/Actors/Handlers/CachedDelegate.cs +++ b/Src/PChecker/CheckerCore/Runtime/StateMachines/Handlers/CachedDelegate.cs @@ -4,12 +4,12 @@ using System; using System.Reflection; using System.Threading.Tasks; -using PChecker.Actors.Events; +using PChecker.Runtime.Events; -namespace PChecker.Actors.Handlers +namespace PChecker.Runtime.StateMachines.Handlers { /// - /// An actor delegate that has been cached to optimize performance of invocations. + /// An state machine delegate that has been cached to optimize performance of invocations. /// internal class CachedDelegate { diff --git a/Src/PChecker/CheckerCore/Actors/Handlers/DeferEventHandlerDeclaration.cs b/Src/PChecker/CheckerCore/Runtime/StateMachines/Handlers/DeferEventHandlerDeclaration.cs similarity index 86% rename from Src/PChecker/CheckerCore/Actors/Handlers/DeferEventHandlerDeclaration.cs rename to Src/PChecker/CheckerCore/Runtime/StateMachines/Handlers/DeferEventHandlerDeclaration.cs index 428426ed4a..9e3bf9a065 100644 --- a/Src/PChecker/CheckerCore/Actors/Handlers/DeferEventHandlerDeclaration.cs +++ b/Src/PChecker/CheckerCore/Runtime/StateMachines/Handlers/DeferEventHandlerDeclaration.cs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -namespace PChecker.Actors.Handlers +namespace PChecker.Runtime.StateMachines.Handlers { /// /// Defines a defer event handler declaration. diff --git a/Src/PChecker/CheckerCore/Actors/Handlers/EventHandlerDeclaration.cs b/Src/PChecker/CheckerCore/Runtime/StateMachines/Handlers/EventHandlerDeclaration.cs similarity index 84% rename from Src/PChecker/CheckerCore/Actors/Handlers/EventHandlerDeclaration.cs rename to Src/PChecker/CheckerCore/Runtime/StateMachines/Handlers/EventHandlerDeclaration.cs index 870fae0ca7..6d9462251f 100644 --- a/Src/PChecker/CheckerCore/Actors/Handlers/EventHandlerDeclaration.cs +++ b/Src/PChecker/CheckerCore/Runtime/StateMachines/Handlers/EventHandlerDeclaration.cs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -namespace PChecker.Actors.Handlers +namespace PChecker.Runtime.StateMachines.Handlers { /// /// An abstract event handler declaration. diff --git a/Src/PChecker/CheckerCore/Actors/Handlers/IgnoreEventHandlerDeclaration.cs b/Src/PChecker/CheckerCore/Runtime/StateMachines/Handlers/IgnoreEventHandlerDeclaration.cs similarity index 86% rename from Src/PChecker/CheckerCore/Actors/Handlers/IgnoreEventHandlerDeclaration.cs rename to Src/PChecker/CheckerCore/Runtime/StateMachines/Handlers/IgnoreEventHandlerDeclaration.cs index 0486c36c04..454a9524e4 100644 --- a/Src/PChecker/CheckerCore/Actors/Handlers/IgnoreEventHandlerDeclaration.cs +++ b/Src/PChecker/CheckerCore/Runtime/StateMachines/Handlers/IgnoreEventHandlerDeclaration.cs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -namespace PChecker.Actors.Handlers +namespace PChecker.Runtime.StateMachines.Handlers { /// /// Defines an ignore event handler declaration. diff --git a/Src/PChecker/CheckerCore/Actors/Managers/IActorManager.cs b/Src/PChecker/CheckerCore/Runtime/StateMachines/Managers/IStateMachineManager.cs similarity index 53% rename from Src/PChecker/CheckerCore/Actors/Managers/IActorManager.cs rename to Src/PChecker/CheckerCore/Runtime/StateMachines/Managers/IStateMachineManager.cs index bc2ec7ab8e..52d6677292 100644 --- a/Src/PChecker/CheckerCore/Actors/Managers/IActorManager.cs +++ b/Src/PChecker/CheckerCore/Runtime/StateMachines/Managers/IStateMachineManager.cs @@ -3,39 +3,34 @@ using System; using System.Collections.Generic; -using PChecker.Actors.Events; +using PChecker.Runtime.Events; -namespace PChecker.Actors.Managers +namespace PChecker.Runtime.StateMachines.Managers { /// - /// Interface for managing an actor. + /// Interface for managing a state machine. /// - internal interface IActorManager + internal interface IStateMachineManager { /// - /// True if the event handler of the actor is running, else false. + /// True if the event handler of the state machine is running, else false. /// bool IsEventHandlerRunning { get; set; } - - /// - /// Id used to identify subsequent operations performed by the actor. - /// - Guid OperationGroupId { get; set; } - + /// - /// Returns the cached state of the actor. + /// Returns the cached state of the state machine. /// int GetCachedState(); /// /// Checks if the specified event is currently ignored. /// - bool IsEventIgnored(Event e, Guid opGroupId, EventInfo eventInfo); + bool IsEventIgnored(Event e, EventInfo eventInfo); /// /// Checks if the specified event is currently deferred. /// - bool IsEventDeferred(Event e, Guid opGroupId, EventInfo eventInfo); + bool IsEventDeferred(Event e, EventInfo eventInfo); /// /// Checks if a default handler is currently available. @@ -43,35 +38,35 @@ internal interface IActorManager bool IsDefaultHandlerAvailable(); /// - /// Notifies the actor that an event has been enqueued. + /// Notifies the state machine that an event has been enqueued. /// - void OnEnqueueEvent(Event e, Guid opGroupId, EventInfo eventInfo); + void OnEnqueueEvent(Event e, EventInfo eventInfo); /// - /// Notifies the actor that an event has been raised. + /// Notifies the state machine that an event has been raised. /// - void OnRaiseEvent(Event e, Guid opGroupId, EventInfo eventInfo); + void OnRaiseEvent(Event e, EventInfo eventInfo); /// - /// Notifies the actor that it is waiting to receive an event of one of the specified types. + /// Notifies the state machine that it is waiting to receive an event of one of the specified types. /// void OnWaitEvent(IEnumerable eventTypes); /// - /// Notifies the actor that an event it was waiting to receive has been enqueued. + /// Notifies the state machine that an event it was waiting to receive has been enqueued. /// - void OnReceiveEvent(Event e, Guid opGroupId, EventInfo eventInfo); + void OnReceiveEvent(Event e, EventInfo eventInfo); /// - /// Notifies the actor that an event it was waiting to receive was already in the - /// event queue when the actor invoked the receive statement. + /// Notifies the state machine that an event it was waiting to receive was already in the + /// event queue when the state machine invoked the receiving statement. /// - void OnReceiveEventWithoutWaiting(Event e, Guid opGroupId, EventInfo eventInfo); + void OnReceiveEventWithoutWaiting(Event e, EventInfo eventInfo); /// - /// Notifies the actor that an event has been dropped. + /// Notifies the state machine that an event has been dropped. /// - void OnDropEvent(Event e, Guid opGroupId, EventInfo eventInfo); + void OnDropEvent(Event e, EventInfo eventInfo); /// /// Asserts if the specified condition holds. diff --git a/Src/PChecker/CheckerCore/Actors/Managers/Mocks/MockStateMachineManager.cs b/Src/PChecker/CheckerCore/Runtime/StateMachines/Managers/StateMachineManager.cs similarity index 71% rename from Src/PChecker/CheckerCore/Actors/Managers/Mocks/MockStateMachineManager.cs rename to Src/PChecker/CheckerCore/Runtime/StateMachines/Managers/StateMachineManager.cs index 92bd38948b..549f37ed0b 100644 --- a/Src/PChecker/CheckerCore/Actors/Managers/Mocks/MockStateMachineManager.cs +++ b/Src/PChecker/CheckerCore/Runtime/StateMachines/Managers/StateMachineManager.cs @@ -4,15 +4,15 @@ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; -using PChecker.Actors.Events; +using PChecker.Runtime.Events; using PChecker.SystematicTesting; -namespace PChecker.Actors.Managers.Mocks +namespace PChecker.Runtime.StateMachines.Managers { /// /// Implements a state machine manager that is used during testing. /// - internal sealed class MockStateMachineManager : IActorManager + internal sealed class StateMachineManager : IStateMachineManager { /// /// The runtime that executes the state machine being managed. @@ -27,9 +27,6 @@ internal sealed class MockStateMachineManager : IActorManager /// public bool IsEventHandlerRunning { get; set; } - /// - public Guid OperationGroupId { get; set; } - /// /// Program counter used for state-caching. Distinguishes /// scheduling from non-deterministic choices. @@ -37,14 +34,13 @@ internal sealed class MockStateMachineManager : IActorManager internal int ProgramCounter; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - internal MockStateMachineManager(ControlledRuntime runtime, StateMachine instance, Guid operationGroupId) + internal StateMachineManager(ControlledRuntime runtime, StateMachine instance) { Runtime = runtime; Instance = instance; IsEventHandlerRunning = true; - OperationGroupId = operationGroupId; ProgramCounter = 0; } @@ -62,12 +58,12 @@ public int GetCachedState() /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsEventIgnored(Event e, Guid opGroupId, EventInfo eventInfo) => + public bool IsEventIgnored(Event e, EventInfo eventInfo) => Instance.IsEventIgnoredInCurrentState(e); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsEventDeferred(Event e, Guid opGroupId, EventInfo eventInfo) => + public bool IsEventDeferred(Event e, EventInfo eventInfo) => Instance.IsEventDeferredInCurrentState(e); /// @@ -76,12 +72,12 @@ public bool IsEventDeferred(Event e, Guid opGroupId, EventInfo eventInfo) => /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void OnEnqueueEvent(Event e, Guid opGroupId, EventInfo eventInfo) => + public void OnEnqueueEvent(Event e, EventInfo eventInfo) => Runtime.LogWriter.LogEnqueueEvent(Instance.Id, e); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void OnRaiseEvent(Event e, Guid opGroupId, EventInfo eventInfo) => + public void OnRaiseEvent(Event e, EventInfo eventInfo) => Runtime.NotifyRaisedEvent(Instance, e, eventInfo); /// @@ -90,33 +86,21 @@ public void OnWaitEvent(IEnumerable eventTypes) => Runtime.NotifyWaitEvent(Instance, eventTypes); /// - public void OnReceiveEvent(Event e, Guid opGroupId, EventInfo eventInfo) + public void OnReceiveEvent(Event e, EventInfo eventInfo) { - if (opGroupId != Guid.Empty) - { - // Inherit the operation group id of the receive operation, if it is non-empty. - OperationGroupId = opGroupId; - } - Runtime.NotifyReceivedEvent(Instance, e, eventInfo); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void OnReceiveEventWithoutWaiting(Event e, Guid opGroupId, EventInfo eventInfo) + public void OnReceiveEventWithoutWaiting(Event e, EventInfo eventInfo) { - if (opGroupId != Guid.Empty) - { - // Inherit the operation group id of the receive operation, if it is non-empty. - OperationGroupId = opGroupId; - } - Runtime.NotifyReceivedEventWithoutWaiting(Instance, e, eventInfo); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void OnDropEvent(Event e, Guid opGroupId, EventInfo eventInfo) + public void OnDropEvent(Event e, EventInfo eventInfo) { Runtime.TryHandleDroppedEvent(e, Instance.Id); } diff --git a/Src/PChecker/CheckerCore/Actors/StateMachine.cs b/Src/PChecker/CheckerCore/Runtime/StateMachines/StateMachine.cs similarity index 56% rename from Src/PChecker/CheckerCore/Actors/StateMachine.cs rename to Src/PChecker/CheckerCore/Runtime/StateMachines/StateMachine.cs index 27e5d910da..0c2ae5701a 100644 --- a/Src/PChecker/CheckerCore/Actors/StateMachine.cs +++ b/Src/PChecker/CheckerCore/Runtime/StateMachines/StateMachine.cs @@ -4,25 +4,56 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Globalization; +using System.IO; using System.Linq; using System.Linq.Expressions; using System.Reflection; +using System.Runtime.CompilerServices; using System.Threading.Tasks; -using PChecker.Actors.Events; -using PChecker.Actors.Exceptions; -using PChecker.Actors.Handlers; -using PChecker.Actors.StateTransitions; using PChecker.Exceptions; - -namespace PChecker.Actors +using PChecker.IO.Debugging; +using PChecker.Runtime.Events; +using PChecker.Runtime.Exceptions; +using PChecker.Runtime.Logging; +using PChecker.Runtime.StateMachines.EventQueues; +using PChecker.Runtime.StateMachines.Exceptions; +using PChecker.Runtime.StateMachines.Handlers; +using PChecker.Runtime.StateMachines.Managers; +using PChecker.Runtime.StateMachines.StateTransitions; +using PChecker.Runtime.Values; +using PChecker.SystematicTesting; +using EventInfo = PChecker.Runtime.Events.EventInfo; + + +namespace PChecker.Runtime.StateMachines { /// - /// Type that implements a state machine actor. Inherit from this class to declare - /// a custom actor with states, state transitions and event handlers. + /// Type that implements a state machine with states, state transitions and event handlers. /// - public abstract class StateMachine : Actor + public abstract class StateMachine { + + /// + /// The runtime that executes this state machine. + /// + internal ControlledRuntime Runtime { get; private set; } + + /// + /// Unique id that identifies this state machine. + /// + protected internal StateMachineId Id { get; private set; } + + /// + /// Manages the state machine. + /// + internal IStateMachineManager Manager { get; private set; } + + /// + /// The inbox of the state machine. Incoming events are enqueued here. + /// Events are dequeued to be processed. + /// + private protected IEventQueue Inbox; + /// /// Cache of state machine types to a map of action names to action declarations. /// @@ -35,7 +66,7 @@ public abstract class StateMachine : Actor /// private static readonly ConcurrentDictionary ActionCacheLocks = new ConcurrentDictionary(); - + /// /// Cache of state machine types to a set of all possible states types. /// @@ -48,19 +79,6 @@ public abstract class StateMachine : Actor private static readonly ConcurrentDictionary> StateInstanceCache = new ConcurrentDictionary>(); - /// - /// A stack of states. The state on the top of the stack represents the current state. - /// - private readonly Stack StateStack; - - /// - /// A map from event type to a Stack of HandlerInfo where the stack contains the inheritable - /// event handlers defined by each state that has been pushed onto the StateStack (if any). - /// The HandlerInfo also remembers which state the handler was defined on so that when the - /// handler is invoked the IActorRuntimeLog can be given that information. - /// - private readonly Dictionary> InheritableEventHandlerMap; - /// /// A map from event type to EventHandlerDeclaration for those EventHandlerDeclarations that /// are not inheritable on the state stack. @@ -76,6 +94,32 @@ public abstract class StateMachine : Actor /// Map from action names to cached action delegates for all states in this state machine. /// private readonly Dictionary StateMachineActionMap; + + /// + /// A cached array that contains a single event type. + /// + private static readonly Type[] SingleEventTypeArray = new Type[] { typeof(Event) }; + + /// + /// The current status of the state machine. It is marked volatile as + /// the runtime can read it concurrently. + /// + private protected volatile Status CurrentStatus; + + /// + /// Gets the name of the current state, if there is one. + /// + internal string CurrentStateName { get; private protected set; } + + /// + /// Checks if the state machine is halted. + /// + internal bool IsHalted => CurrentStatus is Status.Halted; + + /// + /// Checks if a default handler is available. + /// + internal bool IsDefaultHandlerAvailable { get; private set; } /// /// Newly created Transition that hasn't been returned from InvokeActionAsync yet. @@ -85,25 +129,327 @@ public abstract class StateMachine : Actor /// /// Gets the of the current state. /// - protected internal Type CurrentState { get; private set; } + protected internal State CurrentState { get; private set; } + + /// + /// The installed runtime logger. + /// + protected TextWriter Logger => Runtime.Logger; + + /// + /// The installed runtime json logger. + /// + protected JsonWriter JsonLogger => Runtime.JsonLogger; + + protected IPValue gotoPayload; + + public List creates = new List(); + public string interfaceName; + public List receives = new List(); + public PMachineValue self; + public List sends = new List(); + + protected virtual Event GetConstructorEvent(IPValue value) + { + throw new NotImplementedException(); + } + + /// + /// + /// + /// + /// + /// + /// + public PMachineValue CreateInterface(StateMachine creator, IPValue payload = null) + where T : PMachineValue + { + var createdInterface = PModule.linkMap[creator.interfaceName][typeof(T).Name]; + Assert(creates.Contains(createdInterface), + $"Machine {GetType().Name} cannot create interface {createdInterface}, not in its creates set"); + var createMachine = PModule.interfaceDefinitionMap[createdInterface]; + var machineId = CreateStateMachine(createMachine, createdInterface.Substring(2), + GetConstructorEvent(payload)); + return new PMachineValue(machineId, PInterfaces.GetPermissions(createdInterface)); + } + + + /// + /// + /// + /// + /// + /// + public IPValue TryRandom(IPValue param) + { + switch (param) + { + case PInt maxValue: + { + Assert(maxValue <= 10000, $"choose expects a parameter with at most 10000 choices, got {maxValue} choices instead."); + return (PInt)RandomInteger(maxValue); + } + + case PSeq seq: + { + Assert(seq.Any(), "Trying to choose from an empty sequence!"); + Assert(seq.Count <= 10000, $"choose expects a parameter with at most 10000 choices, got {seq.Count} choices instead."); + return seq[RandomInteger(seq.Count)]; + } + case PSet set: + { + Assert(set.Any(), "Trying to choose from an empty set!"); + Assert(set.Count <= 10000, $"choose expects a parameter with at most 10000 choices, got {set.Count} choices instead."); + return set.ElementAt(RandomInteger(set.Count)); + } + case PMap map: + { + Assert(map.Any(), "Trying to choose from an empty map!"); + Assert(map.Keys.Count <= 10000, $"choose expects a parameter with at most 10000 choices, got {map.Keys.Count} choices instead."); + return map.Keys.ElementAt(RandomInteger(map.Keys.Count)); + } + default: + throw new PInternalException("This is an unexpected (internal) P exception. Please report to the P Developers"); + } + } + + public void LogLine(string message) + { + Logger.WriteLine($" {message}"); + + // Log message to JSON output + JsonLogger.AddLogType(JsonWriter.LogType.Print); + JsonLogger.AddLog(message); + JsonLogger.AddToLogs(updateVcMap: false); + } + + public void Log(string message) + { + Logger.Write($"{message}"); + } + + public void Announce(Event ev, object payload = null) + { + Assert(ev != null, "Machine cannot announce a null event"); + if (ev is PHalt) + { + ev = HaltEvent.Instance; + } + + var oneArgConstructor = ev.GetType().GetConstructors().First(x => x.GetParameters().Length > 0); + var @event = (Event)oneArgConstructor.Invoke(new[] { payload }); + var pText = payload == null ? "" : $" with payload {((IPValue)payload).ToEscapedString()}"; + + Logger.WriteLine($" '{Id}' announced event '{ev.GetType().Name}'{pText}."); + + // Log message to JSON output + JsonLogger.AddLogType(JsonWriter.LogType.Announce); + JsonLogger.LogDetails.Id = $"{Id}"; + JsonLogger.LogDetails.Event = ev.GetType().Name; + if (payload != null) + { + JsonLogger.LogDetails.Payload = ((IPValue)payload).ToDict(); + } + JsonLogger.AddLog($"{Id} announced event {ev.GetType().Name}{pText}."); + JsonLogger.AddToLogs(updateVcMap: true); + + AnnounceInternal(@event); + } + + private void AnnounceInternal(Event ev) + { + Assert(ev != null, "cannot send a null event"); + if (!PModule.monitorMap.ContainsKey(interfaceName)) + { + return; + } + foreach (var monitor in PModule.monitorMap[interfaceName]) + { + if (PModule.monitorObserves[monitor.Name].Contains(ev.GetType().Name)) + { + Monitor(monitor, ev); + } + } + } + /// /// Initializes a new instance of the class. /// protected StateMachine() : base() { - StateStack = new Stack(); - InheritableEventHandlerMap = new Dictionary>(); + CurrentStatus = Status.Active; + CurrentStateName = default; + IsDefaultHandlerAvailable = false; EventHandlerMap = EmptyEventHandlerMap; StateMachineActionMap = new Dictionary(); } + + /// + /// Configures the state machine. + /// + internal void Configure(ControlledRuntime runtime, StateMachineId id, IStateMachineManager manager, IEventQueue inbox) + { + Runtime = runtime; + Id = id; + Manager = manager; + Inbox = inbox; + } + + /// + /// Returns a nondeterministic boolean choice, that can be + /// controlled during analysis or testing. + /// + /// The controlled nondeterministic choice. + public bool RandomBoolean() => Runtime.GetNondeterministicBooleanChoice(2, Id.Name, Id.Type); + + /// + /// Returns a nondeterministic boolean choice, that can be + /// controlled during analysis or testing. The value is used + /// to generate a number in the range [0..maxValue), where 0 + /// triggers true. + /// + /// The max value. + /// The controlled nondeterministic choice. + public bool RandomBoolean(int maxValue) => + Runtime.GetNondeterministicBooleanChoice(maxValue, Id.Name, Id.Type); + + /// + /// Returns a nondeterministic integer, that can be controlled during + /// analysis or testing. The value is used to generate an integer in + /// the range [0..maxValue). + /// + /// The max value. + /// The controlled nondeterministic integer. + public int RandomInteger(int maxValue) => + Runtime.GetNondeterministicIntegerChoice(maxValue, Id.Name, Id.Type); + + public int RandomInteger(int minValue, int maxValue) + { + return minValue + RandomInteger(maxValue - minValue); + } + + /// + /// Invokes the specified monitor with the specified . + /// + /// Type of the monitor. + /// Event to send to the monitor. + protected void Monitor(Event e) => Monitor(typeof(T), e); + + /// + /// Invokes the specified monitor with the specified event. + /// + /// Type of the monitor. + /// The event to send. + protected void Monitor(Type type, Event e) + { + Assert(e != null, "{0} is sending a null event.", Id); + Runtime.Monitor(type, e, Id.Name, Id.Type, CurrentStateName); + } + + /// + /// Checks if the assertion holds, and if not, throws an exception. + /// + public void Assert(bool predicate) => Runtime.Assert(predicate); + + /// + /// Checks if the assertion holds, and if not, throws an exception. + /// + public void Assert(bool predicate, string s, object arg0) => + Runtime.Assert(predicate, s, arg0); + + /// + /// Checks if the assertion holds, and if not, throws an exception. + /// + public void Assert(bool predicate, string s, object arg0, object arg1) => + Runtime.Assert(predicate, s, arg0, arg1); + + /// + /// Checks if the assertion holds, and if not, throws an exception. + /// + public void Assert(bool predicate, string s, object arg0, object arg1, object arg2) => + Runtime.Assert(predicate, s, arg0, arg1, arg2); + + /// + /// Checks if the assertion holds, and if not, throws an exception. + /// + public void Assert(bool predicate, string s, params object[] args) => + Runtime.Assert(predicate, s, args); + + /// + /// Asynchronous callback that is invoked when the state machine is initialized with an optional event. + /// + /// Optional event used for initialization. + /// Task that represents the asynchronous operation. + protected virtual Task OnInitializeAsync(Event initialEvent) => Task.CompletedTask; + + /// + /// Asynchronous callback that is invoked when the state machine successfully dequeues + /// an event from its inbox. This method is not called when the dequeue happens + /// via a receive statement. + /// + /// The event that was dequeued. + protected virtual Task OnEventDequeuedAsync(Event e) => Task.CompletedTask; + + /// + /// Asynchronous callback that is invoked when the state machine finishes handling a dequeued + /// event, unless the handler of the dequeued event caused the state machine to halt (either + /// normally or due to an exception). The state machine will either become idle or dequeue + /// the next event from its inbox. + /// + /// The event that was handled. + protected virtual Task OnEventHandledAsync(Event e) => Task.CompletedTask; + + /// + /// Asynchronous callback that is invoked when the state machine receives an event that + /// it is not prepared to handle. The callback is invoked first, after which the + /// state machine will necessarily throw an + /// + /// The event that was unhandled. + /// The state when the event was dequeued. + protected Task OnEventUnhandledAsync(Event e, string state) => Task.CompletedTask; + + /// + /// Asynchronous callback that is invoked when the state machine handles an exception. + /// + /// The exception thrown by the state machine. + /// The event being handled when the exception was thrown. + /// The action that the runtime should take. + protected Task OnExceptionHandledAsync(Exception ex, Event e) => Task.CompletedTask; + + /// + /// Asynchronous callback that is invoked when the state machine halts. + /// + /// The event being handled when the state machine halted. + /// Task that represents the asynchronous operation. + protected Task OnHaltAsync(Event e) => Task.CompletedTask; + + /// + /// Halts the state machine. + /// + /// The event being handled when the state machine halts. + private protected Task HaltAsync(Event e) + { + CurrentStatus = Status.Halted; + + // Close the inbox, which will stop any subsequent enqueues. + Inbox.Close(); + + Runtime.LogWriter.LogHalt(Id, Inbox.Size); + + // Dispose any held resources. + Inbox.Dispose(); + // Invoke user callback. + return OnHaltAsync(e); + } + /// - /// Initializes the actor with the specified optional event. + /// Initializes the state machine with the specified optional event. /// /// Optional event used for initialization. - internal override async Task InitializeAsync(Event initialEvent) + internal async Task InitializeAsync(Event initialEvent) { // Invoke the custom initializer, if there is one. await InvokeUserCallbackAsync(UserCallbackType.OnInitialize, initialEvent); @@ -115,6 +461,480 @@ internal override async Task InitializeAsync(Event initialEvent) await HaltAsync(initialEvent); } } + + /// + /// An exception filter that calls, + /// which can choose to fast-fail the app to get a full dump. + /// + /// The action being executed when the failure occurred. + /// The exception being tested. + private protected bool InvokeOnFailureExceptionFilter(CachedDelegate action, Exception ex) + { + // This is called within the exception filter so the stack has not yet been unwound. + // If the call does not fail-fast, return false to process the exception normally. + Runtime.RaiseOnFailureEvent(new ActionExceptionFilterException(action.MethodInfo.Name, ex)); + return false; + } + + /// + /// Tries to handle an exception thrown during an action invocation. + /// + private protected Task TryHandleActionInvocationExceptionAsync(Exception ex, string actionName) + { + var innerException = ex; + while (innerException is TargetInvocationException) + { + innerException = innerException.InnerException; + } + + if (innerException is AggregateException) + { + innerException = innerException.InnerException; + } + + if (innerException is ExecutionCanceledException || innerException is TaskSchedulerException) + { + CurrentStatus = Status.Halted; + Debug.WriteLine($" {innerException.GetType().Name} was thrown from {Id}."); + } + else + { + // Reports the unhandled exception. + ReportUnhandledException(innerException, actionName); + } + + return Task.CompletedTask; + } + + /// + /// Creates a new state machine of the specified type and name, and with the specified + /// optional . This can only be used to + /// access its payload, and cannot be handled. + /// + /// Type of the state machine. + /// Optional name used for logging. + /// Optional initialization event. + /// Optional id that can be used to identify this operation. + /// The unique state machine id. + protected StateMachineId CreateStateMachine(Type type, string name, Event initialEvent = null) => + Runtime.CreateStateMachine(null, type, name, initialEvent, this); + + + /// + /// Sends an asynchronous to a target. + /// + /// The target. + /// The event to send. + /// Optional id that can be used to identify this operation. + public void SendEvent(PMachineValue target, Event ev) + { + Assert(ev != null, "Machine cannot send a null event"); + Assert(target != null, "Machine in send cannot be null"); + Assert(sends.Contains(ev.GetType().Name), + $"Event {ev.GetType().Name} is not in the sends set of the Machine {GetType().Name}"); + Assert(target.Permissions.Contains(ev.GetType().Name), + $"Event {ev.GetType().Name} is not in the permissions set of the target machine"); + AnnounceInternal(ev); + Runtime.SendEvent(target.Id, ev, this); + } + + /// + /// Waits to receive an of the specified type + /// that satisfies an optional predicate. + /// + /// The event type. + /// The optional predicate. + /// The received event. + public Task ReceiveEventAsync(Type eventType, Func predicate = null) + { + Assert(CurrentStatus is Status.Active, "{0} invoked ReceiveEventAsync while halting.", Id); + Runtime.NotifyReceiveCalled(this); + return Inbox.ReceiveEventAsync(eventType, predicate); + } + + /// + /// Waits to receive an of the specified types. + /// + /// The event types to wait for. + /// The received event. + public Task ReceiveEventAsync(params Type[] eventTypes) + { + Assert(CurrentStatus is Status.Active, "{0} invoked ReceiveEventAsync while halting.", Id); + Runtime.NotifyReceiveCalled(this); + return Inbox.ReceiveEventAsync(eventTypes); + } + + /// + /// Waits to receive an of the specified types + /// that satisfy the specified predicates. + /// + /// Event types and predicates. + /// The received event. + public Task ReceiveEventAsync(params Tuple>[] events) + { + Assert(CurrentStatus is Status.Active, "{0} invoked ReceiveEventAsync while halting.", Id); + Runtime.NotifyReceiveCalled(this); + return Inbox.ReceiveEventAsync(events); + } + + /// + /// Runs the event handler. The handler terminates if there is no next + /// event to process or if the state machine has halted. + /// + internal async Task RunEventHandlerAsync() + { + Event lastDequeuedEvent = null; + while (CurrentStatus != Status.Halted && Runtime.IsRunning) + { + (var status, var e, var info) = Inbox.Dequeue(); + + if (status is DequeueStatus.Success) + { + // Notify the runtime for a new event to handle. This is only used + // during bug-finding and operation bounding, because the runtime + // has to schedule an state machine when a new operation is dequeued. + Runtime.NotifyDequeuedEvent(this, e, info); + await InvokeUserCallbackAsync(UserCallbackType.OnEventDequeued, e); + lastDequeuedEvent = e; + } + else if (status is DequeueStatus.Raised) + { + // Only supported by types (e.g. StateMachine) that allow + // the user to explicitly raise events. + Runtime.NotifyHandleRaisedEvent(this, e); + } + else if (status is DequeueStatus.Default) + { + Runtime.LogWriter.LogDefaultEventHandler(Id, CurrentStateName); + + // If the default event was dequeued, then notify the runtime. + // This is only used during bug-finding, because the runtime must + // instrument a scheduling point between default event handlers. + Runtime.NotifyDefaultEventDequeued(this); + } + else if (status is DequeueStatus.NotAvailable) + { + // Terminate the handler as there is no event available. + break; + } + + if (CurrentStatus is Status.Active) + { + // Handles the next event, if the state machine is not halted. + await HandleEventAsync(e); + } + + if (!Inbox.IsEventRaised && lastDequeuedEvent != null && CurrentStatus != Status.Halted) + { + // Inform the user that the state machine handled the dequeued event. + await InvokeUserCallbackAsync(UserCallbackType.OnEventHandled, lastDequeuedEvent); + lastDequeuedEvent = null; + } + + if (CurrentStatus is Status.Halting) + { + // If the current status is halting, then halt the state machine. + await HaltAsync(e); + } + } + } + + /// + /// Invokes the specified event handler user callback. + /// + private protected async Task InvokeUserCallbackAsync(string callbackType, Event e, string currentState = default) + { + try + { + Task task = null; + if (callbackType is UserCallbackType.OnInitialize) + { + task = OnInitializeAsync(e); + } + else if (callbackType is UserCallbackType.OnEventDequeued) + { + task = OnEventDequeuedAsync(e); + } + else if (callbackType is UserCallbackType.OnEventHandled) + { + task = OnEventHandledAsync(e); + } + else if (callbackType is UserCallbackType.OnEventUnhandled) + { + task = OnEventUnhandledAsync(e, currentState); + } + + Runtime.NotifyWaitTask(this, task); + await task; + } + catch (Exception ex) when (OnExceptionHandler(ex, callbackType, e)) + { + // User handled the exception. + await OnExceptionHandledAsync(ex, e); + } + catch (Exception ex) + { + // Reports the unhandled exception. + await TryHandleActionInvocationExceptionAsync(ex, callbackType); + } + } + + /// + /// Invokes the specified action delegate. + /// + private protected async Task InvokeActionAsync(CachedDelegate cachedAction, Event e) + { + try + { + if (cachedAction.IsAsync) + { + Task task = null; + if (cachedAction.Handler is Func taskFuncWithEvent) + { + task = taskFuncWithEvent(e); + } + else if (cachedAction.Handler is Func taskFunc) + { + task = taskFunc(); + } + + Runtime.NotifyWaitTask(this, task); + + // We have no reliable stack for awaited operations. + await task; + } + else if (cachedAction.Handler is Action actionWithEvent) + { + actionWithEvent(e); + } + else if (cachedAction.Handler is Action action) + { + action(); + } + } + catch (Exception ex) when (OnExceptionHandler(ex, cachedAction.MethodInfo.Name, e)) + { + // User handled the exception. + await OnExceptionHandledAsync(ex, e); + } + catch (Exception ex) when (!cachedAction.IsAsync && InvokeOnFailureExceptionFilter(cachedAction, ex)) + { + // Use an exception filter to call OnFailure before the stack + // has been unwound. If the exception filter does not fail-fast, + // it returns false to process the exception normally. + } + catch (Exception ex) + { + await TryHandleActionInvocationExceptionAsync(ex, cachedAction.MethodInfo.Name); + } + } + + /// + /// Returns the action with the specified name. + /// + private protected MethodInfo GetActionWithName(string actionName) + { + MethodInfo action; + var stateMachineType = GetType(); + + do + { + var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | + BindingFlags.Instance | BindingFlags.FlattenHierarchy; + action = stateMachineType.GetMethod(actionName, bindingFlags, Type.DefaultBinder, SingleEventTypeArray, null); + if (action is null) + { + action = stateMachineType.GetMethod(actionName, bindingFlags, Type.DefaultBinder, Array.Empty(), null); + } + + stateMachineType = stateMachineType.BaseType; + } + while (action is null && stateMachineType != typeof(StateMachine)); + + Assert(action != null, "Cannot detect action declaration '{0}' in '{1}'.", actionName, GetType().FullName); + AssertActionValidity(action); + return action; + } + + /// + /// Checks the validity of the specified action. + /// + private void AssertActionValidity(MethodInfo action) + { + var actionType = action.DeclaringType; + var parameters = action.GetParameters(); + Assert(parameters.Length is 0 || + (parameters.Length is 1 && parameters[0].ParameterType == typeof(Event)), + "Action '{0}' in '{1}' must either accept no parameters or a single parameter of type 'Event'.", + action.Name, actionType.Name); + + // Check if the action is an 'async' method. + if (action.GetCustomAttribute(typeof(AsyncStateMachineAttribute)) != null) + { + Assert(action.ReturnType == typeof(Task), + "Async action '{0}' in '{1}' must have 'Task' return type.", + action.Name, actionType.Name); + } + else + { + Assert(action.ReturnType == typeof(void), + "Action '{0}' in '{1}' must have 'void' return type.", + action.Name, actionType.Name); + } + } + + /// + /// Invokes user callback when the state machine throws an exception. + /// + /// The exception thrown by the state machine. + /// The handler (outermost) that threw the exception. + /// The event being handled when the exception was thrown. + /// True if the exception was handled, else false if it should continue to get thrown. + private bool OnExceptionHandler(Exception ex, string methodName, Event e) + { + if (ex is ExecutionCanceledException) + { + // Internal exception used during testing. + return false; + } + + Runtime.LogWriter.LogExceptionThrown(Id, CurrentStateName, methodName, ex); + + var outcome = OnException(ex, methodName, e); + if (outcome is OnExceptionOutcome.ThrowException) + { + return false; + } + else if (outcome is OnExceptionOutcome.Halt) + { + CurrentStatus = Status.Halting; + } + + Runtime.LogWriter.LogExceptionHandled(Id, CurrentStateName, methodName, ex); + return true; + } + + /// + /// Invokes user callback when the state machine receives an event that it cannot handle. + /// + /// The exception thrown by the state machine. + /// The unhandled event. + /// True if the state machine should gracefully halt, else false if the exception + /// should continue to get thrown. + private bool OnUnhandledEventExceptionHandler(UnhandledEventException ex, Event e) + { + Runtime.LogWriter.LogExceptionThrown(Id, ex.CurrentStateName, string.Empty, ex); + + var outcome = OnException(ex, string.Empty, e); + if (outcome is OnExceptionOutcome.ThrowException) + { + return false; + } + + CurrentStatus = Status.Halting; + Runtime.LogWriter.LogExceptionHandled(Id, ex.CurrentStateName, string.Empty, ex); + return true; + } + + /// + /// User callback when the state machine throws an exception. By default, + /// the state machine throws the exception causing the runtime to fail. + /// + /// The exception thrown by the state machine. + /// The handler (outermost) that threw the exception. + /// The event being handled when the exception was thrown. + /// The action that the runtime should take. + protected OnExceptionOutcome OnException(Exception ex, string methodName, Event e) + { + var v = ex is UnhandledEventException; + if (!v) + { + return ex is PNonStandardReturnException + ? OnExceptionOutcome.HandledException + : OnExceptionOutcome.ThrowException; + } + + return (ex as UnhandledEventException).UnhandledEvent is PHalt + ? OnExceptionOutcome.Halt + : OnExceptionOutcome.ThrowException; + } + + /// + /// Determines whether the specified object is equal to the current object. + /// + public override bool Equals(object obj) + { + if (obj is StateMachine m && + GetType() == m.GetType()) + { + return Id.Value == m.Id.Value; + } + + return false; + } + + /// + /// Returns the hash code for this instance. + /// + public override int GetHashCode() + { + return Id.Value.GetHashCode(); + } + + /// + /// Enqueues the specified event and its metadata. + /// + internal EnqueueStatus Enqueue(Event e, EventInfo info) + { + if (CurrentStatus is Status.Halted) + { + return EnqueueStatus.Dropped; + } + + return Inbox.Enqueue(e, info); + } + + /// + /// Returns a string that represents the current state machine. + /// + public override string ToString() + { + return Id.Name; + } + + /// + /// The status of the state machine. + /// + private protected enum Status + { + /// + /// The state machine is active. + /// + Active = 0, + + /// + /// The state machine is halting. + /// + Halting, + + /// + /// The state machine is halted. + /// + Halted + } + + /// + /// The type of user callback. + /// + private protected static class UserCallbackType + { + internal const string OnInitialize = nameof(OnInitializeAsync); + internal const string OnEventDequeued = nameof(OnEventDequeuedAsync); + internal const string OnEventHandled = nameof(OnEventHandledAsync); + internal const string OnEventUnhandled = nameof(OnEventUnhandledAsync); + internal const string OnExceptionHandled = nameof(OnExceptionHandledAsync); + internal const string OnHalt = nameof(OnHaltAsync); + } /// /// Raises the specified at the end of the current action. @@ -128,12 +948,13 @@ internal override async Task InitializeAsync(Event initialEvent) /// An Assert is raised if you accidentally try and do two of these operations in a single action. /// /// The event to raise. - protected void RaiseEvent(Event e) + public void RaiseEvent(Event e) { Assert(CurrentStatus is Status.Active, "{0} invoked RaiseEvent while halting.", Id); Assert(e != null, "{0} is raising a null event.", Id); CheckDanglingTransition(); PendingTransition = new Transition(Transition.Type.RaiseEvent, default, e); + throw new PNonStandardReturnException { ReturnKind = NonStandardReturn.Raise }; } /// @@ -155,9 +976,12 @@ protected void RaiseEvent(Event e) /// An Assert is raised if you accidentally try and do two of these operations in a single action. /// /// Type of the state. - protected void RaiseGotoStateEvent() - where S : State => + public void RaiseGotoStateEvent(IPValue payload = null) where S : State + { + gotoPayload = payload; RaiseGotoStateEvent(typeof(S)); + throw new PNonStandardReturnException { ReturnKind = NonStandardReturn.Goto }; + } /// /// Raise a special event that performs a goto state operation at the end of the current action. @@ -187,7 +1011,7 @@ protected void RaiseGotoStateEvent(Type state) } /// - /// Raises a to halt the actor at the end of the current action. + /// Raises a to halt the state machine at the end of the current action. /// /// /// This event is not handled until the action that calls this method returns control back @@ -197,26 +1021,19 @@ protected void RaiseGotoStateEvent(Type state) /// , and . /// An Assert is raised if you accidentally try and do two of these operations in a single action. /// - protected override void RaiseHaltEvent() + protected void RaiseHaltEvent() { - base.RaiseHaltEvent(); + Assert(CurrentStatus is Status.Active, "{0} invoked Halt while halting.", Id); + CurrentStatus = Status.Halting; CheckDanglingTransition(); PendingTransition = new Transition(Transition.Type.Halt, null, default); } - - /// - /// Asynchronous callback that is invoked when the actor finishes handling a dequeued - /// event, unless the handler of the dequeued event raised an event or caused the actor - /// to halt (either normally or due to an exception). Unless this callback raises an - /// event, the actor will either become idle or dequeue the next event from its inbox. - /// - /// The event that was handled. - protected override Task OnEventHandledAsync(Event e) => Task.CompletedTask; + /// /// Handles the specified . /// - private protected override async Task HandleEventAsync(Event e) + private protected async Task HandleEventAsync(Event e) { var currentState = CurrentState; @@ -227,12 +1044,12 @@ private protected override async Task HandleEventAsync(Event e) // If the stack of states is empty then halt or fail the state machine. if (e is HaltEvent) { - // If it is the halt event, then change the actor status to halting. + // If it is the halt event, then change the state machine status to halting. CurrentStatus = Status.Halting; break; } - var currentStateName = NameResolver.GetQualifiedStateName(currentState); + var currentStateName = currentState.GetType().Name; await InvokeUserCallbackAsync(UserCallbackType.OnEventUnhandled, e, currentStateName); if (CurrentStatus is Status.Active) { @@ -252,36 +1069,18 @@ private protected override async Task HandleEventAsync(Event e) } else if (EventHandlerMap.ContainsKey(e.GetType())) { - await HandleEventAsync(e, StateStack.Peek(), EventHandlerMap[e.GetType()]); + await HandleEventAsync(e, currentState, EventHandlerMap[e.GetType()]); } else { - var hasWildCard = TryGetInheritedHandler(typeof(WildCardEvent), out var wildInfo); - if (EventHandlerMap.ContainsKey(typeof(WildCardEvent))) - { - // A non-inherited wildcard handler cannot beat a "specific" event handler if that - // "specific" event handler is also at the top of the stack. - wildInfo = new HandlerInfo(StateStack.Peek(), StateStack.Count, - EventHandlerMap[typeof(WildCardEvent)]); - hasWildCard = true; - } - - var hasSpecific = TryGetInheritedHandler(e.GetType(), out var info); - - if ((hasWildCard && hasSpecific && wildInfo.StackDepth > info.StackDepth) || - (!hasSpecific && hasWildCard)) - { - // Then wild card takes precedence over earlier specific event handlers. - await HandleEventAsync(e, wildInfo.State, wildInfo.Handler); - } - else if (hasSpecific) + if (TryGetHandler(e.GetType(), out EventHandlerDeclaration ehandler)) { // Then specific event is more recent than any wild card events. - await HandleEventAsync(e, info.State, info.Handler); + await HandleEventAsync(e, currentState, ehandler); } - else if (ActionMap.TryGetValue(e.GetType(), out var handler)) + else if (StateMachineActionMap.TryGetValue(e.GetType().Name, out var handler)) { - // Allow StateMachine to have class level OnEventDoActions the same way Actor allows. + // Allow StateMachine to have class level OnEventDoActions. Runtime.NotifyInvokedAction(this, handler.MethodInfo, CurrentStateName, CurrentStateName, e); await InvokeActionAsync(handler, e); } @@ -292,7 +1091,9 @@ private protected override async Task HandleEventAsync(Event e) if (CurrentStatus is Status.Active) { Runtime.LogWriter.LogPopStateUnhandledEvent(Id, CurrentStateName, e); - DoStatePop(); + EventHandlerMap = EmptyEventHandlerMap; + CurrentState = null; + CurrentStateName = string.Empty; continue; } } @@ -302,9 +1103,27 @@ private protected override async Task HandleEventAsync(Event e) } } + private bool TryGetHandler(Type e, out EventHandlerDeclaration o) + { + if (EventHandlerMap.ContainsKey(e)) + { + o = EventHandlerMap[e]; + return true; + } + + if (EventHandlerMap.ContainsKey(typeof(WildCardEvent))) + { + o = EventHandlerMap[typeof(WildCardEvent)]; + return true; + } + + o = null; + return false; + } + private async Task HandleEventAsync(Event e, State declaringState, EventHandlerDeclaration eventHandler) { - var handlingStateName = NameResolver.GetQualifiedStateName(declaringState.GetType()); + var handlingStateName = declaringState.GetType().Name; if (eventHandler is ActionEventHandlerDeclaration actionEventHandler) { var cachedAction = StateMachineActionMap[actionEventHandler.Name]; @@ -330,9 +1149,9 @@ private async Task ExecuteCurrentStateOnEntryAsync(Event e) Runtime.NotifyEnteredState(this); CachedDelegate entryAction = null; - if (StateStack.Peek().EntryAction != null) + if (CurrentState.EntryAction != null) { - entryAction = StateMachineActionMap[StateStack.Peek().EntryAction]; + entryAction = StateMachineActionMap[CurrentState.EntryAction]; } // Invokes the entry action of the new state, if there is one available. @@ -352,9 +1171,9 @@ private async Task ExecuteCurrentStateOnExitAsync(string eventHandlerExitActionN Runtime.NotifyExitedState(this); CachedDelegate exitAction = null; - if (StateStack.Peek().ExitAction != null) + if (CurrentState.ExitAction != null) { - exitAction = StateMachineActionMap[StateStack.Peek().ExitAction]; + exitAction = StateMachineActionMap[CurrentState.ExitAction]; } // Invokes the exit action of the current state, @@ -399,16 +1218,16 @@ private Task ApplyEventHandlerTransitionAsync(Transition transition, Event e) else if (transition.TypeValue is Transition.Type.RaiseEvent) { PendingTransition = default; - Inbox.RaiseEvent(transition.Event, OperationGroupId); + Inbox.RaiseEvent(transition.Event); } else if (transition.TypeValue is Transition.Type.GotoState) { PendingTransition = default; - Inbox.RaiseEvent(new GotoStateEvent(transition.State), OperationGroupId); + Inbox.RaiseEvent(new GotoStateEvent(transition.State)); } else if (transition.TypeValue is Transition.Type.Halt) { - // If it is the halt transition, then change the actor status to halting. + // If it is the halt transition, then change the state machine status to halting. PendingTransition = default; CurrentStatus = Status.Halting; } @@ -457,151 +1276,46 @@ private void CheckDanglingTransition() private async Task GotoStateAsync(Type s, string onExitActionName, Event e) { Runtime.LogWriter.LogGotoState(Id, CurrentStateName, - $"{s.DeclaringType}.{NameResolver.GetStateNameForLogging(s)}"); + $"{s.DeclaringType}.{s.Name}"); // The state machine performs the on exit action of the current state. await ExecuteCurrentStateOnExitAsync(onExitActionName, e); if (CurrentStatus is Status.Active) { - DoStatePop(); - // The state machine transitions to the new state. var nextState = StateInstanceCache[GetType()].First(val => val.GetType().Equals(s)); - DoStatePush(nextState); - - // The state machine performs the on entry action of the new state. - await ExecuteCurrentStateOnEntryAsync(e); - } - } - - /// - /// Performs a push transition to the specified state. - /// - private async Task PushStateAsync(Type s, Event e) - { - - var nextState = StateInstanceCache[GetType()].First(val => val.GetType().Equals(s)); - DoStatePush(nextState); - - // The state machine performs the on entry statements of the new state. - await ExecuteCurrentStateOnEntryAsync(e); - } - - private void PushHandler(State state, Type eventType, EventHandlerDeclaration handler) - { - if (handler.Inheritable) - { - if (!InheritableEventHandlerMap.TryGetValue(eventType, out var stack)) - { - stack = new Stack(); - InheritableEventHandlerMap[eventType] = stack; - } - - stack.Push(new HandlerInfo(state, StateStack.Count, handler)); - } - } - - private bool TryGetInheritedHandler(Type eventType, out HandlerInfo result) - { - if (InheritableEventHandlerMap.TryGetValue(eventType, out var stack) && stack.Count > 0) - { - result = stack.Peek(); - return true; - } + DoStateTransition(nextState); - result = default; - return false; - } - - /// - /// Configures the state transitions of the state machine when a state is pushed into the stack. - /// - private void DoStatePush(State state) - { - EventHandlerMap = state.EventHandlers; // non-inheritable handlers. - - StateStack.Push(state); - CurrentState = state.GetType(); - CurrentStateName = NameResolver.GetQualifiedStateName(CurrentState); - - // Push the inheritable event handlers. - foreach (var eventHandler in state.InheritableEventHandlers) - { - PushHandler(state, eventHandler.Key, eventHandler.Value); + // The state machine performs the on entry action of the new state. + await ExecuteCurrentStateOnEntryAsync(e); } } /// - /// Configures the state transitions of the state machine - /// when a state is popped. + /// Performs a push transition to the specified state. /// - private void DoStatePop() + private async Task PushStateAsync(Type s, Event e) { - var state = StateStack.Pop(); - foreach (var item in InheritableEventHandlerMap) - { - var stack = item.Value; - if (stack != null && stack.Count > 0 && stack.Peek().State == state) - { - stack.Pop(); - } - } - if (StateStack.Count > 0) - { - // re-instate the non-inheritable handlers from previous state. - state = StateStack.Peek(); - CurrentState = state.GetType(); - CurrentStateName = NameResolver.GetQualifiedStateName(CurrentState); - EventHandlerMap = StateStack.Peek().EventHandlers; - } - else - { - EventHandlerMap = EmptyEventHandlerMap; - CurrentState = null; - CurrentStateName = string.Empty; - } + var nextState = StateInstanceCache[GetType()].First(val => val.GetType().Equals(s)); + DoStateTransition(nextState); + + // The state machine performs the on entry statements of the new state. + await ExecuteCurrentStateOnEntryAsync(e); } /// - /// Get the appropriate inherited event handler for the given event. + /// Configures the state transitions of the state machine when a state is pushed into the stack. /// - /// The event we want to handle - /// The HandlerInfo in the state stack - /// True if a handler is found, otherwise false - private bool GetInheritedEventHandler(Event e, ref HandlerInfo info) + private void DoStateTransition(State state) { - var eventType = e.GetType(); - // Wild card only takes precidence if it is higher on the state stack. - var hasWildCard = TryGetInheritedHandler(typeof(WildCardEvent), out var wildInfo); - if (EventHandlerMap.ContainsKey(typeof(WildCardEvent))) - { - // a non-inherited wildcard handler cannot beat a "specific" IgnoreEvent instruction if that - // "specific" instruction is also at the top of the stack. - wildInfo.StackDepth = StateStack.Count; - wildInfo.State = StateStack.Peek(); - wildInfo.Handler = EventHandlerMap[typeof(WildCardEvent)]; - hasWildCard = true; - } - - var hasSpecific = TryGetInheritedHandler(eventType, out info); - - if ((hasSpecific && hasWildCard && wildInfo.StackDepth > info.StackDepth) || - (!hasSpecific && hasWildCard)) - { - info = wildInfo; - return true; - } - - if (hasSpecific) - { - return true; - } - - info = new HandlerInfo(null, 0, null); - return false; + EventHandlerMap = state.EventHandlers; // non-inheritable handlers. + CurrentState = state; + CurrentStateName = CurrentState.GetType().Name; } + + /// /// Checks if the specified event is ignored in the current state. /// @@ -613,13 +1327,7 @@ internal bool IsEventIgnoredInCurrentState(Event e) // because the non-inheritable operation takes precedent. if (EventHandlerMap.ContainsKey(eventType)) { - return false; - } - - var info = new HandlerInfo(null, 0, null); - if (GetInheritedEventHandler(e, ref info)) - { - return info.Handler is IgnoreEventHandlerDeclaration; + return EventHandlerMap[eventType] is IgnoreEventHandlerDeclaration; } return false; @@ -635,15 +1343,8 @@ internal bool IsEventDeferredInCurrentState(Event e) // If a non-inheritable transition is defined, then the event is not deferred. if (EventHandlerMap.ContainsKey(eventType)) { - return false; - } - - var info = new HandlerInfo(null, 0, null); - if (GetInheritedEventHandler(e, ref info)) - { - return info.Handler is DeferEventHandlerDeclaration; + return EventHandlerMap[eventType] is DeferEventHandlerDeclaration; } - return false; } @@ -651,13 +1352,12 @@ internal bool IsEventDeferredInCurrentState(Event e) /// Checks if a default handler is installed in current state. /// internal bool IsDefaultHandlerInstalledInCurrentState() => - EventHandlerMap.ContainsKey(typeof(DefaultEvent)) || - TryGetInheritedHandler(typeof(DefaultEvent), out _); + EventHandlerMap.ContainsKey(typeof(DefaultEvent)); /// /// Returns the hashed state of this state machine. /// - internal override int GetHashedState() + internal int GetHashedState() { unchecked { @@ -667,20 +1367,9 @@ internal override int GetHashedState() hash = (hash * 31) + IsHalted.GetHashCode(); hash = (hash * 31) + Manager.GetCachedState(); - - foreach (var state in StateStack) - { - hash = (hash * 31) + state.GetType().GetHashCode(); - } - + hash = (hash * 31) + Inbox.GetCachedState(); - if (HashedState != 0) - { - // Adds the user-defined hashed state. - hash = (hash * 31) + HashedState; - } - return hash; } } @@ -688,9 +1377,8 @@ internal override int GetHashedState() /// /// Extracts user declarations and setups the event handlers and state transitions. /// - internal override void SetupEventHandlers() + internal void SetupEventHandlers() { - base.SetupEventHandlers(); var stateMachineType = GetType(); // If this type has not already been setup in the ActionCache, then we need to try and grab the ActionCacheLock @@ -698,7 +1386,7 @@ internal override void SetupEventHandlers() var syncObject = ActionCacheLocks.GetOrAdd(stateMachineType, _ => new object()); // Locking this syncObject ensures only one thread enters the initialization code to update - // the ActionCache for this specific Actor type. + // the ActionCache for this specific state machine type. lock (syncObject) { if (ActionCache.ContainsKey(stateMachineType)) @@ -791,17 +1479,6 @@ internal override void SetupEventHandlers() map.Add(state.ExitAction, GetActionWithName(state.ExitAction)); } - foreach (var handler in state.InheritableEventHandlers.Values) - { - if (handler is ActionEventHandlerDeclaration action) - { - if (!map.ContainsKey(action.Name)) - { - map.Add(action.Name, GetActionWithName(action.Name)); - } - } - } - foreach (var handler in state.EventHandlers.Values) { if (handler is GotoStateTransition transition) @@ -812,6 +1489,14 @@ internal override void SetupEventHandlers() map.Add(transition.Lambda, GetActionWithName(transition.Lambda)); } } + + if (handler is ActionEventHandlerDeclaration action) + { + if (!map.ContainsKey(action.Name)) + { + map.Add(action.Name, GetActionWithName(action.Name)); + } + } } } @@ -829,19 +1514,10 @@ internal override void SetupEventHandlers() Assert(initialStates.Count != 0, "{0} must declare a start state.", Id); Assert(initialStates.Count is 1, "{0} can not declare more than one start states.", Id); - DoStatePush(initialStates[0]); + DoStateTransition(initialStates[0]); AssertStateValidity(); } - /// - /// Returns the type of the state at the specified state - /// stack index, if there is one. - /// - internal Type GetStateTypeAtStackIndex(int index) - { - return StateStack.ElementAtOrDefault(index)?.GetType(); - } - /// /// Processes a type, looking for states. /// @@ -858,17 +1534,11 @@ private void ExtractStateTypes(Type type) { StateTypeCache[GetType()].Add(nextType); } - else if (nextType.IsClass && nextType.IsSubclassOf(typeof(StateGroup))) + + /* TODO: figure whether this part is needed */ + if (nextType.BaseType != null) { - // Adds the contents of the group of states to the stack. - foreach (var t in nextType.GetNestedTypes(BindingFlags.Instance | - BindingFlags.NonPublic | BindingFlags.Public | - BindingFlags.DeclaredOnly)) - { - Assert(t.IsSubclassOf(typeof(StateGroup)) || t.IsSubclassOf(typeof(State)), - "'{0}' is neither a group of states nor a state.", t.Name); - stack.Push(t); - } + stack.Push(nextType.BaseType); } } } @@ -883,7 +1553,7 @@ internal HashSet GetAllStates() var allStates = new HashSet(); foreach (var state in StateInstanceCache[GetType()]) { - allStates.Add(NameResolver.GetQualifiedStateName(state.GetType())); + allStates.Add(state.GetType().Name); } return allStates; @@ -910,11 +1580,11 @@ internal HashSet> GetAllStateEventPairs() var pairs = new HashSet>(); foreach (var state in StateInstanceCache[GetType()]) { - foreach (var binding in from b in state.InheritableEventHandlers.Concat(state.EventHandlers) + foreach (var binding in from b in state.EventHandlers where IncludeInCoverage(b.Value) select b) { - pairs.Add(Tuple.Create(NameResolver.GetQualifiedStateName(state.GetType()), binding.Key.FullName)); + pairs.Add(Tuple.Create(state.GetType().Name, binding.Key.FullName)); } } @@ -927,21 +1597,14 @@ where IncludeInCoverage(b.Value) private void AssertStateValidity() { Assert(StateTypeCache[GetType()].Count > 0, "{0} must have one or more states.", Id); - Assert(StateStack.Peek() != null, "{0} must not have a null current state.", Id); + Assert(CurrentState != null, "{0} must not have a null current state.", Id); } - /// - /// Returns the formatted strint to be used with a fair nondeterministic boolean choice. - /// - private protected override string FormatFairRandom(string callerMemberName, string callerFilePath, int callerLineNumber) => - string.Format(CultureInfo.InvariantCulture, "{0}_{1}_{2}_{3}_{4}", - Id.Name, CurrentStateName, callerMemberName, callerFilePath, callerLineNumber.ToString()); - /// /// Wraps the unhandled exception inside an /// exception, and throws it to the user. /// - private protected override void ReportUnhandledException(Exception ex, string actionName) + private protected void ReportUnhandledException(Exception ex, string actionName) { var state = CurrentState is null ? "" : CurrentStateName; Runtime.WrapAndThrowException(ex, "{0} (state '{1}', action '{2}')", Id, state, actionName); @@ -951,15 +1614,12 @@ private protected override void ReportUnhandledException(Exception ex, string ac /// Defines the transition that is the /// result of executing an event handler. Transitions are created by using /// , and . - /// The Transition is processed by the Coyote runtime when + /// The Transition is processed by the ControlledRuntime when /// an event handling method of a StateMachine returns a Transition object. /// This means such a method can only do one such Transition per method call. /// If the method wants to do a conditional transition it can return /// Transition.None to indicate no transition is to be performed. /// - /// - /// See State machines for more information. - /// internal readonly struct Transition { /// @@ -1026,42 +1686,9 @@ public enum Type } } - /// - /// A struct used to track event handlers that are pushed or popped on the StateStack. - /// - private struct HandlerInfo - { - /// - /// The state that provided this EventHandler. - /// - public State State; - - /// - /// Records where this State is in the StateStack. This information is needed to implement WildCardEvent - /// semantics. A specific Handler closest to the top of the stack (higher StackDepth) wins over a - /// WildCardEvent further down the stack (lower StackDepth). - /// - public int StackDepth; - - /// - /// The event handler for a given event Type defined by the State. - /// - public EventHandlerDeclaration Handler; - - public HandlerInfo(State state, int depth, EventHandlerDeclaration handler) - { - State = state; - StackDepth = depth; - Handler = handler; - } - } - /// /// Abstract class representing a state. /// - /// - /// See State machines for more information. - /// public abstract class State { /// @@ -1074,11 +1701,6 @@ public abstract class State /// internal string ExitAction { get; private set; } - /// - /// Map containing all event handler declarations. - /// - internal Dictionary InheritableEventHandlers; - /// /// Map containing all non-inheritable event handler declarations. /// @@ -1102,8 +1724,6 @@ protected State() internal void InitializeState() { IsStart = false; - - InheritableEventHandlers = new Dictionary(); EventHandlers = new Dictionary(); if (GetType().GetCustomAttribute(typeof(OnEntryAttribute), true) is OnEntryAttribute entryAttribute) @@ -1126,7 +1746,6 @@ internal void InitializeState() // Install event handlers. InstallGotoTransitions(handledEvents); - InstallPushTransitions(handledEvents); InstallActionBindings(handledEvents); InstallIgnoreHandlers(handledEvents); InstallDeferHandlers(handledEvents); @@ -1155,105 +1774,6 @@ private void InstallGotoTransitions(HashSet handledEvents) handledEvents.Add(attr.Event); } - - InheritGotoTransitions(GetType().BaseType, handledEvents); - } - - /// - /// Inherits goto event handlers from a base state, if there is one. - /// - private void InheritGotoTransitions(Type baseState, HashSet handledEvents) - { - if (!baseState.IsSubclassOf(typeof(State))) - { - return; - } - - var gotoAttributesInherited = baseState.GetCustomAttributes(typeof(OnEventGotoStateAttribute), false) - as OnEventGotoStateAttribute[]; - - var gotoTransitionsInherited = new Dictionary(); - foreach (var attr in gotoAttributesInherited) - { - if (EventHandlers.ContainsKey(attr.Event)) - { - continue; - } - - CheckEventHandlerAlreadyInherited(attr.Event, baseState, handledEvents); - - if (attr.Action is null) - { - gotoTransitionsInherited.Add(attr.Event, new GotoStateTransition(attr.State)); - } - else - { - gotoTransitionsInherited.Add(attr.Event, new GotoStateTransition(attr.State, attr.Action)); - } - - handledEvents.Add(attr.Event); - } - - foreach (var kvp in gotoTransitionsInherited) - { - EventHandlers.Add(kvp.Key, kvp.Value); - } - - InheritGotoTransitions(baseState.BaseType, handledEvents); - } - - /// - /// Declares push event handlers, if there are any. - /// - private void InstallPushTransitions(HashSet handledEvents) - { - var pushAttributes = GetType().GetCustomAttributes(typeof(OnEventPushStateAttribute), false) - as OnEventPushStateAttribute[]; - - foreach (var attr in pushAttributes) - { - CheckEventHandlerAlreadyDeclared(attr.Event, handledEvents); - - EventHandlers.Add(attr.Event, new PushStateTransition(attr.State)); - handledEvents.Add(attr.Event); - } - - InheritPushTransitions(GetType().BaseType, handledEvents); - } - - /// - /// Inherits push event handlers from a base state, if there is one. - /// - private void InheritPushTransitions(Type baseState, HashSet handledEvents) - { - if (!baseState.IsSubclassOf(typeof(State))) - { - return; - } - - var pushAttributesInherited = baseState.GetCustomAttributes(typeof(OnEventPushStateAttribute), false) - as OnEventPushStateAttribute[]; - - var pushTransitionsInherited = new Dictionary(); - foreach (var attr in pushAttributesInherited) - { - if (EventHandlers.ContainsKey(attr.Event)) - { - continue; - } - - CheckEventHandlerAlreadyInherited(attr.Event, baseState, handledEvents); - - pushTransitionsInherited.Add(attr.Event, new PushStateTransition(attr.State)); - handledEvents.Add(attr.Event); - } - - foreach (var kvp in pushTransitionsInherited) - { - EventHandlers.Add(kvp.Key, kvp.Value); - } - - InheritPushTransitions(baseState.BaseType, handledEvents); } /// @@ -1268,48 +1788,11 @@ private void InstallActionBindings(HashSet handledEvents) { CheckEventHandlerAlreadyDeclared(attr.Event, handledEvents); - InheritableEventHandlers.Add(attr.Event, new ActionEventHandlerDeclaration(attr.Action)); - handledEvents.Add(attr.Event); - } - - InheritActionBindings(GetType().BaseType, handledEvents); - } - - /// - /// Inherits action bindings from a base state, if there is one. - /// - private void InheritActionBindings(Type baseState, HashSet handledEvents) - { - if (!baseState.IsSubclassOf(typeof(State))) - { - return; - } - - var doAttributesInherited = baseState.GetCustomAttributes(typeof(OnEventDoActionAttribute), false) - as OnEventDoActionAttribute[]; - - var actionBindingsInherited = new Dictionary(); - foreach (var attr in doAttributesInherited) - { - if (InheritableEventHandlers.ContainsKey(attr.Event)) - { - continue; - } - - CheckEventHandlerAlreadyInherited(attr.Event, baseState, handledEvents); - - actionBindingsInherited.Add(attr.Event, new ActionEventHandlerDeclaration(attr.Action)); + EventHandlers.Add(attr.Event, new ActionEventHandlerDeclaration(attr.Action)); handledEvents.Add(attr.Event); } - - foreach (var kvp in actionBindingsInherited) - { - InheritableEventHandlers.Add(kvp.Key, kvp.Value); - } - - InheritActionBindings(baseState.BaseType, handledEvents); } - + /// /// Declares ignore event handlers, if there are any. /// @@ -1322,44 +1805,13 @@ private void InstallIgnoreHandlers(HashSet handledEvents) { CheckEventHandlerAlreadyDeclared(e, handledEvents); - InheritableEventHandlers.Add(e, new IgnoreEventHandlerDeclaration()); - ignoredEvents.Add(e); - handledEvents.Add(e); - } - } - - InheritIgnoreHandlers(GetType().BaseType, handledEvents, ignoredEvents); - } - - /// - /// Inherits ignore event handlers from a base state, if there is one. - /// - private void InheritIgnoreHandlers(Type baseState, HashSet handledEvents, HashSet ignoredEvents) - { - if (!baseState.IsSubclassOf(typeof(State))) - { - return; - } - - if (baseState.GetCustomAttribute(typeof(IgnoreEventsAttribute), false) is IgnoreEventsAttribute ignoreEventsAttribute) - { - foreach (var e in ignoreEventsAttribute.Events) - { - if (ignoredEvents.Contains(e)) - { - continue; - } - - CheckEventHandlerAlreadyInherited(e, baseState, handledEvents); - - InheritableEventHandlers.Add(e, new IgnoreEventHandlerDeclaration()); + EventHandlers.Add(e, new IgnoreEventHandlerDeclaration()); ignoredEvents.Add(e); handledEvents.Add(e); } } - - InheritIgnoreHandlers(baseState.BaseType, handledEvents, ignoredEvents); } + /// /// Declares defer event handlers, if there are any. @@ -1372,7 +1824,7 @@ private void InstallDeferHandlers(HashSet handledEvents) foreach (var e in deferEventsAttribute.Events) { CheckEventHandlerAlreadyDeclared(e, handledEvents); - InheritableEventHandlers.Add(e, new DeferEventHandlerDeclaration()); + EventHandlers.Add(e, new DeferEventHandlerDeclaration()); deferredEvents.Add(e); handledEvents.Add(e); } @@ -1399,9 +1851,8 @@ private void InheritDeferHandlers(Type baseState, HashSet handledEvents, H { continue; } - - CheckEventHandlerAlreadyInherited(e, baseState, handledEvents); - InheritableEventHandlers.Add(e, new DeferEventHandlerDeclaration()); + CheckEventHandlerAlreadyDeclared(e, handledEvents); + EventHandlers.Add(e, new DeferEventHandlerDeclaration()); deferredEvents.Add(e); handledEvents.Add(e); } @@ -1421,17 +1872,6 @@ private static void CheckEventHandlerAlreadyDeclared(Type e, HashSet handl } } - /// - /// Checks if an event handler has been already inherited. - /// - private static void CheckEventHandlerAlreadyInherited(Type e, Type baseState, HashSet handledEvents) - { - if (handledEvents.Contains(e)) - { - throw new InvalidOperationException($"inherited multiple handlers for event '{e}' from state '{baseState}'"); - } - } - /// /// Attribute for declaring the state that a state machine transitions upon creation. /// @@ -1529,35 +1969,6 @@ public OnEventGotoStateAttribute(Type eventType, Type stateType, string actionNa } } - /// - /// Attribute for declaring a push state transition when the state machine - /// is in the specified state and dequeues an event of the specified type. - /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] - protected sealed class OnEventPushStateAttribute : Attribute - { - /// - /// The type of the dequeued event. - /// - internal Type Event; - - /// - /// The type of the state. - /// - internal Type State; - - /// - /// Initializes a new instance of the class. - /// - /// The type of the dequeued event. - /// The type of the state. - public OnEventPushStateAttribute(Type eventType, Type stateType) - { - Event = eventType; - State = stateType; - } - } - /// /// Attribute for declaring which action should be invoked when the state machine /// is in the specified state to handle a dequeued event of the specified type. @@ -1629,12 +2040,5 @@ public IgnoreEventsAttribute(params Type[] eventTypes) } } } - - /// - /// Abstract class used for representing a group of related states. - /// - public abstract class StateGroup - { - } } } \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Actors/ActorId.cs b/Src/PChecker/CheckerCore/Runtime/StateMachines/StateMachineId.cs similarity index 54% rename from Src/PChecker/CheckerCore/Actors/ActorId.cs rename to Src/PChecker/CheckerCore/Runtime/StateMachines/StateMachineId.cs index 5c48c481f0..2faeedb972 100644 --- a/Src/PChecker/CheckerCore/Actors/ActorId.cs +++ b/Src/PChecker/CheckerCore/Runtime/StateMachines/StateMachineId.cs @@ -4,20 +4,16 @@ using System; using System.Globalization; using System.Runtime.Serialization; +using PChecker.SystematicTesting; -namespace PChecker.Actors +namespace PChecker.Runtime.StateMachines { /// - /// Unique actor id. + /// Unique state machine id. /// [DataContract] - public sealed class ActorId : IEquatable, IComparable + public sealed class StateMachineId : IEquatable, IComparable { - /// - /// The runtime that executes the actor with this id. - /// - public IActorRuntime Runtime { get; private set; } - /// /// Unique id, when is empty. /// @@ -31,7 +27,7 @@ public sealed class ActorId : IEquatable, IComparable public readonly string NameValue; /// - /// The type of the actor associated with this id. + /// The type of the state machine associated with this id. /// [DataMember] public readonly string Type; @@ -42,44 +38,26 @@ public sealed class ActorId : IEquatable, IComparable [DataMember] public readonly string Name; - /// - /// Generation of the runtime that created this actor id. - /// - [DataMember] - public readonly ulong Generation; - - /// - /// Endpoint. - /// - [DataMember] - public readonly string Endpoint; - /// /// True if is used as the unique id, else false. /// public bool IsNameUsedForHashing => NameValue.Length > 0; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - internal ActorId(Type type, string name, ActorRuntime runtime, bool useNameForHashing = false) + internal StateMachineId(Type type, string name, ControlledRuntime runtime, bool useNameForHashing = false) { - Runtime = runtime; - Endpoint = string.Empty; if (useNameForHashing) { Value = 0; NameValue = name; - Runtime.Assert(!string.IsNullOrEmpty(NameValue), "The actor name cannot be null when used as id."); } else { Value = runtime.GetNextOperationId(); NameValue = string.Empty; - - // Checks for overflow. - Runtime.Assert(Value != ulong.MaxValue, "Detected actor id overflow."); } Type = type.FullName; @@ -94,20 +72,12 @@ internal ActorId(Type type, string name, ActorRuntime runtime, bool useNameForHa } } - /// - /// Bind the actor id. - /// - internal void Bind(ActorRuntime runtime) - { - Runtime = runtime; - } - /// /// Determines whether the specified object is equal to the current object. /// public override bool Equals(object obj) { - if (obj is ActorId id) + if (obj is StateMachineId id) { // Use same machanism for hashing. if (IsNameUsedForHashing != id.IsNameUsedForHashing) @@ -116,8 +86,8 @@ public override bool Equals(object obj) } return IsNameUsedForHashing ? - NameValue.Equals(id.NameValue) && Generation == id.Generation : - Value == id.Value && Generation == id.Generation; + NameValue.Equals(id.NameValue) : + Value == id.Value; } return false; @@ -130,29 +100,28 @@ public override int GetHashCode() { var hash = 17; hash = (hash * 23) + (IsNameUsedForHashing ? NameValue.GetHashCode() : Value.GetHashCode()); - hash = (hash * 23) + Generation.GetHashCode(); return hash; } /// - /// Returns a string that represents the current actor id. + /// Returns a string that represents the current state machine id. /// public override string ToString() => Name; /// - /// Indicates whether the specified is equal - /// to the current . + /// Indicates whether the specified is equal + /// to the current . /// - public bool Equals(ActorId other) => Equals((object)other); + public bool Equals(StateMachineId other) => Equals((object)other); /// - /// Compares the specified with the current - /// for ordering or sorting purposes. + /// Compares the specified with the current + /// for ordering or sorting purposes. /// - public int CompareTo(ActorId other) => string.Compare(Name, other?.Name); + public int CompareTo(StateMachineId other) => string.Compare(Name, other?.Name); - bool IEquatable.Equals(ActorId other) => Equals(other); + bool IEquatable.Equals(StateMachineId other) => Equals(other); - int IComparable.CompareTo(ActorId other) => string.Compare(Name, other?.Name); + int IComparable.CompareTo(StateMachineId other) => string.Compare(Name, other?.Name); } } \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Actors/StateTransitions/GotoStateTransition.cs b/Src/PChecker/CheckerCore/Runtime/StateMachines/StateTransitions/GotoStateTransition.cs similarity index 93% rename from Src/PChecker/CheckerCore/Actors/StateTransitions/GotoStateTransition.cs rename to Src/PChecker/CheckerCore/Runtime/StateMachines/StateTransitions/GotoStateTransition.cs index 2b41829acc..485298c868 100644 --- a/Src/PChecker/CheckerCore/Actors/StateTransitions/GotoStateTransition.cs +++ b/Src/PChecker/CheckerCore/Runtime/StateMachines/StateTransitions/GotoStateTransition.cs @@ -2,9 +2,9 @@ // Licensed under the MIT License. using System; -using PChecker.Actors.Handlers; +using PChecker.Runtime.StateMachines.Handlers; -namespace PChecker.Actors.StateTransitions +namespace PChecker.Runtime.StateMachines.StateTransitions { /// /// Defines a goto state transition. diff --git a/Src/PChecker/CheckerCore/Actors/StateTransitions/PushStateTransition.cs b/Src/PChecker/CheckerCore/Runtime/StateMachines/StateTransitions/PushStateTransition.cs similarity index 87% rename from Src/PChecker/CheckerCore/Actors/StateTransitions/PushStateTransition.cs rename to Src/PChecker/CheckerCore/Runtime/StateMachines/StateTransitions/PushStateTransition.cs index da0f64c517..74ab6131d5 100644 --- a/Src/PChecker/CheckerCore/Actors/StateTransitions/PushStateTransition.cs +++ b/Src/PChecker/CheckerCore/Runtime/StateMachines/StateTransitions/PushStateTransition.cs @@ -2,9 +2,9 @@ // Licensed under the MIT License. using System; -using PChecker.Actors.Handlers; +using PChecker.Runtime.StateMachines.Handlers; -namespace PChecker.Actors.StateTransitions +namespace PChecker.Runtime.StateMachines.StateTransitions { /// /// Defines a push state transition. diff --git a/Src/PChecker/CheckerCore/PRuntime/Exceptions/PFrozenMutationException.cs b/Src/PChecker/CheckerCore/Runtime/Values/Exceptions/PFrozenMutationException.cs similarity index 84% rename from Src/PChecker/CheckerCore/PRuntime/Exceptions/PFrozenMutationException.cs rename to Src/PChecker/CheckerCore/Runtime/Values/Exceptions/PFrozenMutationException.cs index c00dddfeed..ec056c0777 100644 --- a/Src/PChecker/CheckerCore/PRuntime/Exceptions/PFrozenMutationException.cs +++ b/Src/PChecker/CheckerCore/Runtime/Values/Exceptions/PFrozenMutationException.cs @@ -1,6 +1,6 @@ using System; -namespace PChecker.PRuntime.Exceptions +namespace PChecker.Runtime.Values.Exceptions { public class PFrozenMutationException : Exception { diff --git a/Src/PChecker/CheckerCore/Runtime/Values/Exceptions/PInhabitsTypeException.cs b/Src/PChecker/CheckerCore/Runtime/Values/Exceptions/PInhabitsTypeException.cs new file mode 100644 index 0000000000..57fb917d49 --- /dev/null +++ b/Src/PChecker/CheckerCore/Runtime/Values/Exceptions/PInhabitsTypeException.cs @@ -0,0 +1,19 @@ +using System; + +namespace PChecker.Runtime.Values.Exceptions +{ + public class PInhabitsTypeException : Exception + { + public PInhabitsTypeException() + { + } + + public PInhabitsTypeException(string message) : base(message) + { + } + + public PInhabitsTypeException(string message, Exception innerException) : base(message, innerException) + { + } + } +} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/PRuntime/Exceptions/UnknownNamedTupleFieldAccess.cs b/Src/PChecker/CheckerCore/Runtime/Values/Exceptions/UnknownNamedTupleFieldAccess.cs similarity index 92% rename from Src/PChecker/CheckerCore/PRuntime/Exceptions/UnknownNamedTupleFieldAccess.cs rename to Src/PChecker/CheckerCore/Runtime/Values/Exceptions/UnknownNamedTupleFieldAccess.cs index a9982f30b0..4699c488c2 100644 --- a/Src/PChecker/CheckerCore/PRuntime/Exceptions/UnknownNamedTupleFieldAccess.cs +++ b/Src/PChecker/CheckerCore/Runtime/Values/Exceptions/UnknownNamedTupleFieldAccess.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace PChecker.PRuntime.Exceptions +namespace PChecker.Runtime.Values.Exceptions { public class UnknownNamedTupleFieldAccess : Exception { diff --git a/Src/PChecker/CheckerCore/PRuntime/Values/HashHelper.cs b/Src/PChecker/CheckerCore/Runtime/Values/HashHelper.cs similarity index 92% rename from Src/PChecker/CheckerCore/PRuntime/Values/HashHelper.cs rename to Src/PChecker/CheckerCore/Runtime/Values/HashHelper.cs index 36dc42ca46..914109b625 100644 --- a/Src/PChecker/CheckerCore/PRuntime/Values/HashHelper.cs +++ b/Src/PChecker/CheckerCore/Runtime/Values/HashHelper.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; -namespace PChecker.PRuntime.Values +namespace PChecker.Runtime.Values { public class HashHelper { diff --git a/Src/PChecker/CheckerCore/Runtime/Values/IPMutableValue.cs b/Src/PChecker/CheckerCore/Runtime/Values/IPMutableValue.cs new file mode 100644 index 0000000000..1525defdf8 --- /dev/null +++ b/Src/PChecker/CheckerCore/Runtime/Values/IPMutableValue.cs @@ -0,0 +1,7 @@ +namespace PChecker.Runtime.Values +{ + public interface IPMutableValue : IPValue + { + void Freeze(); + } +} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/PRuntime/Values/IPrtValue.cs b/Src/PChecker/CheckerCore/Runtime/Values/IPValue.cs similarity index 76% rename from Src/PChecker/CheckerCore/PRuntime/Values/IPrtValue.cs rename to Src/PChecker/CheckerCore/Runtime/Values/IPValue.cs index 6dbc411363..2df6942ebc 100644 --- a/Src/PChecker/CheckerCore/PRuntime/Values/IPrtValue.cs +++ b/Src/PChecker/CheckerCore/Runtime/Values/IPValue.cs @@ -1,10 +1,10 @@ using System; -namespace PChecker.PRuntime.Values +namespace PChecker.Runtime.Values { - public interface IPrtValue : IEquatable + public interface IPValue : IEquatable { - IPrtValue Clone(); + IPValue Clone(); /// /// Returns a string representation of this Value, such that strings are diff --git a/Src/PChecker/CheckerCore/PRuntime/Values/MutabilityHelper.cs b/Src/PChecker/CheckerCore/Runtime/Values/MutabilityHelper.cs similarity index 61% rename from Src/PChecker/CheckerCore/PRuntime/Values/MutabilityHelper.cs rename to Src/PChecker/CheckerCore/Runtime/Values/MutabilityHelper.cs index 8e7860b537..dd0b1d4700 100644 --- a/Src/PChecker/CheckerCore/PRuntime/Values/MutabilityHelper.cs +++ b/Src/PChecker/CheckerCore/Runtime/Values/MutabilityHelper.cs @@ -1,11 +1,11 @@ -namespace PChecker.PRuntime.Values +namespace PChecker.Runtime.Values { public static class MutabilityHelper { public static void EnsureFrozen(T value) - where T : IPrtValue + where T : IPValue { - if (value is IPrtMutableValue mutable) + if (value is IPMutableValue mutable) { mutable.Freeze(); } diff --git a/Src/PChecker/CheckerCore/PRuntime/Values/PrtBool.cs b/Src/PChecker/CheckerCore/Runtime/Values/PBool.cs similarity index 53% rename from Src/PChecker/CheckerCore/PRuntime/Values/PrtBool.cs rename to Src/PChecker/CheckerCore/Runtime/Values/PBool.cs index 9d80012eee..26cab0ec21 100644 --- a/Src/PChecker/CheckerCore/PRuntime/Values/PrtBool.cs +++ b/Src/PChecker/CheckerCore/Runtime/Values/PBool.cs @@ -1,12 +1,12 @@ using System; using System.Runtime.CompilerServices; -namespace PChecker.PRuntime.Values +namespace PChecker.Runtime.Values { [Serializable] - public readonly struct PrtBool : IPrtValue + public readonly struct PBool : IPValue { - public bool Equals(PrtBool other) + public bool Equals(PBool other) { return value == other.value; } @@ -18,7 +18,7 @@ public override bool Equals(object obj) return false; } - return obj is PrtBool other && Equals(other); + return obj is PBool other && Equals(other); } public override string ToString() @@ -34,99 +34,99 @@ public object ToDict() private readonly bool value; [MethodImpl(MethodImplOptions.AggressiveInlining)] - private PrtBool(bool value) + private PBool(bool value) { this.value = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public IPrtValue Clone() + public IPValue Clone() { return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator bool(in PrtBool val) + public static implicit operator bool(in PBool val) { return val.value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator PrtBool(bool val) + public static implicit operator PBool(bool val) { - return new PrtBool(val); + return new PBool(val); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator true(in PrtBool pValue) + public static bool operator true(in PBool pValue) { return pValue; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator false(in PrtBool pValue) + public static bool operator false(in PBool pValue) { return !pValue; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator !(in PrtBool pValue) + public static PBool operator !(in PBool pValue) { - return new PrtBool(!pValue.value); + return new PBool(!pValue.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator &(in PrtBool pValue1, in PrtBool pValue2) + public static PBool operator &(in PBool pValue1, in PBool pValue2) { - return new PrtBool(pValue1.value && pValue2.value); + return new PBool(pValue1.value && pValue2.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static PrtBool operator |(in PrtBool pValue1, in PrtBool pValue2) + public static PBool operator |(in PBool pValue1, in PBool pValue2) { - return new PrtBool(pValue1.value || pValue2.value); + return new PBool(pValue1.value || pValue2.value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(in PrtBool pValue1, in PrtBool pValue2) + public static bool operator ==(in PBool pValue1, in PBool pValue2) { return Equals(pValue1, pValue2); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(in PrtBool pValue1, in PrtBool pValue2) + public static bool operator !=(in PBool pValue1, in PBool pValue2) { return !Equals(pValue1, pValue2); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(in PrtBool pValue1, in IPrtValue pValue2) + public static bool operator ==(in PBool pValue1, in IPValue pValue2) { - return pValue2 is PrtBool prtBool && pValue1.value == prtBool.value; + return pValue2 is PBool pBool && pValue1.value == pBool.value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(in PrtBool pValue1, in IPrtValue pValue2) + public static bool operator !=(in PBool pValue1, in IPValue pValue2) { - return pValue2 is PrtBool prtBool && pValue1.value != prtBool.value; + return pValue2 is PBool pBool && pValue1.value != pBool.value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(in IPrtValue pValue1, in PrtBool pValue2) + public static bool operator ==(in IPValue pValue1, in PBool pValue2) { - return pValue1 is PrtBool prtBool && pValue2.value == prtBool.value; + return pValue1 is PBool pBool && pValue2.value == pBool.value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(in IPrtValue pValue1, in PrtBool pValue2) + public static bool operator !=(in IPValue pValue1, in PBool pValue2) { - return pValue1 is PrtBool prtBool && pValue2.value != prtBool.value; + return pValue1 is PBool pBool && pValue2.value != pBool.value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(IPrtValue obj) + public bool Equals(IPValue obj) { - return obj is PrtBool other && value == other.value; + return obj is PBool other && value == other.value; } public override int GetHashCode() diff --git a/Src/PChecker/CheckerCore/PRuntime/Values/PrtEnum.cs b/Src/PChecker/CheckerCore/Runtime/Values/PEnum.cs similarity index 73% rename from Src/PChecker/CheckerCore/PRuntime/Values/PrtEnum.cs rename to Src/PChecker/CheckerCore/Runtime/Values/PEnum.cs index b73a11dd23..1e0117a463 100644 --- a/Src/PChecker/CheckerCore/PRuntime/Values/PrtEnum.cs +++ b/Src/PChecker/CheckerCore/Runtime/Values/PEnum.cs @@ -1,13 +1,13 @@ using System.Collections.Generic; using System.Linq; -namespace PChecker.PRuntime.Values +namespace PChecker.Runtime.Values { - public class PrtEnum + public class PEnum { - private static readonly Dictionary enumElements = new Dictionary(); + private static readonly Dictionary enumElements = new Dictionary(); - public static PrtInt Get(string name) + public static PInt Get(string name) { return enumElements[name]; } diff --git a/Src/PChecker/CheckerCore/Runtime/Values/PFloat.cs b/Src/PChecker/CheckerCore/Runtime/Values/PFloat.cs new file mode 100644 index 0000000000..6fbbaf406a --- /dev/null +++ b/Src/PChecker/CheckerCore/Runtime/Values/PFloat.cs @@ -0,0 +1,147 @@ +using System; +using System.Runtime.CompilerServices; + +namespace PChecker.Runtime.Values +{ + [Serializable] + public readonly struct PFloat : IPValue + { + private readonly double value; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public PFloat(double value) + { + this.value = value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public IPValue Clone() + { + return this; + } + + public override string ToString() + { + return value.ToString(); + } + + public object ToDict() + { + return value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(IPValue other) + { + return other is PFloat f && value == f.value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override bool Equals(object val) + { + return val is PFloat other && Equals(value, other.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() + { + return value.GetHashCode(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator double(in PFloat val) + { + return val.value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PFloat(float val) + { + return new PFloat(val); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PFloat(double val) + { + return new PFloat(val); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PFloat(PInt val) + { + return new PFloat(val); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PFloat operator +(in PFloat pFloat1, in PFloat pFloat2) + { + return new PFloat(pFloat1.value + pFloat2.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PFloat operator -(in PFloat pFloat1, in PFloat pFloat2) + { + return new PFloat(pFloat1.value - pFloat2.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PFloat operator *(in PFloat pFloat1, in PFloat pFloat2) + { + return new PFloat(pFloat1.value * pFloat2.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PFloat operator /(in PFloat pFloat1, in PFloat pFloat2) + { + return new PFloat(pFloat1.value / pFloat2.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator <(in PFloat pFloat1, in PFloat pFloat2) + { + return pFloat1.value < pFloat2.value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator >(in PFloat pFloat1, in PFloat pFloat2) + { + return pFloat1.value > pFloat2.value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator <=(in PFloat pFloat1, in PFloat pFloat2) + { + return pFloat1.value <= pFloat2.value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator >=(in PFloat pFloat1, in PFloat pFloat2) + { + return pFloat1.value >= pFloat2.value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator ==(in PFloat pFloat1, in PFloat pFloat2) + { + return Equals(pFloat1.value, pFloat2.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator !=(in PFloat pFloat1, in PFloat pFloat2) + { + return Equals(pFloat1.value, pFloat2.value) == false; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PFloat operator +(in PFloat pFloat) + { + return new PFloat(+pFloat.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PFloat operator -(in PFloat pFloat) + { + return new PFloat(-pFloat.value); + } + } +} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Runtime/Values/PInt.cs b/Src/PChecker/CheckerCore/Runtime/Values/PInt.cs new file mode 100644 index 0000000000..9094c2d37b --- /dev/null +++ b/Src/PChecker/CheckerCore/Runtime/Values/PInt.cs @@ -0,0 +1,185 @@ +using System; +using System.Runtime.CompilerServices; + +namespace PChecker.Runtime.Values +{ + [Serializable] + public readonly struct PInt : IPValue + { + private readonly long value; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public PInt(long value) + { + this.value = value; + } + + public bool Equals(IPValue other) + { + return other is PInt i && value == i.value; + } + + public IPValue Clone() + { + return this; + } + + public override bool Equals(object val) + { + return val is PInt other && Equals(value, other.value); + } + + public override int GetHashCode() + { + return value.GetHashCode(); + } + + public override string ToString() + { + return value.ToString(); + } + + public object ToDict() + { + return value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PInt(byte val) + { + return new PInt(val); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PInt(short val) + { + return new PInt(val); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PInt(int val) + { + return new PInt(val); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PInt(long val) + { + return new PInt(val); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PInt(in PFloat val) + { + return new PInt((long)val); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator int(in PInt val) + { + return (int)val.value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator long(in PInt val) + { + return val.value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PInt operator +(in PInt pInt1, in PInt pInt2) + { + return new PInt(pInt1.value + pInt2.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PInt operator -(in PInt pInt1, in PInt pInt2) + { + return new PInt(pInt1.value - pInt2.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PInt operator *(in PInt pInt1, in PInt pInt2) + { + return new PInt(pInt1.value * pInt2.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PInt operator /(in PInt pInt1, in PInt pInt2) + { + return new PInt(pInt1.value / pInt2.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator <(in PInt pInt1, in PInt pInt2) + { + return pInt1.value < pInt2.value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator >(in PInt pInt1, in PInt pInt2) + { + return pInt1.value > pInt2.value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator <=(in PInt pInt1, in PInt pInt2) + { + return pInt1.value <= pInt2.value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator >=(in PInt pInt1, in PInt pInt2) + { + return pInt1.value >= pInt2.value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator ==(in PInt pInt1, in PInt pInt2) + { + return Equals(pInt1.value, pInt2.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator ==(in IPValue pInt1, in PInt pInt2) + { + return pInt1 is PInt int1 && Equals(int1.value, pInt2.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator !=(in IPValue pInt1, in PInt pInt2) + { + return pInt1 is PInt int1 && !Equals(int1.value, pInt2.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator ==(in PInt pInt1, in IPValue pInt2) + { + return pInt2 is PInt int2 && Equals(pInt1.value, int2.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator !=(in PInt pInt1, in IPValue pInt2) + { + return pInt2 is PInt int2 && !Equals(pInt1.value, int2.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator !=(in PInt pInt1, in PInt pInt2) + { + return Equals(pInt1.value, pInt2.value) == false; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PInt operator +(in PInt pInt) + { + return new PInt(+pInt.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PInt operator -(in PInt pInt) + { + return new PInt(-pInt.value); + } + } +} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/PRuntime/Values/PMachineValue.cs b/Src/PChecker/CheckerCore/Runtime/Values/PMachineValue.cs similarity index 69% rename from Src/PChecker/CheckerCore/PRuntime/Values/PMachineValue.cs rename to Src/PChecker/CheckerCore/Runtime/Values/PMachineValue.cs index 16c758c4d6..abc6c508cf 100644 --- a/Src/PChecker/CheckerCore/PRuntime/Values/PMachineValue.cs +++ b/Src/PChecker/CheckerCore/Runtime/Values/PMachineValue.cs @@ -1,19 +1,19 @@ using System.Collections.Generic; using System.Linq; -using PChecker.Actors; +using PChecker.Runtime.StateMachines; -namespace PChecker.PRuntime.Values +namespace PChecker.Runtime.Values { public class I_Main : PMachineValue { - public I_Main(ActorId machine, List permissions) : base(machine, permissions) + public I_Main(StateMachineId machine, List permissions) : base(machine, permissions) { } } - public class PMachineValue : IPrtValue + public class PMachineValue : IPValue { - public PMachineValue(ActorId machine, List permissions) + public PMachineValue(StateMachineId machine, List permissions) { Id = machine; Permissions = permissions.ToList(); @@ -25,10 +25,10 @@ public PMachineValue(PMachineValue mValue) Permissions = mValue.Permissions.ToList(); } - public ActorId Id { get; } + public StateMachineId Id { get; } public List Permissions { get; } - public bool Equals(IPrtValue other) + public bool Equals(IPValue other) { return other is PMachineValue machine && Equals(Id, machine.Id); } @@ -38,7 +38,7 @@ public override int GetHashCode() return Id.GetHashCode(); } - public IPrtValue Clone() + public IPValue Clone() { return new PMachineValue(Id, new List(Permissions)); } diff --git a/Src/PChecker/CheckerCore/PRuntime/Values/PrtMap.cs b/Src/PChecker/CheckerCore/Runtime/Values/PMap.cs similarity index 74% rename from Src/PChecker/CheckerCore/PRuntime/Values/PrtMap.cs rename to Src/PChecker/CheckerCore/Runtime/Values/PMap.cs index dff333d165..2ef23a816f 100644 --- a/Src/PChecker/CheckerCore/PRuntime/Values/PrtMap.cs +++ b/Src/PChecker/CheckerCore/Runtime/Values/PMap.cs @@ -2,24 +2,24 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using PChecker.PRuntime.Exceptions; +using PChecker.Runtime.Values.Exceptions; -namespace PChecker.PRuntime.Values +namespace PChecker.Runtime.Values { - public sealed class PrtMap : IPrtMutableValue, IDictionary + public sealed class PMap : IPMutableValue, IDictionary { - private readonly IDictionary map = new Dictionary(); + private readonly IDictionary map = new Dictionary(); private int hashCode; private bool isDirty; private bool isFrozen; - public PrtMap() + public PMap() { hashCode = ComputeHashCode(); } - public PrtMap(IDictionary map) + public PMap(IDictionary map) { this.map = map; hashCode = ComputeHashCode(); @@ -39,7 +39,7 @@ private bool IsDirty } } - public IEnumerator> GetEnumerator() + public IEnumerator> GetEnumerator() { return map.GetEnumerator(); } @@ -49,7 +49,7 @@ IEnumerator IEnumerable.GetEnumerator() return GetEnumerator(); } - public void Add(KeyValuePair item) + public void Add(KeyValuePair item) { MutabilityHelper.EnsureFrozen(item.Key); map.Add(item.Key?.Clone(), item.Value?.Clone()); @@ -62,12 +62,12 @@ public void Clear() IsDirty = true; } - public bool Contains(KeyValuePair item) + public bool Contains(KeyValuePair item) { return map.Contains(item); } - public void CopyTo(KeyValuePair[] array, int arrayIndex) + public void CopyTo(KeyValuePair[] array, int arrayIndex) { foreach (var kv in map) { @@ -75,7 +75,7 @@ public void CopyTo(KeyValuePair[] array, int arrayIndex) } } - public bool Remove(KeyValuePair item) + public bool Remove(KeyValuePair item) { var removed = map.Remove(item.Key); IsDirty = true; @@ -85,31 +85,31 @@ public bool Remove(KeyValuePair item) public int Count => map.Count; public bool IsReadOnly => false; - public void Add(IPrtValue key, IPrtValue value) + public void Add(IPValue key, IPValue value) { MutabilityHelper.EnsureFrozen(key); map.Add(key?.Clone(), value?.Clone()); IsDirty = true; } - public bool ContainsKey(IPrtValue key) + public bool ContainsKey(IPValue key) { return map.ContainsKey(key); } - public bool Remove(IPrtValue key) + public bool Remove(IPValue key) { var removed = map.Remove(key); IsDirty = true; return removed; } - public bool TryGetValue(IPrtValue key, out IPrtValue value) + public bool TryGetValue(IPValue key, out IPValue value) { return map.TryGetValue(key, out value); } - public IPrtValue this[IPrtValue key] + public IPValue this[IPValue key] { get => map[key]; set @@ -120,20 +120,20 @@ public IPrtValue this[IPrtValue key] } } - public ICollection Keys => map.Keys; - public ICollection Values => map.Values; + public ICollection Keys => map.Keys; + public ICollection Values => map.Values; - public bool Equals(IPrtValue other) + public bool Equals(IPValue other) { - return other is PrtMap otherMap + return other is PMap otherMap && !map.Keys.Except(otherMap.map.Keys).Any() && !otherMap.map.Keys.Except(map.Keys).Any() - && map.All(kv => PrtValues.SafeEquals(otherMap.map[kv.Key], kv.Value)); + && map.All(kv => PValues.SafeEquals(otherMap.map[kv.Key], kv.Value)); } - public IPrtValue Clone() + public IPValue Clone() { - return new PrtMap(map.ToDictionary( + return new PMap(map.ToDictionary( kv => kv.Key?.Clone(), kv => kv.Value?.Clone())); } @@ -148,14 +148,14 @@ public void Freeze() isFrozen = true; } - public PrtSeq CloneKeys() + public PSeq CloneKeys() { - return new PrtSeq(map.Keys.Select(v => v.Clone())); + return new PSeq(map.Keys.Select(v => v.Clone())); } - public PrtSeq CloneValues() + public PSeq CloneValues() { - return new PrtSeq(map.Values.Select(v => v.Clone())); + return new PSeq(map.Values.Select(v => v.Clone())); } public override int GetHashCode() diff --git a/Src/PChecker/CheckerCore/PRuntime/Values/PrtSeq.cs b/Src/PChecker/CheckerCore/Runtime/Values/PSeq.cs similarity index 80% rename from Src/PChecker/CheckerCore/PRuntime/Values/PrtSeq.cs rename to Src/PChecker/CheckerCore/Runtime/Values/PSeq.cs index 943f9b9994..4590794175 100644 --- a/Src/PChecker/CheckerCore/PRuntime/Values/PrtSeq.cs +++ b/Src/PChecker/CheckerCore/Runtime/Values/PSeq.cs @@ -2,24 +2,24 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using PChecker.PRuntime.Exceptions; +using PChecker.Runtime.Values.Exceptions; -namespace PChecker.PRuntime.Values +namespace PChecker.Runtime.Values { - public sealed class PrtSeq : IPrtMutableValue, IReadOnlyList + public sealed class PSeq : IPMutableValue, IReadOnlyList { - private readonly List values = new List(); + private readonly List values = new List(); private int hashCode; private bool isDirty; private bool isFrozen; - public PrtSeq() + public PSeq() { hashCode = ComputeHashCode(); } - public PrtSeq(IEnumerable values) + public PSeq(IEnumerable values) { this.values = values.ToList(); hashCode = ComputeHashCode(); @@ -49,17 +49,17 @@ public void Freeze() isFrozen = true; } - public IPrtValue Clone() + public IPValue Clone() { - return new PrtSeq(values.Select(item => item?.Clone())); + return new PSeq(values.Select(item => item?.Clone())); } - public bool Equals(IPrtValue other) + public bool Equals(IPValue other) { - return other is PrtSeq otherValue && Equals(otherValue); + return other is PSeq otherValue && Equals(otherValue); } - public IEnumerator GetEnumerator() + public IEnumerator GetEnumerator() { return values.GetEnumerator(); } @@ -71,7 +71,7 @@ IEnumerator IEnumerable.GetEnumerator() public int Count => values.Count; - public IPrtValue this[int index] + public IPValue this[int index] { get => values[index]; set @@ -90,13 +90,13 @@ private int ComputeHashCode() return HashHelper.ComputeHash(values); } - public void Add(IPrtValue item) + public void Add(IPValue item) { IsDirty = true; values.Add(item?.Clone()); } - public void Insert(int index, IPrtValue item) + public void Insert(int index, IPValue item) { IsDirty = true; values.Insert(index, item?.Clone()); @@ -108,12 +108,12 @@ public void RemoveAt(int index) values.RemoveAt(index); } - public bool Contains(IPrtValue item) + public bool Contains(IPValue item) { return values.Contains(item); } - private bool Equals(PrtSeq other) + private bool Equals(PSeq other) { return other != null && values.SequenceEqual(other.values); } diff --git a/Src/PChecker/CheckerCore/PRuntime/Values/PrtSet.cs b/Src/PChecker/CheckerCore/Runtime/Values/PSet.cs similarity index 72% rename from Src/PChecker/CheckerCore/PRuntime/Values/PrtSet.cs rename to Src/PChecker/CheckerCore/Runtime/Values/PSet.cs index 474dc47c4a..806fece412 100644 --- a/Src/PChecker/CheckerCore/PRuntime/Values/PrtSet.cs +++ b/Src/PChecker/CheckerCore/Runtime/Values/PSet.cs @@ -3,24 +3,26 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using PChecker.PRuntime.Exceptions; +using PChecker.Runtime.Values.Exceptions; -namespace PChecker.PRuntime.Values +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace PChecker.Runtime.Values { - public sealed class PrtSet : IPrtMutableValue, IReadOnlyList, ICollection + public sealed class PSet : IPMutableValue, IReadOnlyList, ICollection { - private readonly ISet set = new HashSet(); + private readonly ISet set = new HashSet(); private int hashCode; private bool isDirty; private bool isFrozen; - public PrtSet() + public PSet() { hashCode = ComputeHashCode(); } - public PrtSet(ISet set) + public PSet(ISet set) { this.set = set; hashCode = ComputeHashCode(); @@ -50,7 +52,7 @@ public override int GetHashCode() return hashCode; } - public IEnumerator GetEnumerator() + public IEnumerator GetEnumerator() { return set.GetEnumerator(); } @@ -60,7 +62,7 @@ IEnumerator IEnumerable.GetEnumerator() return GetEnumerator(); } - public bool Add(IPrtValue item) + public bool Add(IPValue item) { MutabilityHelper.EnsureFrozen(item); IsDirty = true; @@ -73,12 +75,12 @@ public void Clear() IsDirty = true; } - public bool Contains(IPrtValue item) + public bool Contains(IPValue item) { return set.Contains(item); } - public bool Remove(IPrtValue item) + public bool Remove(IPValue item) { var removed = set.Remove(item); IsDirty = true; @@ -88,15 +90,15 @@ public bool Remove(IPrtValue item) public int Count => set.Count; public bool IsReadOnly => false; - public bool Equals(IPrtValue other) + public bool Equals(IPValue other) { - return other is PrtSet otherSet + return other is PSet otherSet && set.SetEquals(otherSet.set); } - public IPrtValue Clone() + public IPValue Clone() { - var clone = new PrtSet(new HashSet()); + var clone = new PSet(new HashSet()); foreach (var item in set) clone.Add(item.Clone()); return clone; } @@ -154,67 +156,67 @@ public object ToDict() return set.Select(value => value == null ? null : value.ToDict()).ToList(); } - public IPrtValue this[int index] + public IPValue this[int index] { get => set.ElementAt(index); set => throw new Exception("Setting set elements using indexing is not allowed!"); } - public void UnionWith(IEnumerable other) + public void UnionWith(IEnumerable other) { set.UnionWith(other.Select(i => i.Clone())); } - public void IntersectWith(IEnumerable other) + public void IntersectWith(IEnumerable other) { set.IntersectWith(other); } - public void ExceptWith(IEnumerable other) + public void ExceptWith(IEnumerable other) { set.ExceptWith(other); } - public void SymmetricExceptWith(IEnumerable other) + public void SymmetricExceptWith(IEnumerable other) { set.SymmetricExceptWith(other); } - public bool IsSubsetOf(IEnumerable other) + public bool IsSubsetOf(IEnumerable other) { return set.IsSubsetOf(other); } - public bool IsSupersetOf(IEnumerable other) + public bool IsSupersetOf(IEnumerable other) { return set.IsSupersetOf(other); } - public bool IsProperSupersetOf(IEnumerable other) + public bool IsProperSupersetOf(IEnumerable other) { return set.IsProperSupersetOf(other); } - public bool IsProperSubsetOf(IEnumerable other) + public bool IsProperSubsetOf(IEnumerable other) { return set.IsProperSubsetOf(other); } - public bool Overlaps(IEnumerable other) + public bool Overlaps(IEnumerable other) { return set.Overlaps(other); } - public bool SetEquals(IEnumerable other) + public bool SetEquals(IEnumerable other) { return set.SetEquals(other); } - void ICollection.Add(IPrtValue item) + void ICollection.Add(IPValue item) { set.Add(item); } - public void CopyTo(IPrtValue[] array, int arrayIndex) + public void CopyTo(IPValue[] array, int arrayIndex) { set.CopyTo(array, arrayIndex); } diff --git a/Src/PChecker/CheckerCore/Runtime/Values/PString.cs b/Src/PChecker/CheckerCore/Runtime/Values/PString.cs new file mode 100644 index 0000000000..5179961c36 --- /dev/null +++ b/Src/PChecker/CheckerCore/Runtime/Values/PString.cs @@ -0,0 +1,197 @@ +using System; +using System.Runtime.CompilerServices; + +namespace PChecker.Runtime.Values +{ + [Serializable] + public readonly struct PString : IPValue + { + public bool Equals(PString other) + { + return string.Equals(value, other.value); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) + { + return false; + } + + return obj is PString other && Equals(other); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public IPValue Clone() + { + return this; + } + + private readonly string value; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PString(string val) + { + return new PString(val); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator string(PString val) + { + return val.value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private PString(string value) + { + this.value = value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PString operator +(in PString pString1, in PString pString2) + { + return new PString(pString1.value + pString2.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(in PString pValue1, in PString pValue2) + { + return Equals(pValue1, pValue2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(in PString pValue1, in PString pValue2) + { + return !Equals(pValue1, pValue2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(in PString pValue1, in IPValue pValue2) + { + return pValue2 is PString pString && string.Equals(pValue1.value, pString.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(in PString pValue1, in IPValue pValue2) + { + return pValue2 is PString pString && !string.Equals(pValue1.value, pString.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(in IPValue pValue1, in PString pValue2) + { + return pValue1 is PString pString && string.Equals(pValue2.value, pString.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(in IPValue pValue1, in PString pValue2) + { + return pValue1 is PString pString && !string.Equals(pValue2.value, pString.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator <(in PString pString1, in PString pString2) + { + return string.Compare(pString1.value, pString2.value) == -1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator <(in IPValue pValue1, in PString pValue2) + { + return pValue1 is PString pString && string.Compare(pString.value, pValue2.value) == -1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator <(in PString pValue1, in IPValue pValue2) + { + return pValue2 is PString pString && string.Compare(pString.value, pValue1.value) == -1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator >(in PString pString1, in PString pString2) + { + return string.Compare(pString1.value, pString2.value) == 1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator >(in IPValue pValue1, in PString pValue2) + { + return pValue1 is PString pString && string.Compare(pString.value, pValue2.value) == 1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator >(in PString pValue1, in IPValue pValue2) + { + return pValue2 is PString pString && string.Compare(pString.value, pValue1.value) == 1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator <=(in PString pString1, in PString pString2) + { + return string.Compare(pString1.value, pString2.value) != 1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator <=(in IPValue pValue1, in PString pValue2) + { + return pValue1 is PString pString && string.Compare(pString.value, pValue2.value) != 1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator <=(in PString pValue1, in IPValue pValue2) + { + return pValue2 is PString pString && string.Compare(pString.value, pValue1.value) != 1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator >=(in PString pString1, in PString pString2) + { + return string.Compare(pString1.value, pString2.value) != -1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator >=(in IPValue pValue1, in PString pValue2) + { + return pValue1 is PString pString && string.Compare(pString.value, pValue2.value) != -1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static PBool operator >=(in PString pValue1, in IPValue pValue2) + { + return pValue2 is PString pString && string.Compare(pString.value, pValue1.value) != -1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(IPValue obj) + { + return obj is PString other && string.Equals(value, other.value); + } + + public override int GetHashCode() + { + return value.GetHashCode(); + } + + public override string ToString() + { + return value; + } + + /// + /// Like ToString, but emits a representation of a string literal, surrounded by double-quotes, + /// and where all interior double-quotes are escaped. + /// + /// + public string ToEscapedString() + { + var v = value ?? ""; + return $"\"{v.Replace("\"", "\\\"")}\""; + } + + + public object ToDict() + { + return ToString(); + } + } +} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/PRuntime/Values/PrtTuple.cs b/Src/PChecker/CheckerCore/Runtime/Values/PTuple.cs similarity index 79% rename from Src/PChecker/CheckerCore/PRuntime/Values/PrtTuple.cs rename to Src/PChecker/CheckerCore/Runtime/Values/PTuple.cs index a43d53c138..21edb638b9 100644 --- a/Src/PChecker/CheckerCore/PRuntime/Values/PrtTuple.cs +++ b/Src/PChecker/CheckerCore/Runtime/Values/PTuple.cs @@ -1,23 +1,23 @@ using System; using System.Collections.Generic; using System.Linq; -using PChecker.PRuntime.Exceptions; +using PChecker.Runtime.Values.Exceptions; -namespace PChecker.PRuntime.Values +namespace PChecker.Runtime.Values { [Serializable] - public class PrtTuple : IPrtValue + public class PTuple : IPValue { - public readonly List fieldValues; + public readonly List fieldValues; - public PrtTuple() + public PTuple() { - fieldValues = new List(); + fieldValues = new List(); } - public PrtTuple(params IPrtValue[] elems) + public PTuple(params IPValue[] elems) { - fieldValues = new List(); + fieldValues = new List(); if (elems == null || elems.Length == 1) { fieldValues.Add(elems?.First()); @@ -31,15 +31,15 @@ public PrtTuple(params IPrtValue[] elems) } } - public IPrtValue this[int key] + public IPValue this[int key] { get => fieldValues[key]; set => fieldValues[key] = value; } - public IPrtValue Clone() + public IPValue Clone() { - var clone = new PrtTuple(); + var clone = new PTuple(); foreach (var val in fieldValues) { clone.fieldValues.Add(val?.Clone()); @@ -48,14 +48,14 @@ public IPrtValue Clone() return clone; } - public bool Equals(IPrtValue val) + public bool Equals(IPValue val) { - if (val is PrtNamedTuple) + if (val is PNamedTuple) { return false; } - var tupValue = val as PrtTuple; + var tupValue = val as PTuple; if (tupValue == null) { return false; @@ -68,7 +68,7 @@ public bool Equals(IPrtValue val) for (var i = 0; i < fieldValues.Count; i++) { - if (!PrtValues.SafeEquals(fieldValues[i], tupValue.fieldValues[i])) + if (!PValues.SafeEquals(fieldValues[i], tupValue.fieldValues[i])) { return false; } @@ -77,7 +77,7 @@ public bool Equals(IPrtValue val) return true; } - public void Update(int index, IPrtValue val) + public void Update(int index, IPValue val) { fieldValues[index] = val; } @@ -115,23 +115,23 @@ public object ToDict() } [Serializable] - public class PrtNamedTuple : IPrtValue + public class PNamedTuple : IPValue { - public readonly List fieldValues; + public readonly List fieldValues; public List fieldNames; - public PrtNamedTuple() + public PNamedTuple() { fieldNames = new List(); - fieldValues = new List(); + fieldValues = new List(); } - public PrtNamedTuple(string[] _fieldNames, params IPrtValue[] _fieldValues) + public PNamedTuple(string[] _fieldNames, params IPValue[] _fieldValues) { fieldNames = _fieldNames.ToList(); if (_fieldValues == null || _fieldValues.Length == 1) { - fieldValues = new List(); + fieldValues = new List(); fieldValues.Add(_fieldValues?.First()); } @@ -141,7 +141,7 @@ public PrtNamedTuple(string[] _fieldNames, params IPrtValue[] _fieldValues) } } - public IPrtValue this[string name] + public IPValue this[string name] { get { @@ -163,9 +163,9 @@ public IPrtValue this[string name] } } - public IPrtValue Clone() + public IPValue Clone() { - var clone = new PrtNamedTuple(); + var clone = new PNamedTuple(); foreach (var name in fieldNames) { clone.fieldNames.Add(name); @@ -179,9 +179,9 @@ public IPrtValue Clone() return clone; } - public bool Equals(IPrtValue val) + public bool Equals(IPValue val) { - if (!(val is PrtNamedTuple tup)) + if (!(val is PNamedTuple tup)) { return false; } @@ -198,7 +198,7 @@ public bool Equals(IPrtValue val) return false; } - if (!PrtValues.SafeEquals(fieldValues[i], tup.fieldValues[i])) + if (!PValues.SafeEquals(fieldValues[i], tup.fieldValues[i])) { return false; } diff --git a/Src/PChecker/CheckerCore/Runtime/Values/PValues.cs b/Src/PChecker/CheckerCore/Runtime/Values/PValues.cs new file mode 100644 index 0000000000..c38cfe9e07 --- /dev/null +++ b/Src/PChecker/CheckerCore/Runtime/Values/PValues.cs @@ -0,0 +1,54 @@ +namespace PChecker.Runtime.Values +{ + public static class PValues + { + public static PBool Box(bool value) + { + return value; + } + + public static PInt Box(long value) + { + return new PInt(value); + } + + public static PInt Box(int value) + { + return new PInt(value); + } + + public static PInt Box(short value) + { + return new PInt(value); + } + + public static PInt Box(byte value) + { + return new PInt(value); + } + + public static PFloat Box(double value) + { + return new PFloat(value); + } + + public static PFloat Box(float value) + { + return new PFloat(value); + } + + public static PBool SafeEquals(IPValue val1, IPValue val2) + { + return ReferenceEquals(val1, val2) || val1 != null && val1.Equals(val2); + } + + public static IPValue PCastValue(IPValue value, PType type) + { + //todo: Needs to be fixed for better error message + /*if (!PInhabitsType(value, type)) + throw new PInhabitsTypeException( + $"value {value.ToString()} is not a member of type {type.ToString()}");*/ + return value.Clone(); + } + } +} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Scheduling/TestingProcessScheduler.cs b/Src/PChecker/CheckerCore/Scheduling/TestingProcessScheduler.cs deleted file mode 100644 index 4e1cf63a5e..0000000000 --- a/Src/PChecker/CheckerCore/Scheduling/TestingProcessScheduler.cs +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using PChecker.SystematicTesting; -using PChecker.Testing; -using PChecker.Utilities; -using Debug = PChecker.IO.Debugging.Debug; - -namespace PChecker.Scheduling -{ - /// - /// Testing Process that handles the scheduler - /// - public class TestingProcessScheduler - { - /// - /// CheckerConfiguration. - /// - private readonly CheckerConfiguration _checkerConfiguration; - - /// - /// Records if we want certain child test processes to terminate, this key here is the - /// SmartSocketClient Name. - /// - private readonly HashSet Terminating = new HashSet(); - - /// - /// The test reports per process. - /// - private readonly ConcurrentDictionary TestReports; - - /// - /// Test Trace files. - /// - private readonly ConcurrentDictionary traceFiles; - - /// - /// The global test report, which contains merged information - /// from the test report of each testing process. - /// - private readonly TestReport GlobalTestReport; - - /// - /// The testing profiler. - /// - private readonly Profiler Profiler; - - /// - /// The scheduler lock. - /// - private readonly object SchedulerLock; - - - /// - /// Set if ctrl-c or ctrl-break occurred. - /// - public static bool IsProcessCanceled; - - /// - /// Whether to write verbose output. - /// - private readonly bool IsVerbose; - - /// - /// Initializes a new instance of the class. - /// - private TestingProcessScheduler(CheckerConfiguration checkerConfiguration) - { - TestReports = new ConcurrentDictionary(); - traceFiles = new ConcurrentDictionary(); - GlobalTestReport = new TestReport(checkerConfiguration); - Profiler = new Profiler(); - SchedulerLock = new object(); - - IsVerbose = checkerConfiguration.IsVerbose; - - checkerConfiguration.EnableColoredConsoleOutput = true; - - _checkerConfiguration = checkerConfiguration; - } - - /// - /// Creates a new testing process scheduler. - /// - public static TestingProcessScheduler Create(CheckerConfiguration checkerConfiguration) - { - return new TestingProcessScheduler(checkerConfiguration); - } - - /// - /// Runs the Coyote testing scheduler. - /// - public void Run() - { - Profiler.StartMeasuringExecutionTime(); - - CreateAndRunInMemoryTestingProcess(); - - Profiler.StopMeasuringExecutionTime(); - - if (!IsProcessCanceled) - { - // Merges and emits the test report. - EmitTestReport(); - } - } - - /// - /// Creates and runs an in-memory testing process. - /// - private void CreateAndRunInMemoryTestingProcess() - { - var testingProcess = TestingProcess.Create(_checkerConfiguration); - - // Runs the testing process. - testingProcess.Run(); - - // Get and merge the test report. - var testReport = testingProcess.GetTestReport(); - if (testReport != null) - { - MergeTestReport(testReport, 0); - } - } - - /// - /// Merges the test report from the specified process. - /// - private void MergeTestReport(TestReport testReport, uint processId) - { - if (TestReports.TryAdd(processId, testReport)) - { - // Merges the test report into the global report. - Debug.WriteLine($"... Merging task {processId} test report."); - GlobalTestReport.Merge(testReport); - } - else - { - Debug.WriteLine($"... Unable to merge test report from task '{processId}'. " + - " Report is already merged."); - } - } - - /// - /// Emits the test report. - /// - private void EmitTestReport() - { - - if (TestReports.Count == 0) - { - Environment.ExitCode = (int)ExitCode.InternalError; - return; - } - - if (_checkerConfiguration.ReportActivityCoverage) - { - Console.WriteLine($"... Emitting coverage reports:"); - Reporter.EmitTestingCoverageReport(GlobalTestReport); - } - - if (_checkerConfiguration.DebugActivityCoverage) - { - Console.WriteLine($"... Emitting debug coverage reports:"); - foreach (var report in TestReports) - { - Reporter.EmitTestingCoverageReport(report.Value, report.Key, isDebug: true); - } - } - - Console.WriteLine(GlobalTestReport.GetText(_checkerConfiguration, "...")); - - var file = Path.GetFileNameWithoutExtension(GlobalTestReport.CheckerConfiguration.AssemblyToBeAnalyzed); - var directory = GlobalTestReport.CheckerConfiguration.OutputDirectory; - var pintPath = directory + file + "_pchecker_summary.txt"; - Console.WriteLine($"..... Writing {pintPath}"); - File.WriteAllText(pintPath, GlobalTestReport.GetSummaryText(Profiler)); - - Console.WriteLine($"... Elapsed {Profiler.GetElapsedTime():0.##} sec and used {Profiler.GetMaxMemoryUsage():0.##} GB."); - - if (GlobalTestReport.InternalErrors.Count > 0) - { - Environment.ExitCode = (int)ExitCode.InternalError; - } - else if (GlobalTestReport.NumOfFoundBugs > 0) - { - Environment.ExitCode = (int)ExitCode.BugFound; - } - else - { - Environment.ExitCode = (int)ExitCode.Success; - } - } - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs b/Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs index c5983e709a..9f1cd05283 100644 --- a/Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs +++ b/Src/PChecker/CheckerCore/SystematicTesting/ControlledRuntime.cs @@ -6,40 +6,93 @@ using System.Collections.Generic; using System.Diagnostics; using System.Globalization; +using System.IO; using System.Linq; +using System.Linq.Expressions; using System.Reflection; +using System.Threading; using System.Threading.Tasks; -using PChecker.Actors; -using PChecker.Actors.EventQueues; -using PChecker.Actors.EventQueues.Mocks; -using PChecker.Actors.Events; -using PChecker.Actors.Exceptions; -using PChecker.Actors.Managers; -using PChecker.Actors.Managers.Mocks; using PChecker.Coverage; using PChecker.Exceptions; using PChecker.Random; -using PChecker.Runtime; -using PChecker.Specifications.Monitors; +using PChecker.Runtime.Events; +using PChecker.Runtime.Logging; +using PChecker.Runtime.StateMachines; +using PChecker.Runtime.StateMachines.EventQueues; +using PChecker.Runtime.StateMachines.Exceptions; +using PChecker.Runtime.StateMachines.Managers; using PChecker.SystematicTesting.Operations; using PChecker.SystematicTesting.Strategies; using PChecker.SystematicTesting.Strategies.Liveness; using PChecker.SystematicTesting.Traces; using Debug = PChecker.IO.Debugging.Debug; -using EventInfo = PChecker.Actors.Events.EventInfo; +using EventInfo = PChecker.Runtime.Events.EventInfo; +using Monitor = PChecker.Runtime.Specifications.Monitor; +using PMachineValue = PChecker.Runtime.Values.PMachineValue; namespace PChecker.SystematicTesting { /// /// Runtime for controlling asynchronous operations. /// - internal sealed class ControlledRuntime : ActorRuntime + public sealed class ControlledRuntime : IDisposable { + /// + /// Provides access to the runtime associated with each asynchronous control flow. + /// + /// + /// In testing mode, each testing schedule uses a unique runtime instance. To safely + /// retrieve it from static methods, we store it in each asynchronous control flow. + /// + private static readonly AsyncLocal AsyncLocalInstance = new AsyncLocal(); + + private static ControlledRuntime CreateWithConfiguration(CheckerConfiguration checkerConfiguration) + { + if (checkerConfiguration is null) + { + checkerConfiguration = CheckerConfiguration.Create(); + } + + var valueGenerator = new RandomValueGenerator(checkerConfiguration); + return new ControlledRuntime(checkerConfiguration, valueGenerator); + } + /// /// The currently executing runtime. /// - internal static new ControlledRuntime Current => CoyoteRuntime.Current as ControlledRuntime; + internal static ControlledRuntime Current => AsyncLocalInstance.Value ?? + throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, + "Uncontrolled task '{0}' invoked a runtime method. Please make sure to avoid using concurrency APIs " + + "(e.g. 'Task.Run', 'Task.Delay' or 'Task.Yield' from the 'System.Threading.Tasks' namespace) inside " + + "state machine handlers or controlled tasks. If you are using external libraries that are executing concurrently, " + + "you will need to mock them during testing.", + Task.CurrentId.HasValue ? Task.CurrentId.Value.ToString() : "")); + + /// + /// The checkerConfiguration used by the runtime. + /// + internal readonly CheckerConfiguration CheckerConfiguration; + + /// + /// List of monitors in the program. + /// + readonly List Monitors; + /// + /// Monotonically increasing operation id counter. + /// + private long OperationIdCounter; + + /// + /// Records if the runtime is running. + /// + internal volatile bool IsRunning; + + /// + /// Callback that is fired when the program throws an exception which includes failed assertions. + /// + public event OnFailureHandler OnFailure; + /// /// The asynchronous operation scheduler. /// @@ -56,14 +109,46 @@ internal sealed class ControlledRuntime : ActorRuntime internal CoverageInfo CoverageInfo; /// - /// Map that stores all unique names and their corresponding actor ids. + /// Map that stores all unique names and their corresponding state machine ids. /// - internal readonly ConcurrentDictionary NameValueToActorId; + internal readonly ConcurrentDictionary NameValueToStateMachineId; /// /// The root task id. /// internal readonly int? RootTaskId; + + /// + /// Cache storing state machine constructors. + /// + private static readonly Dictionary> StateMachineConstructorCache = + new Dictionary>(); + + /// + /// Map from unique state machine ids to state machines. + /// + private readonly ConcurrentDictionary StateMachineMap; + + /// + /// Callback that is fired when an event is dropped. + /// + public event OnEventDroppedHandler OnEventDropped; + + /// + /// Responsible for writing to all registered objects. + /// + internal LogWriter LogWriter { get; private set; } + + /// + /// Used to log text messages. Use + /// to replace the logger with a custom one. + /// + public TextWriter Logger => LogWriter.Logger; + + /// + /// Used to log json trace outputs. + /// + public JsonWriter JsonLogger => LogWriter.JsonLogger; /// @@ -105,10 +190,10 @@ internal int GetHashedProgramState() foreach (var operation in Scheduler.GetRegisteredOperations().OrderBy(op => op.Id)) { - if (operation is ActorOperation actorOperation) + if (operation is StateMachineOperation stateMachineOperation) { - int operationHash = 31 + actorOperation.Actor.GetHashedState(); - operationHash = (operationHash * 31) + actorOperation.Type.GetHashCode(); + int operationHash = 31 + stateMachineOperation.StateMachine.GetHashedState(); + operationHash = (operationHash * 31) + stateMachineOperation.Type.GetHashCode(); hash *= operationHash; } else if (operation is TaskOperation taskOperation) @@ -125,14 +210,18 @@ internal int GetHashedProgramState() /// /// Initializes a new instance of the class. /// - internal ControlledRuntime(CheckerConfiguration checkerConfiguration, ISchedulingStrategy strategy, - IRandomValueGenerator valueGenerator) - : base(checkerConfiguration, valueGenerator) + internal ControlledRuntime(CheckerConfiguration checkerConfiguration, ISchedulingStrategy strategy) { - IsExecutionControlled = true; + CheckerConfiguration = checkerConfiguration; + Monitors = new List(); + OperationIdCounter = 0; + IsRunning = true; + + StateMachineMap = new ConcurrentDictionary(); + LogWriter = new LogWriter(checkerConfiguration); RootTaskId = Task.CurrentId; - NameValueToActorId = new ConcurrentDictionary(); + NameValueToStateMachineId = new ConcurrentDictionary(); CoverageInfo = new CoverageInfo(); @@ -149,70 +238,127 @@ internal ControlledRuntime(CheckerConfiguration checkerConfiguration, ISchedulin // allowing future retrieval in the same asynchronous call stack. AssignAsyncControlFlowRuntime(this); } - - /// - public override ActorId CreateActorIdFromName(Type type, string name) + + /// + /// Initializes a new instance of the class. + /// + internal ControlledRuntime(CheckerConfiguration checkerConfiguration, + IRandomValueGenerator valueGenerator) { - // It is important that all actor ids use the monotonically incrementing - // value as the id during testing, and not the unique name. - var id = new ActorId(type, name, this); - return NameValueToActorId.GetOrAdd(name, id); - } + StateMachineMap = new ConcurrentDictionary(); + LogWriter = new LogWriter(checkerConfiguration); - /// - public override ActorId CreateActor(Type type, Event initialEvent = null, Guid opGroupId = default) => - CreateActor(null, type, null, initialEvent, opGroupId); + RootTaskId = Task.CurrentId; + NameValueToStateMachineId = new ConcurrentDictionary(); - /// - public override ActorId CreateActor(Type type, string name, Event initialEvent = null, Guid opGroupId = default) => - CreateActor(null, type, name, initialEvent, opGroupId); + CoverageInfo = new CoverageInfo(); + + // Update the current asynchronous control flow with this runtime instance, + // allowing future retrieval in the same asynchronous call stack. + AssignAsyncControlFlowRuntime(this); + } + + /// + /// Assigns the specified runtime as the default for the current asynchronous control flow. + /// + internal static void AssignAsyncControlFlowRuntime(ControlledRuntime runtime) => AsyncLocalInstance.Value = runtime; + + /// + /// Creates a fresh state machine id that has not yet been bound to any state machine. + /// + public StateMachineId CreateStateMachineId(Type type, string name = null) => new StateMachineId(type, name, this); - /// - public override ActorId CreateActor(ActorId id, Type type, Event initialEvent = null, Guid opGroupId = default) + /// + /// Creates an state machine id that is uniquely tied to the specified unique name. The + /// returned state machine id can either be a fresh id (not yet bound to any state machine), or + /// it can be bound to a previously created state machine. In the second case, this state machine + /// id can be directly used to communicate with the corresponding state machine. + /// + public StateMachineId CreateStateMachineIdFromName(Type type, string name) { - Assert(id != null, "Cannot create an actor using a null actor id."); - return CreateActor(id, type, null, initialEvent, opGroupId); + // It is important that all state machine ids use the monotonically incrementing + // value as the id during testing, and not the unique name. + var id = new StateMachineId(type, name, this); + return NameValueToStateMachineId.GetOrAdd(name, id); } - /// - public override Task CreateActorAndExecuteAsync(Type type, Event e = null, Guid opGroupId = default) => - CreateActorAndExecuteAsync(null, type, null, e, opGroupId); + /// + /// Creates a new state machine of the specified and with the specified + /// optional . This event can only be used to access its payload, + /// and cannot be handled. + /// + public StateMachineId CreateStateMachine(Type type, Event initialEvent = null) => + CreateStateMachine(null, type, null, initialEvent); - /// - public override Task CreateActorAndExecuteAsync(Type type, string name, Event e = null, Guid opGroupId = default) => - CreateActorAndExecuteAsync(null, type, name, e, opGroupId); + /// + /// Creates a new state machine of the specified and name, and with the + /// specified optional . This event can only be used to access + /// its payload, and cannot be handled. + /// + public StateMachineId CreateStateMachine(Type type, string name, Event initialEvent = null) => + CreateStateMachine(null, type, name, initialEvent); - /// - public override Task CreateActorAndExecuteAsync(ActorId id, Type type, Event e = null, Guid opGroupId = default) + /// + /// Creates a new state machine of the specified type, using the specified . + /// This method optionally passes an to the new state machine, which can only + /// be used to access its payload, and cannot be handled. + /// + public StateMachineId CreateStateMachine(StateMachineId id, Type type, Event initialEvent = null) { - Assert(id != null, "Cannot create an actor using a null actor id."); - return CreateActorAndExecuteAsync(id, type, null, e, opGroupId); + Assert(id != null, "Cannot create an state machine using a null state machine id."); + return CreateStateMachine(id, type, null, initialEvent); } - /// - public override void SendEvent(ActorId targetId, Event e, Guid opGroupId = default) + /// + /// Creates a new state machine of the specified and with the specified + /// optional . This event can only be used to access its payload, + /// and cannot be handled. The method returns only when the state machine is initialized and + /// the (if any) is handled. + /// + public Task CreateStateMachineAndExecuteAsync(Type type, Event e = null) => + CreateStateMachineAndExecuteAsync(null, type, null, e); + + /// + /// Creates a new state machine of the specified and name, and with the + /// specified optional . This event can only be used to access + /// its payload, and cannot be handled. The method returns only when the state machine is + /// initialized and the (if any) is handled. + /// + public Task CreateStateMachineAndExecuteAsync(Type type, string name, Event e = null) => + CreateStateMachineAndExecuteAsync(null, type, name, e); + + /// + /// Creates a new state machine of the specified , using the specified unbound + /// state machine id, and passes the specified optional . This event can only + /// be used to access its payload, and cannot be handled. The method returns only when + /// the state machine is initialized and the (if any) + /// is handled. + /// + public Task CreateStateMachineAndExecuteAsync(StateMachineId id, Type type, Event e = null) { - var senderOp = Scheduler.GetExecutingOperation(); - SendEvent(targetId, e, senderOp?.Actor, opGroupId); + Assert(id != null, "Cannot create an state machine using a null state machine id."); + return CreateStateMachineAndExecuteAsync(id, type, null, e); } - /// - public override Task SendEventAndExecuteAsync(ActorId targetId, Event e, Guid opGroupId = default) + /// + /// Sends an asynchronous to a state machine. + /// + public void SendEvent(StateMachineId targetId, Event e) { - var senderOp = Scheduler.GetExecutingOperation(); - return SendEventAndExecuteAsync(targetId, e, senderOp?.Actor, opGroupId); + var senderOp = Scheduler.GetExecutingOperation(); + SendEvent(targetId, e, senderOp?.StateMachine); } - /// - public override Guid GetCurrentOperationGroupId(ActorId currentActorId) + /// + /// Sends an to a state machine. Returns immediately if the target was already + /// running. Otherwise, blocks until the target handles the event and reaches quiescence. + /// + public Task SendEventAndExecuteAsync(StateMachineId targetId, Event e) { - var callerOp = Scheduler.GetExecutingOperation(); - Assert(callerOp != null && currentActorId == callerOp.Actor.Id, - "Trying to access the operation group id of {0}, which is not the currently executing actor.", - currentActorId); - return callerOp.Actor.OperationGroupId; + var senderOp = Scheduler.GetExecutingOperation(); + return SendEventAndExecuteAsync(targetId, e, senderOp?.StateMachine); } - + /// /// Runs the specified test method. /// @@ -238,7 +384,7 @@ internal void RunTest(Delegate testMethod, string testName) OperationScheduler.StartOperation(op); - if (testMethod is Action actionWithRuntime) + if (testMethod is Action actionWithRuntime) { actionWithRuntime(this); } @@ -246,7 +392,7 @@ internal void RunTest(Delegate testMethod, string testName) { action(); } - else if (testMethod is Func functionWithRuntime) + else if (testMethod is Func functionWithRuntime) { await functionWithRuntime(this); } @@ -275,65 +421,77 @@ internal void RunTest(Delegate testMethod, string testName) task.Start(); Scheduler.WaitOperationStart(op); } + + /// + /// Returns the next available unique operation id. + /// + /// Value representing the next available unique operation id. + internal ulong GetNextOperationId() => + // Atomically increments and safely wraps the value into an unsigned long. + (ulong)Interlocked.Increment(ref OperationIdCounter) - 1; /// - /// Creates a new actor of the specified and name, using the specified - /// unbound actor id, and passes the specified optional . This event + /// Creates a new state machine of the specified and name, using the specified + /// unbound state machine id, and passes the specified optional . This event /// can only be used to access its payload, and cannot be handled. /// - internal ActorId CreateActor(ActorId id, Type type, string name, Event initialEvent = null, - Guid opGroupId = default) + internal StateMachineId CreateStateMachine(StateMachineId id, Type type, string name, Event initialEvent = null) { - var creatorOp = Scheduler.GetExecutingOperation(); - return CreateActor(id, type, name, initialEvent, creatorOp?.Actor, opGroupId); + var creatorOp = Scheduler.GetExecutingOperation(); + return CreateStateMachine(id, type, name, initialEvent, creatorOp?.StateMachine); } - /// - internal override ActorId CreateActor(ActorId id, Type type, string name, Event initialEvent, Actor creator, - Guid opGroupId) + /// + /// Creates a new of the specified . + /// + internal StateMachineId CreateStateMachine(StateMachineId id, Type type, string name, Event initialEvent, StateMachine creator) { - AssertExpectedCallerActor(creator, "CreateActor"); + AssertExpectedCallerStateMachine(creator, "CreateStateMachine"); - var actor = CreateActor(id, type, name, creator, opGroupId); - RunActorEventHandler(actor, initialEvent, true, null); - return actor.Id; + var stateMachine = CreateStateMachine(id, type, name, creator); + LogWriter.LogCreateStateMachine(stateMachine.Id, creator?.Id.Name, creator?.Id.Type); + RunStateMachineEventHandler(stateMachine, initialEvent, true, null); + return stateMachine.Id; } /// - /// Creates a new actor of the specified and name, using the specified - /// unbound actor id, and passes the specified optional . This event + /// Creates a new state machine of the specified and name, using the specified + /// unbound state machine id, and passes the specified optional . This event /// can only be used to access its payload, and cannot be handled. The method returns only - /// when the actor is initialized and the (if any) is handled. + /// when the state machine is initialized and the (if any) is handled. /// - internal Task CreateActorAndExecuteAsync(ActorId id, Type type, string name, Event initialEvent = null, - Guid opGroupId = default) + internal Task CreateStateMachineAndExecuteAsync(StateMachineId id, Type type, string name, Event initialEvent = null) { - var creatorOp = Scheduler.GetExecutingOperation(); - return CreateActorAndExecuteAsync(id, type, name, initialEvent, creatorOp?.Actor, opGroupId); + var creatorOp = Scheduler.GetExecutingOperation(); + return CreateStateMachineAndExecuteAsync(id, type, name, initialEvent, creatorOp?.StateMachine); } - /// - internal override async Task CreateActorAndExecuteAsync(ActorId id, Type type, string name, - Event initialEvent, Actor creator, Guid opGroupId) + /// + /// Creates a new of the specified . The method + /// returns only when the state machine is initialized and the (if any) + /// is handled. + /// + internal async Task CreateStateMachineAndExecuteAsync(StateMachineId id, Type type, string name, + Event initialEvent, StateMachine creator) { - AssertExpectedCallerActor(creator, "CreateActorAndExecuteAsync"); - Assert(creator != null, "Only an actor can call 'CreateActorAndExecuteAsync': avoid calling " + - "it directly from the test method; instead call it through a test driver actor."); + AssertExpectedCallerStateMachine(creator, "CreateStateMachineAndExecuteAsync"); + Assert(creator != null, "Only a state machine can call 'CreateStateMachineAndExecuteAsync': avoid calling " + + "it directly from the test method; instead call it through a test driver state machine."); - var actor = CreateActor(id, type, name, creator, opGroupId); - RunActorEventHandler(actor, initialEvent, true, creator); + var stateMachine = CreateStateMachine(id, type, name, creator); + RunStateMachineEventHandler(stateMachine, initialEvent, true, creator); - // Wait until the actor reaches quiescence. - await creator.ReceiveEventAsync(typeof(QuiescentEvent), rev => (rev as QuiescentEvent).ActorId == actor.Id); - return await Task.FromResult(actor.Id); + // Wait until the state machine reaches quiescence. + await creator.ReceiveEventAsync(typeof(QuiescentEvent), rev => (rev as QuiescentEvent).StateMachineId == stateMachine.Id); + return await Task.FromResult(stateMachine.Id); } /// - /// Creates a new actor of the specified . + /// Creates a new state machine of the specified . /// - private Actor CreateActor(ActorId id, Type type, string name, Actor creator, Guid opGroupId) + private StateMachine CreateStateMachine(StateMachineId id, Type type, string name, StateMachine creator) { - Assert(type.IsSubclassOf(typeof(Actor)), "Type '{0}' is not an actor.", type.FullName); + Assert(type.IsSubclassOf(typeof(StateMachine)), "Type '{0}' is not a state machine.", type.FullName); // Using ulong.MaxValue because a Create operation cannot specify // the id of its target, because the id does not exist yet. @@ -342,145 +500,136 @@ private Actor CreateActor(ActorId id, Type type, string name, Actor creator, Gui if (id is null) { - id = new ActorId(type, name, this); - } - else - { - Assert(id.Runtime is null || id.Runtime == this, "Unbound actor id '{0}' was created by another runtime.", id.Value); - Assert(id.Type == type.FullName, "Cannot bind actor id '{0}' of type '{1}' to an actor of type '{2}'.", - id.Value, id.Type, type.FullName); - id.Bind(this); + id = new StateMachineId(type, name, this); } + + var stateMachine = Create(type); + IStateMachineManager stateMachineManager = new StateMachineManager(this, stateMachine); - // The operation group id of the actor is set using the following precedence: - // (1) To the specified actor creation operation group id, if it is non-empty. - // (2) To the operation group id of the creator actor, if it exists and is non-empty. - // (3) To the empty operation group id. - if (opGroupId == Guid.Empty && creator != null) - { - opGroupId = creator.OperationGroupId; - } + IEventQueue eventQueue = new EventQueue(stateMachineManager, stateMachine); + stateMachine.Configure(this, id, stateMachineManager, eventQueue); + stateMachine.SetupEventHandlers(); + stateMachine.self = new PMachineValue(id, stateMachine.receives.ToList()); + stateMachine.interfaceName = "I_" + name; - var actor = ActorFactory.Create(type); - IActorManager actorManager; - if (actor is StateMachine stateMachine) - { - actorManager = new MockStateMachineManager(this, stateMachine, opGroupId); - } - else + if (CheckerConfiguration.ReportActivityCoverage) { - actorManager = new MockActorManager(this, actor, opGroupId); + ReportActivityCoverageOfStateMachine(stateMachine); } - IEventQueue eventQueue = new MockEventQueue(actorManager, actor); - actor.Configure(this, id, actorManager, eventQueue); - actor.SetupEventHandlers(); + var result = Scheduler.RegisterOperation(new StateMachineOperation(stateMachine)); + Assert(result, "StateMachine id '{0}' is used by an existing or previously halted state machine.", id.Value); + LogWriter.LogCreateStateMachine(id, creator?.Id.Name, creator?.Id.Type); - if (CheckerConfiguration.ReportActivityCoverage) + return stateMachine; + } + + /// + /// Creates a new instance of the specified type. + /// + /// The type of the state machines. + /// The created state machine instance. + public static StateMachine Create(Type type) + { + Func constructor = null; + lock (StateMachineConstructorCache) { - ReportActivityCoverageOfActor(actor); - } + if (!StateMachineConstructorCache.TryGetValue(type, out constructor)) + { + var constructorInfo = type.GetConstructor(Type.EmptyTypes); + if (constructorInfo == null) + { + throw new Exception("Could not find empty constructor for type " + type.FullName); + } - var result = Scheduler.RegisterOperation(new ActorOperation(actor)); - Assert(result, "Actor id '{0}' is used by an existing or previously halted actor.", id.Value); - if (actor is StateMachine) - { - LogWriter.LogCreateStateMachine(id, creator?.Id.Name, creator?.Id.Type); - } - else - { - LogWriter.LogCreateActor(id, creator?.Id.Name, creator?.Id.Type); + constructor = Expression.Lambda>( + Expression.New(constructorInfo)).Compile(); + StateMachineConstructorCache.Add(type, constructor); + } } - return actor; + return constructor(); } - /// - internal override void SendEvent(ActorId targetId, Event e, Actor sender, Guid opGroupId) + /// + /// Sends an asynchronous to a state machine. + /// + internal void SendEvent(StateMachineId targetId, Event e, StateMachine sender) { if (e is null) { var message = sender != null ? - string.Format("{0} is sending a null event.", sender.Id.ToString()) : + string.Format("{0} is sending a null event.", sender.Id) : "Cannot send a null event."; Assert(false, message); } if (sender != null) { - Assert(targetId != null, "{0} is sending event {1} to a null actor.", sender.Id, e); + Assert(targetId != null, "{0} is sending event {1} to a null state machine.", sender.Id, e); } else { - Assert(targetId != null, "Cannot send event {1} to a null actor.", e); + Assert(targetId != null, "Cannot send event {1} to a null state machine.", e); } - AssertExpectedCallerActor(sender, "SendEvent"); + AssertExpectedCallerStateMachine(sender, "SendEvent"); - var enqueueStatus = EnqueueEvent(targetId, e, sender, opGroupId, out var target); + var enqueueStatus = EnqueueEvent(targetId, e, sender, out var target); if (enqueueStatus is EnqueueStatus.EventHandlerNotRunning) { - RunActorEventHandler(target, null, false, null); + RunStateMachineEventHandler(target, null, false, null); } } - /// - internal override async Task SendEventAndExecuteAsync(ActorId targetId, Event e, Actor sender, - Guid opGroupId) + /// + /// Sends an asynchronous to a state machine. Returns immediately if the target was + /// already running. Otherwise, blocks until the target handles the event and reaches quiescence. + /// + internal async Task SendEventAndExecuteAsync(StateMachineId targetId, Event e, StateMachine sender) { - Assert(sender is StateMachine, "Only an actor can call 'SendEventAndExecuteAsync': avoid " + - "calling it directly from the test method; instead call it through a test driver actor."); Assert(e != null, "{0} is sending a null event.", sender.Id); - Assert(targetId != null, "{0} is sending event {1} to a null actor.", sender.Id, e); - AssertExpectedCallerActor(sender, "SendEventAndExecuteAsync"); + Assert(targetId != null, "{0} is sending event {1} to a null state machine.", sender.Id, e); + AssertExpectedCallerStateMachine(sender, "SendEventAndExecuteAsync"); - var enqueueStatus = EnqueueEvent(targetId, e, sender, opGroupId, out var target); + var enqueueStatus = EnqueueEvent(targetId, e, sender, out var target); if (enqueueStatus is EnqueueStatus.EventHandlerNotRunning) { - RunActorEventHandler(target, null, false, sender as StateMachine); + RunStateMachineEventHandler(target, null, false, sender); - // Wait until the actor reaches quiescence. - await (sender as StateMachine).ReceiveEventAsync(typeof(QuiescentEvent), rev => (rev as QuiescentEvent).ActorId == targetId); + // Wait until the state machine reaches quiescence. + await sender.ReceiveEventAsync(typeof(QuiescentEvent), rev => (rev as QuiescentEvent).StateMachineId == targetId); return true; } // EnqueueStatus.EventHandlerNotRunning is not returned by EnqueueEvent - // (even when the actor was previously inactive) when the event e requires - // no action by the actor (i.e., it implicitly handles the event). + // (even when the state machine was previously inactive) when the event e requires + // no action by the state machine (i.e., it implicitly handles the event). return enqueueStatus is EnqueueStatus.Dropped || enqueueStatus is EnqueueStatus.NextEventUnavailable; } /// - /// Enqueues an event to the actor with the specified id. + /// Enqueues an event to the state machine with the specified id. /// - private EnqueueStatus EnqueueEvent(ActorId targetId, Event e, Actor sender, Guid opGroupId, out Actor target) + private EnqueueStatus EnqueueEvent(StateMachineId targetId, Event e, StateMachine sender, out StateMachine target) { - target = Scheduler.GetOperationWithId(targetId.Value)?.Actor; + target = Scheduler.GetOperationWithId(targetId.Value)?.StateMachine; Assert(target != null, - "Cannot send event '{0}' to actor id '{1}' that is not bound to an actor instance.", + "Cannot send event '{0}' to state machine id '{1}' that is not bound to an state machine instance.", e.GetType().FullName, targetId.Value); Scheduler.ScheduleNextEnabledOperation(AsyncOperationType.Send); - ResetProgramCounter(sender as StateMachine); - - // The operation group id of this operation is set using the following precedence: - // (1) To the specified send operation group id, if it is non-empty. - // (2) To the operation group id of the sender actor, if it exists and is non-empty. - // (3) To the empty operation group id. - if (opGroupId == Guid.Empty && sender != null) - { - opGroupId = sender.OperationGroupId; - } + ResetProgramCounter(sender); if (target.IsHalted) { LogWriter.LogSendEvent(targetId, sender?.Id.Name, sender?.Id.Type, - (sender as StateMachine)?.CurrentStateName ?? string.Empty, e, opGroupId, isTargetHalted: true); + (sender)?.CurrentStateName ?? string.Empty, e, isTargetHalted: true); TryHandleDroppedEvent(e, targetId); return EnqueueStatus.Dropped; } - var enqueueStatus = EnqueueEvent(target, e, sender, opGroupId); + var enqueueStatus = EnqueueEvent(target, e, sender); if (enqueueStatus == EnqueueStatus.Dropped) { TryHandleDroppedEvent(e, targetId); @@ -490,47 +639,33 @@ private EnqueueStatus EnqueueEvent(ActorId targetId, Event e, Actor sender, Guid } /// - /// Enqueues an event to the actor with the specified id. + /// Enqueues an event to the state machine with the specified id. /// - private EnqueueStatus EnqueueEvent(Actor actor, Event e, Actor sender, Guid opGroupId) + private EnqueueStatus EnqueueEvent(StateMachine stateMachine, Event e, StateMachine sender) { - EventOriginInfo originInfo; - - string stateName = null; - if (sender is StateMachine senderStateMachine) - { - originInfo = new EventOriginInfo(sender.Id, senderStateMachine.GetType().FullName, - NameResolver.GetStateNameForLogging(senderStateMachine.CurrentState)); - stateName = senderStateMachine.CurrentStateName; - } - else if (sender is Actor senderActor) - { - originInfo = new EventOriginInfo(sender.Id, senderActor.GetType().FullName, string.Empty); - } - else - { - // Message comes from the environment. - originInfo = new EventOriginInfo(null, "Env", "Env"); - } + // Directly use sender as a StateMachine + var originInfo = new EventOriginInfo(sender.Id, sender.GetType().FullName, + sender.CurrentState.GetType().Name); var eventInfo = new EventInfo(e, originInfo); - LogWriter.LogSendEvent(actor.Id, sender?.Id.Name, sender?.Id.Type, stateName, - e, opGroupId, isTargetHalted: false); - return actor.Enqueue(e, opGroupId, eventInfo); + LogWriter.LogSendEvent(stateMachine.Id, sender.Id.Name, sender.Id.Type, sender.CurrentStateName, + e, isTargetHalted: false); + + return stateMachine.Enqueue(e, eventInfo); } /// - /// Runs a new asynchronous event handler for the specified actor. - /// This is a fire and forget invocation. + /// Runs a new asynchronous event handler for the specified state machine. + /// This is a fire-and-forget invocation. /// - /// The actor that executes this event handler. - /// Optional event for initializing the actor. - /// If true, then this is a new actor. - /// Caller actor that is blocked for quiscence. - private void RunActorEventHandler(Actor actor, Event initialEvent, bool isFresh, Actor syncCaller) + /// The state machine that executes this event handler. + /// Optional event for initializing the state machine. + /// If true, then this is a new state machine. + /// Caller state machine that is blocked for quiescence. + private void RunStateMachineEventHandler(StateMachine stateMachine, Event initialEvent, bool isFresh, StateMachine syncCaller) { - var op = Scheduler.GetOperationWithId(actor.Id.Value); + var op = Scheduler.GetOperationWithId(stateMachine.Id.Value); op.OnEnabled(); var task = new Task(async () => @@ -545,24 +680,24 @@ private void RunActorEventHandler(Actor actor, Event initialEvent, bool isFresh, if (isFresh) { - await actor.InitializeAsync(initialEvent); + await stateMachine.InitializeAsync(initialEvent); } - await actor.RunEventHandlerAsync(); + await stateMachine.RunEventHandlerAsync(); if (syncCaller != null) { - EnqueueEvent(syncCaller, new QuiescentEvent(actor.Id), actor, actor.OperationGroupId); + EnqueueEvent(syncCaller, new QuiescentEvent(stateMachine.Id), stateMachine); } - if (!actor.IsHalted) + if (!stateMachine.IsHalted) { - ResetProgramCounter(actor); + ResetProgramCounter(stateMachine); } - Debug.WriteLine(" Completed operation {0} on task '{1}'.", actor.Id, Task.CurrentId); + Debug.WriteLine(" Completed operation {0} on task '{1}'.", stateMachine.Id, Task.CurrentId); op.OnCompleted(); - // The actor is inactive or halted, schedule the next enabled operation. + // The state machine is inactive or halted, schedule the next enabled operation. Scheduler.ScheduleNextEnabledOperation(AsyncOperationType.Stop); } catch (Exception ex) @@ -613,9 +748,29 @@ private void ProcessUnhandledExceptionInOperation(AsyncOperation op, Exception e Scheduler.NotifyAssertionFailure(message, killTasks: true, cancelExecution: false); } } + + /// + /// Registers a new specification monitor of the specified . + /// + public void RegisterMonitor() + where T : Monitor => + TryCreateMonitor(typeof(T)); - /// - internal override void TryCreateMonitor(Type type) + /// + /// Invokes the specified monitor with the specified . + /// + public void Monitor(Event e) + where T : Monitor + { + // If the event is null then report an error and exit. + Assert(e != null, "Cannot monitor a null event."); + Monitor(typeof(T), e, null, null, null); + } + + /// + /// Tries to create a new of the specified . + /// + internal void TryCreateMonitor(Type type) { if (Monitors.Any(m => m.GetType() == type)) { @@ -641,8 +796,10 @@ internal override void TryCreateMonitor(Type type) monitor.GotoStartState(); } - /// - internal override void Monitor(Type type, Event e, string senderName, string senderType, string senderStateName) + /// + /// Invokes the specified with the specified . + /// + internal void Monitor(Type type, Event e, string senderName, string senderType, string senderStateName) { foreach (var monitor in Monitors) { @@ -654,11 +811,13 @@ internal override void Monitor(Type type, Event e, string senderName, string sen } } - /// + /// + /// Checks if the assertion holds, and if not, throws an exception. + /// #if !DEBUG [DebuggerHidden] #endif - public override void Assert(bool predicate) + public void Assert(bool predicate) { if (!predicate) { @@ -666,11 +825,13 @@ public override void Assert(bool predicate) } } - /// + /// + /// Checks if the assertion holds, and if not, throws an exception. + /// #if !DEBUG [DebuggerHidden] #endif - public override void Assert(bool predicate, string s, object arg0) + public void Assert(bool predicate, string s, object arg0) { if (!predicate) { @@ -679,11 +840,13 @@ public override void Assert(bool predicate, string s, object arg0) } } - /// + /// + /// Checks if the assertion holds, and if not, throws an exception. + /// #if !DEBUG [DebuggerHidden] #endif - public override void Assert(bool predicate, string s, object arg0, object arg1) + public void Assert(bool predicate, string s, object arg0, object arg1) { if (!predicate) { @@ -692,11 +855,13 @@ public override void Assert(bool predicate, string s, object arg0, object arg1) } } - /// + /// + /// Checks if the assertion holds, and if not, throws an exception. + /// #if !DEBUG [DebuggerHidden] #endif - public override void Assert(bool predicate, string s, object arg0, object arg1, object arg2) + public void Assert(bool predicate, string s, object arg0, object arg1, object arg2) { if (!predicate) { @@ -705,11 +870,13 @@ public override void Assert(bool predicate, string s, object arg0, object arg1, } } - /// + /// + /// Checks if the assertion holds, and if not, throws an exception. + /// #if !DEBUG [DebuggerHidden] #endif - public override void Assert(bool predicate, string s, params object[] args) + public void Assert(bool predicate, string s, params object[] args) { if (!predicate) { @@ -719,27 +886,27 @@ public override void Assert(bool predicate, string s, params object[] args) } /// - /// Asserts that the actor calling an actor method is also - /// the actor that is currently executing. + /// Asserts that the state machine calling an state machine method is also + /// the state machine that is currently executing. /// #if !DEBUG [DebuggerHidden] #endif - private void AssertExpectedCallerActor(Actor caller, string calledAPI) + private void AssertExpectedCallerStateMachine(StateMachine caller, string calledAPI) { if (caller is null) { return; } - var op = Scheduler.GetExecutingOperation(); + var op = Scheduler.GetExecutingOperation(); if (op is null) { return; } - Assert(op.Actor.Equals(caller), "{0} invoked {1} on behalf of {2}.", - op.Actor.Id, calledAPI, caller.Id); + Assert(op.StateMachine.Equals(caller), "{0} invoked {1} on behalf of {2}.", + op.StateMachine.Id, calledAPI, caller.Id); } /// @@ -768,18 +935,24 @@ internal void CheckNoMonitorInHotStateAtTermination() } } } + + /// + /// Returns a nondeterministic boolean choice, that can be controlled + /// during analysis or testing. + /// + public bool RandomBoolean() => GetNondeterministicBooleanChoice(2, null, null); - /// - internal override bool GetNondeterministicBooleanChoice(int maxValue, string callerName, string callerType) + /// + /// Returns a nondeterministic boolean choice, that can be controlled + /// during analysis or testing. The value is used to generate a number + /// in the range [0..maxValue), where 0 triggers true. + /// + internal bool GetNondeterministicBooleanChoice(int maxValue, string callerName, string callerType) { - var caller = Scheduler.GetExecutingOperation()?.Actor; - if (caller is StateMachine callerStateMachine) + var caller = Scheduler.GetExecutingOperation()?.StateMachine; + if (caller != null) { - (callerStateMachine.Manager as MockStateMachineManager).ProgramCounter++; - } - else if (caller is Actor callerActor) - { - (callerActor.Manager as MockActorManager).ProgramCounter++; + (caller.Manager as StateMachineManager).ProgramCounter++; } var choice = Scheduler.GetNextNondeterministicBooleanChoice(maxValue); @@ -787,23 +960,32 @@ internal override bool GetNondeterministicBooleanChoice(int maxValue, string cal return choice; } - /// - internal override int GetNondeterministicIntegerChoice(int maxValue, string callerName, string callerType) + /// + /// Returns a nondeterministic integer, that can be controlled during + /// analysis or testing. The value is used to generate an integer in + /// the range [0..maxValue). + /// + internal int GetNondeterministicIntegerChoice(int maxValue, string callerName, string callerType) { - var caller = Scheduler.GetExecutingOperation()?.Actor; - if (caller is StateMachine callerStateMachine) - { - (callerStateMachine.Manager as MockStateMachineManager).ProgramCounter++; - } - else if (caller is Actor callerActor) + var caller = Scheduler.GetExecutingOperation()?.StateMachine; + if (caller != null) { - (callerActor.Manager as MockActorManager).ProgramCounter++; + (caller.Manager as StateMachineManager).ProgramCounter++; } var choice = Scheduler.GetNextNondeterministicIntegerChoice(maxValue); LogWriter.LogRandom(choice, callerName ?? caller?.Id.Name, callerType ?? caller?.Id.Type); return choice; } + + /// + /// Gets the state machine of type with the specified id, + /// or null if no such state machine exists. + /// + private TStateMachine GetStateMachineWithId(StateMachineId id) + where TStateMachine : StateMachine => + id != null && StateMachineMap.TryGetValue(id, out var value) && + value is TStateMachine stateMachine ? stateMachine : null; /// /// Gets the that is executing on the current @@ -837,17 +1019,21 @@ internal void ScheduleNextOperation(AsyncOperationType type) } } - /// - internal override void NotifyInvokedAction(Actor actor, MethodInfo action, string handlingStateName, + /// + /// Notifies that a state machine invoked an action. + /// + internal void NotifyInvokedAction(StateMachine stateMachine, MethodInfo action, string handlingStateName, string currentStateName, Event receivedEvent) { - LogWriter.LogExecuteAction(actor.Id, handlingStateName, currentStateName, action.Name); + LogWriter.LogExecuteAction(stateMachine.Id, handlingStateName, currentStateName, action.Name); } - /// - internal override void NotifyDequeuedEvent(Actor actor, Event e, EventInfo eventInfo) + /// + /// Notifies that a state machine dequeued an . + /// + internal void NotifyDequeuedEvent(StateMachine stateMachine, Event e, EventInfo eventInfo) { - var op = Scheduler.GetOperationWithId(actor.Id.Value); + var op = Scheduler.GetOperationWithId(stateMachine.Id.Value); // Skip `ReceiveEventAsync` if the last operation exited the previous event handler, // to avoid scheduling duplicate `ReceiveEventAsync` operations. @@ -858,68 +1044,87 @@ internal override void NotifyDequeuedEvent(Actor actor, Event e, EventInfo event else { Scheduler.ScheduleNextEnabledOperation(AsyncOperationType.Receive); - ResetProgramCounter(actor); + ResetProgramCounter(stateMachine); } - var stateName = actor is StateMachine stateMachine ? stateMachine.CurrentStateName : null; - LogWriter.LogDequeueEvent(actor.Id, stateName, e); + var stateName = stateMachine.CurrentStateName; + LogWriter.LogDequeueEvent(stateMachine.Id, stateName, e); } - /// - internal override void NotifyDefaultEventDequeued(Actor actor) + /// + /// Notifies that a state machine dequeued the default . + /// + internal void NotifyDefaultEventDequeued(StateMachine stateMachine) { Scheduler.ScheduleNextEnabledOperation(AsyncOperationType.Receive); - ResetProgramCounter(actor); + ResetProgramCounter(stateMachine); } - /// - internal override void NotifyDefaultEventHandlerCheck(Actor actor) + /// + /// Notifies that the inbox of the specified state machine is about to be + /// checked to see if the default event handler should fire. + /// + internal void NotifyDefaultEventHandlerCheck(StateMachine stateMachine) { Scheduler.ScheduleNextEnabledOperation(AsyncOperationType.Default); } - /// - internal override void NotifyRaisedEvent(Actor actor, Event e, EventInfo eventInfo) + /// + /// Notifies that a state machine raised an . + /// + internal void NotifyRaisedEvent(StateMachine stateMachine, Event e, EventInfo eventInfo) { - var stateName = actor is StateMachine stateMachine ? stateMachine.CurrentStateName : null; - LogWriter.LogRaiseEvent(actor.Id, stateName, e); + var stateName = stateMachine.CurrentStateName; + LogWriter.LogRaiseEvent(stateMachine.Id, stateName, e); } - /// - internal override void NotifyHandleRaisedEvent(Actor actor, Event e) + /// + /// Notifies that a state machine is handling a raised . + /// + internal void NotifyHandleRaisedEvent(StateMachine stateMachine, Event e) { - var stateName = actor is StateMachine stateMachine ? stateMachine.CurrentStateName : null; - LogWriter.LogHandleRaisedEvent(actor.Id, stateName, e); + var stateName = stateMachine.CurrentStateName; + LogWriter.LogHandleRaisedEvent(stateMachine.Id, stateName, e); } - /// - internal override void NotifyReceiveCalled(Actor actor) + /// + /// Notifies that a state machine called + /// or one of its overloaded methods. + /// + internal void NotifyReceiveCalled(StateMachine stateMachine) { - AssertExpectedCallerActor(actor, "ReceiveEventAsync"); + AssertExpectedCallerStateMachine(stateMachine, "ReceiveEventAsync"); } - /// - internal override void NotifyReceivedEvent(Actor actor, Event e, EventInfo eventInfo) + /// + /// Notifies that a state machine enqueued an event that it was waiting to receive. + /// + internal void NotifyReceivedEvent(StateMachine stateMachine, Event e, EventInfo eventInfo) { - var stateName = actor is StateMachine stateMachine ? stateMachine.CurrentStateName : null; - LogWriter.LogReceiveEvent(actor.Id, stateName, e, wasBlocked: true); - var op = Scheduler.GetOperationWithId(actor.Id.Value); + var stateName = stateMachine.CurrentStateName; + LogWriter.LogReceiveEvent(stateMachine.Id, stateName, e, wasBlocked: true); + var op = Scheduler.GetOperationWithId(stateMachine.Id.Value); op.OnReceivedEvent(); } - /// - internal override void NotifyReceivedEventWithoutWaiting(Actor actor, Event e, EventInfo eventInfo) + /// + /// Notifies that a state machine received an event without waiting because the event + /// was already in the inbox when the state machine invoked the receiving statement. + /// + internal void NotifyReceivedEventWithoutWaiting(StateMachine stateMachine, Event e, EventInfo eventInfo) { - var stateName = actor is StateMachine stateMachine ? stateMachine.CurrentStateName : null; - LogWriter.LogReceiveEvent(actor.Id, stateName, e, wasBlocked: false); + var stateName = stateMachine.CurrentStateName; + LogWriter.LogReceiveEvent(stateMachine.Id, stateName, e, wasBlocked: false); Scheduler.ScheduleNextEnabledOperation(AsyncOperationType.Receive); - ResetProgramCounter(actor); + ResetProgramCounter(stateMachine); } - /// - internal override void NotifyWaitTask(Actor actor, Task task) + /// + /// Notifies that a state machine is waiting for the specified task to complete. + /// + internal void NotifyWaitTask(StateMachine stateMachine, Task task) { - Assert(task != null, "{0} is waiting for a null task to complete.", actor.Id); + Assert(task != null, "{0} is waiting for a null task to complete.", stateMachine.Id); var finished = task.IsCompleted || task.IsCanceled || task.IsFaulted; if (!finished) @@ -927,86 +1132,140 @@ internal override void NotifyWaitTask(Actor actor, Task task) Assert(finished, "Controlled task '{0}' is trying to wait for an uncontrolled task or awaiter to complete. Please " + "make sure to avoid using concurrency APIs (e.g. 'Task.Run', 'Task.Delay' or 'Task.Yield' from " + - "the 'System.Threading.Tasks' namespace) inside actor handlers. If you are using external libraries " + + "the 'System.Threading.Tasks' namespace) inside state machine handlers. If you are using external libraries " + "that are executing concurrently, you will need to mock them during testing.", Task.CurrentId); } } - /// - internal override void NotifyWaitEvent(Actor actor, IEnumerable eventTypes) + /// + /// Notifies that a state machine is waiting to receive an event of one of the specified types. + /// + internal void NotifyWaitEvent(StateMachine stateMachine, IEnumerable eventTypes) { - var stateName = actor is StateMachine stateMachine ? stateMachine.CurrentStateName : null; - var op = Scheduler.GetOperationWithId(actor.Id.Value); + var stateName = stateMachine.CurrentStateName; + var op = Scheduler.GetOperationWithId(stateMachine.Id.Value); op.OnWaitEvent(eventTypes); var eventWaitTypesArray = eventTypes.ToArray(); if (eventWaitTypesArray.Length == 1) { - LogWriter.LogWaitEvent(actor.Id, stateName, eventWaitTypesArray[0]); + LogWriter.LogWaitEvent(stateMachine.Id, stateName, eventWaitTypesArray[0]); } else { - LogWriter.LogWaitEvent(actor.Id, stateName, eventWaitTypesArray); + LogWriter.LogWaitEvent(stateMachine.Id, stateName, eventWaitTypesArray); } Scheduler.ScheduleNextEnabledOperation(AsyncOperationType.Join); - ResetProgramCounter(actor); + ResetProgramCounter(stateMachine); } - /// - internal override void NotifyEnteredState(StateMachine stateMachine) + /// + /// Notifies that a state machine entered a state. + /// + internal void NotifyEnteredState(StateMachine stateMachine) { var stateName = stateMachine.CurrentStateName; LogWriter.LogStateTransition(stateMachine.Id, stateName, isEntry: true); } - /// - internal override void NotifyExitedState(StateMachine stateMachine) + /// + /// Notifies that a state machine exited a state. + /// + internal void NotifyExitedState(StateMachine stateMachine) { LogWriter.LogStateTransition(stateMachine.Id, stateMachine.CurrentStateName, isEntry: false); } - /// - internal override void NotifyInvokedOnEntryAction(StateMachine stateMachine, MethodInfo action, Event receivedEvent) + /// + /// Notifies that a state machine invoked an action. + /// + internal void NotifyInvokedOnEntryAction(StateMachine stateMachine, MethodInfo action, Event receivedEvent) { var stateName = stateMachine.CurrentStateName; LogWriter.LogExecuteAction(stateMachine.Id, stateName, stateName, action.Name); } - /// - internal override void NotifyInvokedOnExitAction(StateMachine stateMachine, MethodInfo action, Event receivedEvent) + /// + /// Notifies that a state machine invoked an action. + /// + internal void NotifyInvokedOnExitAction(StateMachine stateMachine, MethodInfo action, Event receivedEvent) { var stateName = stateMachine.CurrentStateName; LogWriter.LogExecuteAction(stateMachine.Id, stateName, stateName, action.Name); } - /// - internal override void NotifyEnteredState(Monitor monitor) + /// + /// Notifies that a monitor entered a state. + /// + internal void NotifyEnteredState(Monitor monitor) { var monitorState = monitor.CurrentStateName; LogWriter.LogMonitorStateTransition(monitor.GetType().FullName, monitorState, true, monitor.GetHotState()); } - /// - internal override void NotifyExitedState(Monitor monitor) + /// + /// Notifies that a monitor exited a state. + /// + internal void NotifyExitedState(Monitor monitor) { LogWriter.LogMonitorStateTransition(monitor.GetType().FullName, monitor.CurrentStateName, false, monitor.GetHotState()); } - /// - internal override void NotifyInvokedAction(Monitor monitor, MethodInfo action, string stateName, Event receivedEvent) + /// + /// Notifies that a monitor invoked an action. + /// + internal void NotifyInvokedAction(Monitor monitor, MethodInfo action, string stateName, Event receivedEvent) { LogWriter.LogMonitorExecuteAction(monitor.GetType().FullName, stateName, action.Name); } - /// - internal override void NotifyRaisedEvent(Monitor monitor, Event e) + /// + /// Notifies that a monitor raised an . + /// + internal void NotifyRaisedEvent(Monitor monitor, Event e) { var monitorState = monitor.CurrentStateName; LogWriter.LogMonitorRaiseEvent(monitor.GetType().FullName, monitorState, e); } + + /// + /// Notifies that a monitor found an error. + /// + internal void NotifyMonitorError(Monitor monitor) + { + if (CheckerConfiguration.IsVerbose) + { + var monitorState = monitor.CurrentStateNameWithTemperature; + LogWriter.LogMonitorError(monitor.GetType().FullName, monitorState, monitor.GetHotState()); + } + } + + /// + /// Tries to handle the specified dropped . + /// + internal void TryHandleDroppedEvent(Event e, StateMachineId id) => OnEventDropped?.Invoke(e, id); + + /// + public TextWriter SetLogger(TextWriter logger) => LogWriter.SetLogger(logger); + + /// + /// Sets the JsonLogger in LogWriter.cs + /// + /// jsonLogger instance + public void SetJsonLogger(JsonWriter jsonLogger) => LogWriter.SetJsonLogger(jsonLogger); + + /// + /// Use this method to register an . + /// + public void RegisterLog(IControlledRuntimeLog log) => LogWriter.RegisterLog(log); + + /// + /// Use this method to unregister a previously registered . + /// + public void RemoveLog(IControlledRuntimeLog log) => LogWriter.RemoveLog(log); /// /// Get the coverage graph information (if any). This information is only available @@ -1018,13 +1277,13 @@ public CoverageInfo GetCoverageInfo() var result = CoverageInfo; if (result != null) { - var builder = LogWriter.GetLogsOfType().FirstOrDefault(); + var builder = LogWriter.GetLogsOfType().FirstOrDefault(); if (builder != null) { result.CoverageGraph = builder.SnapshotGraph(CheckerConfiguration.IsDgmlBugGraph); } - var eventCoverage = LogWriter.GetLogsOfType().FirstOrDefault(); + var eventCoverage = LogWriter.GetLogsOfType().FirstOrDefault(); if (eventCoverage != null) { result.EventInfo = eventCoverage.EventCoverage; @@ -1035,41 +1294,28 @@ public CoverageInfo GetCoverageInfo() } /// - /// Reports actors that are to be covered in coverage report. + /// Reports state machines that are to be covered in coverage report. /// - private void ReportActivityCoverageOfActor(Actor actor) + private void ReportActivityCoverageOfStateMachine(StateMachine stateMachine) { - var name = actor.GetType().FullName; + var name = stateMachine.GetType().FullName; if (CoverageInfo.IsMachineDeclared(name)) { return; } - - if (actor is StateMachine stateMachine) + + // Fetch states. + var states = stateMachine.GetAllStates(); + foreach (var state in states) { - // Fetch states. - var states = stateMachine.GetAllStates(); - foreach (var state in states) - { - CoverageInfo.DeclareMachineState(name, state); - } - - // Fetch registered events. - var pairs = stateMachine.GetAllStateEventPairs(); - foreach (var tup in pairs) - { - CoverageInfo.DeclareStateEvent(name, tup.Item1, tup.Item2); - } + CoverageInfo.DeclareMachineState(name, state); } - else - { - var fakeStateName = actor.GetType().Name; - CoverageInfo.DeclareMachineState(name, fakeStateName); - foreach (var eventId in actor.GetAllRegisteredEvents()) - { - CoverageInfo.DeclareStateEvent(name, fakeStateName, eventId); - } + // Fetch registered events. + var pairs = stateMachine.GetAllStateEventPairs(); + foreach (var tup in pairs) + { + CoverageInfo.DeclareStateEvent(name, tup.Item1, tup.Item2); } } @@ -1102,17 +1348,13 @@ private void ReportActivityCoverageOfMonitor(Monitor monitor) } /// - /// Resets the program counter of the specified actor. + /// Resets the program counter of the specified stateMachine. /// - private static void ResetProgramCounter(Actor actor) + private static void ResetProgramCounter(StateMachine stateMachine) { - if (actor is StateMachine stateMachine) - { - (stateMachine.Manager as MockStateMachineManager).ProgramCounter = 0; - } - else if (actor != null) + if (stateMachine != null) { - (actor.Manager as MockActorManager).ProgramCounter = 0; + (stateMachine.Manager as StateMachineManager).ProgramCounter = 0; } } @@ -1129,9 +1371,9 @@ internal int GetProgramState() foreach (var operation in Scheduler.GetRegisteredOperations().OrderBy(op => op.Id)) { - if (operation is ActorOperation actorOperation) + if (operation is StateMachineOperation stateMachineOperation) { - hash *= 31 + actorOperation.Actor.GetHashedState(); + hash *= 31 + stateMachineOperation.StateMachine.GetHashedState(); } } @@ -1144,9 +1386,12 @@ internal int GetProgramState() } } - /// + /// + /// Throws an exception + /// containing the specified exception. + /// [DebuggerStepThrough] - internal override void WrapAndThrowException(Exception exception, string s, params object[] args) + internal void WrapAndThrowException(Exception exception, string s, params object[] args) { var msg = string.Format(CultureInfo.InvariantCulture, s, args); var message = string.Format(CultureInfo.InvariantCulture, @@ -1159,7 +1404,7 @@ internal override void WrapAndThrowException(Exception exception, string s, para } /// - /// Waits until all actors have finished execution. + /// Waits until all stateMachines have finished execution. /// [DebuggerStepThrough] internal async Task WaitAsync() @@ -1167,9 +1412,16 @@ internal async Task WaitAsync() await Scheduler.WaitAsync(); IsRunning = false; } + + /// + /// Terminates the runtime and notifies each active state machine to halt execution. + /// + public void Stop() => IsRunning = false; - /// - protected internal override void RaiseOnFailureEvent(Exception exception) + /// + /// Raises the event with the specified . + /// + internal void RaiseOnFailureEvent(Exception exception) { if (exception is ExecutionCanceledException || (exception is ActionExceptionFilterException ae && ae.InnerException is ExecutionCanceledException)) @@ -1178,19 +1430,35 @@ protected internal override void RaiseOnFailureEvent(Exception exception) return; } - base.RaiseOnFailureEvent(exception); + OnFailure?.Invoke(exception); } - /// + /// + /// Disposes runtime resources. + /// [DebuggerStepThrough] - protected override void Dispose(bool disposing) + void Dispose(bool disposing) { if (disposing) { Monitors.Clear(); + StateMachineMap.Clear(); } - base.Dispose(disposing); + if (disposing) + { + OperationIdCounter = 0; + } + } + + /// + /// Disposes runtime resources. + /// + [DebuggerStepThrough] + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); } } } \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Runtime/OnFailureHandler.cs b/Src/PChecker/CheckerCore/SystematicTesting/OnFailureHandler.cs similarity index 64% rename from Src/PChecker/CheckerCore/Runtime/OnFailureHandler.cs rename to Src/PChecker/CheckerCore/SystematicTesting/OnFailureHandler.cs index 4c2e7f36bf..679d6d5dbd 100644 --- a/Src/PChecker/CheckerCore/Runtime/OnFailureHandler.cs +++ b/Src/PChecker/CheckerCore/SystematicTesting/OnFailureHandler.cs @@ -3,10 +3,10 @@ using System; -namespace PChecker.Runtime +namespace PChecker.SystematicTesting { /// - /// Handles the event. + /// Handles the event. /// public delegate void OnFailureHandler(Exception ex); } \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/SystematicTesting/OperationScheduler.cs b/Src/PChecker/CheckerCore/SystematicTesting/OperationScheduler.cs index e21e6770e2..718118e5f6 100644 --- a/Src/PChecker/CheckerCore/SystematicTesting/OperationScheduler.cs +++ b/Src/PChecker/CheckerCore/SystematicTesting/OperationScheduler.cs @@ -477,7 +477,7 @@ internal void CheckNoExternalConcurrencyUsed() NotifyAssertionFailure(string.Format(CultureInfo.InvariantCulture, "Uncontrolled task '{0}' invoked a runtime method. Please make sure to avoid using concurrency APIs " + "(e.g. 'Task.Run', 'Task.Delay' or 'Task.Yield' from the 'System.Threading.Tasks' namespace) inside " + - "actor handlers or controlled tasks. If you are using external libraries that are executing concurrently, " + + "state machine handlers or controlled tasks. If you are using external libraries that are executing concurrently, " + "you will need to mock them during testing.", Task.CurrentId.HasValue ? Task.CurrentId.Value.ToString() : "")); } diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Operations/ActorOperation.cs b/Src/PChecker/CheckerCore/SystematicTesting/Operations/StateMachineOperation.cs similarity index 77% rename from Src/PChecker/CheckerCore/SystematicTesting/Operations/ActorOperation.cs rename to Src/PChecker/CheckerCore/SystematicTesting/Operations/StateMachineOperation.cs index a6a43aeb26..9d421c910b 100644 --- a/Src/PChecker/CheckerCore/SystematicTesting/Operations/ActorOperation.cs +++ b/Src/PChecker/CheckerCore/SystematicTesting/Operations/StateMachineOperation.cs @@ -4,31 +4,31 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using PChecker.Actors; +using PChecker.Runtime.StateMachines; namespace PChecker.SystematicTesting.Operations { /// - /// Contains information about an asynchronous actor operation + /// Contains information about an asynchronous state machine operation /// that can be controlled during testing. /// [DebuggerStepThrough] - internal sealed class ActorOperation : AsyncOperation + internal sealed class StateMachineOperation : AsyncOperation { /// - /// The actor that executes this operation. + /// The state machine that executes this operation. /// - internal readonly Actor Actor; + internal readonly StateMachine StateMachine; /// /// Unique id of the operation. /// - public override ulong Id => Actor.Id.Value; + public override ulong Id => StateMachine.Id.Value; /// /// Unique name of the operation. /// - public override string Name => Actor.Id.Name; + public override string Name => StateMachine.Id.Name; /// /// Set of events that this operation is waiting to receive. Receiving @@ -44,12 +44,12 @@ internal sealed class ActorOperation : AsyncOperation internal bool SkipNextReceiveSchedulingPoint; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - internal ActorOperation(Actor actor) + internal StateMachineOperation(StateMachine stateMachine) : base() { - Actor = actor; + StateMachine = stateMachine; EventDependencies = new HashSet(); SkipNextReceiveSchedulingPoint = false; } diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Liveness/LivenessCheckingStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Liveness/LivenessCheckingStrategy.cs index 94976da6c3..4bae9fc198 100644 --- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Liveness/LivenessCheckingStrategy.cs +++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Liveness/LivenessCheckingStrategy.cs @@ -2,7 +2,7 @@ // Licensed under the MIT License. using System.Collections.Generic; -using PChecker.Specifications.Monitors; +using PChecker.Runtime.Specifications; using PChecker.SystematicTesting.Operations; namespace PChecker.SystematicTesting.Strategies.Liveness diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Liveness/TemperatureCheckingStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Liveness/TemperatureCheckingStrategy.cs index a81154746f..f8cfa2a1b3 100644 --- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Liveness/TemperatureCheckingStrategy.cs +++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Liveness/TemperatureCheckingStrategy.cs @@ -2,7 +2,7 @@ // Licensed under the MIT License. using System.Collections.Generic; -using PChecker.Specifications.Monitors; +using PChecker.Runtime.Specifications; using PChecker.SystematicTesting.Operations; namespace PChecker.SystematicTesting.Strategies.Liveness diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Special/ReplayStrategy.cs b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Special/ReplayStrategy.cs index 47be1170d2..12bfb858af 100644 --- a/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Special/ReplayStrategy.cs +++ b/Src/PChecker/CheckerCore/SystematicTesting/Strategies/Special/ReplayStrategy.cs @@ -21,7 +21,7 @@ internal sealed class ReplayStrategy : ISchedulingStrategy private readonly CheckerConfiguration _checkerConfiguration; /// - /// The Coyote program schedule trace. + /// The program schedule trace. /// private readonly ScheduleTrace ScheduleTrace; diff --git a/Src/PChecker/CheckerCore/SystematicTesting/TaskController.cs b/Src/PChecker/CheckerCore/SystematicTesting/TaskController.cs index 7869bfb6f0..c09e99ead6 100644 --- a/Src/PChecker/CheckerCore/SystematicTesting/TaskController.cs +++ b/Src/PChecker/CheckerCore/SystematicTesting/TaskController.cs @@ -58,7 +58,7 @@ public Task ScheduleAction(Action action, System.Threading.Tasks.Task predecesso { // Update the current asynchronous control flow with the current runtime instance, // allowing future retrieval in the same asynchronous call stack. - CoyoteRuntime.AssignAsyncControlFlowRuntime(Runtime); + ControlledRuntime.AssignAsyncControlFlowRuntime(Runtime); OperationScheduler.StartOperation(op); if (predecessor != null) @@ -118,7 +118,7 @@ public Task ScheduleFunction(Func function, System.Threading.Tasks.Task pr { // Update the current asynchronous control flow with the current runtime instance, // allowing future retrieval in the same asynchronous call stack. - CoyoteRuntime.AssignAsyncControlFlowRuntime(Runtime); + ControlledRuntime.AssignAsyncControlFlowRuntime(Runtime); OperationScheduler.StartOperation(op); if (predecessor != null) @@ -177,7 +177,7 @@ public Tasks.Task ScheduleFunction(Func> f { // Update the current asynchronous control flow with the current runtime instance, // allowing future retrieval in the same asynchronous call stack. - CoyoteRuntime.AssignAsyncControlFlowRuntime(Runtime); + ControlledRuntime.AssignAsyncControlFlowRuntime(Runtime); OperationScheduler.StartOperation(op); if (predecessor != null) @@ -235,7 +235,7 @@ public Tasks.Task ScheduleDelegate(Delegate work, System.Threa { // Update the current asynchronous control flow with the current runtime instance, // allowing future retrieval in the same asynchronous call stack. - CoyoteRuntime.AssignAsyncControlFlowRuntime(Runtime); + ControlledRuntime.AssignAsyncControlFlowRuntime(Runtime); OperationScheduler.StartOperation(op); if (predecessor != null) diff --git a/Src/PChecker/CheckerCore/SystematicTesting/TestAttributes.cs b/Src/PChecker/CheckerCore/SystematicTesting/TestAttributes.cs index 47748a5e10..0124cf26d9 100644 --- a/Src/PChecker/CheckerCore/SystematicTesting/TestAttributes.cs +++ b/Src/PChecker/CheckerCore/SystematicTesting/TestAttributes.cs @@ -7,7 +7,7 @@ namespace PChecker.SystematicTesting { /// /// Attribute for declaring the entry point to - /// a Coyote program test. + /// a program test. /// [AttributeUsage(AttributeTargets.Method)] public sealed class TestAttribute : Attribute @@ -43,8 +43,8 @@ public sealed class TestIterationDisposeAttribute : Attribute /// /// Attribute for declaring the factory method that creates - /// the Coyote testing runtime. This is an advanced feature, - /// only to be used for replacing the original Coyote testing + /// the testing runtime. This is an advanced feature, + /// only to be used for replacing the original testing /// runtime with an alternative implementation. /// [AttributeUsage(AttributeTargets.Method)] diff --git a/Src/PChecker/CheckerCore/SystematicTesting/TestMethodInfo.cs b/Src/PChecker/CheckerCore/SystematicTesting/TestMethodInfo.cs index c7df5035c7..a623fd17d3 100644 --- a/Src/PChecker/CheckerCore/SystematicTesting/TestMethodInfo.cs +++ b/Src/PChecker/CheckerCore/SystematicTesting/TestMethodInfo.cs @@ -6,7 +6,6 @@ using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; -using PChecker.Actors; using PChecker.IO.Debugging; using PChecker.Runtime; using PChecker.Tasks; @@ -164,10 +163,10 @@ private static (Delegate testMethod, string testName) GetTestMethod(Assembly ass testMethod.GetCustomAttribute(typeof(AsyncStateMachineAttribute)) != null; var hasNoInputParameters = testParams.Length is 0; - var hasActorInputParameters = testParams.Length is 1 && testParams[0].ParameterType == typeof(IActorRuntime); - var hasTaskInputParameters = testParams.Length is 1 && testParams[0].ParameterType == typeof(ICoyoteRuntime); + var hasStateMachineInputParameters = testParams.Length is 1 && testParams[0].ParameterType == typeof(ControlledRuntime); + var hasTaskInputParameters = testParams.Length is 1 && testParams[0].ParameterType == typeof(ControlledRuntime); - if (!((hasVoidReturnType || hasAsyncReturnType) && (hasNoInputParameters || hasActorInputParameters || hasTaskInputParameters) && + if (!((hasVoidReturnType || hasAsyncReturnType) && (hasNoInputParameters || hasStateMachineInputParameters || hasTaskInputParameters) && !testMethod.IsAbstract && !testMethod.IsVirtual && !testMethod.IsConstructor && !testMethod.ContainsGenericParameters && testMethod.IsPublic && testMethod.IsStatic)) { @@ -176,27 +175,27 @@ private static (Delegate testMethod, string testName) GetTestMethod(Assembly ass $" [{typeof(TestAttribute).FullName}]\n" + $" public static void {testMethod.Name}() {{ ... }}\n\n" + $" [{typeof(TestAttribute).FullName}]\n" + - $" public static void {testMethod.Name}(ICoyoteRuntime runtime) {{ ... }}\n\n" + + $" public static void {testMethod.Name}(ControlledRuntime runtime) {{ ... }}\n\n" + $" [{typeof(TestAttribute).FullName}]\n" + - $" public static void {testMethod.Name}(IActorRuntime runtime) {{ ... }}\n\n" + + $" public static void {testMethod.Name}(ControlledRuntime runtime) {{ ... }}\n\n" + $" [{typeof(TestAttribute).FullName}]\n" + $" public static async {typeof(Task).FullName} {testMethod.Name}() {{ ... await ... }}\n\n" + $" [{typeof(TestAttribute).FullName}]\n" + - $" public static async {typeof(Task).FullName} {testMethod.Name}(ICoyoteRuntime runtime) {{ ... await ... }}\n\n" + + $" public static async {typeof(Task).FullName} {testMethod.Name}(ControlledRuntime runtime) {{ ... await ... }}\n\n" + $" [{typeof(TestAttribute).FullName}]\n" + - $" public static async {typeof(Task).FullName} {testMethod.Name}(IActorRuntime runtime) {{ ... await ... }}"); + $" public static async {typeof(Task).FullName} {testMethod.Name}(ControlledRuntime runtime) {{ ... await ... }}"); } Delegate test; if (hasAsyncReturnType) { - if (hasActorInputParameters) + if (hasStateMachineInputParameters) { - test = Delegate.CreateDelegate(typeof(Func), testMethod); + test = Delegate.CreateDelegate(typeof(Func), testMethod); } else if (hasTaskInputParameters) { - test = Delegate.CreateDelegate(typeof(Func), testMethod); + test = Delegate.CreateDelegate(typeof(Func), testMethod); } else { @@ -205,13 +204,13 @@ private static (Delegate testMethod, string testName) GetTestMethod(Assembly ass } else { - if (hasActorInputParameters) + if (hasStateMachineInputParameters) { - test = Delegate.CreateDelegate(typeof(Action), testMethod); + test = Delegate.CreateDelegate(typeof(Action), testMethod); } else if (hasTaskInputParameters) { - test = Delegate.CreateDelegate(typeof(Action), testMethod); + test = Delegate.CreateDelegate(typeof(Action), testMethod); } else { diff --git a/Src/PChecker/CheckerCore/SystematicTesting/TestReport.cs b/Src/PChecker/CheckerCore/SystematicTesting/TestReport.cs index b729f3e0ed..24befbed6a 100644 --- a/Src/PChecker/CheckerCore/SystematicTesting/TestReport.cs +++ b/Src/PChecker/CheckerCore/SystematicTesting/TestReport.cs @@ -11,7 +11,7 @@ namespace PChecker.SystematicTesting { /// - /// Class implementing the Coyote test report. + /// Class implementing the test report. /// [DataContract] public class TestReport diff --git a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs index b753ad0298..672d54433a 100644 --- a/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs +++ b/Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs @@ -14,14 +14,13 @@ using System.Threading; using System.Threading.Tasks; using System.Xml; -using PChecker.Actors; -using PChecker.Actors.Logging; using PChecker.Coverage; using PChecker.IO; using PChecker.IO.Debugging; using PChecker.IO.Logging; using PChecker.Random; using PChecker.Runtime; +using PChecker.Runtime.Logging; using PChecker.SystematicTesting.Strategies; using PChecker.SystematicTesting.Strategies.Exhaustive; using PChecker.SystematicTesting.Strategies.Probabilistic; @@ -72,9 +71,6 @@ public class TestingEngine /// /// The installed logger. /// - /// - /// See Logging for more information. - /// private TextWriter Logger; /// @@ -133,7 +129,7 @@ public override void Write(Utf8JsonWriter writer, Encoding value, JsonSerializer public TestReport TestReport { get; set; } /// - /// A graph of the actors, state machines and events of a single test schedule. + /// A graph of the state machines, state machines and events of a single test schedule. /// private Graph Graph; @@ -213,17 +209,11 @@ public static TestingEngine Create(CheckerConfiguration checkerConfiguration, As /// public static TestingEngine Create(CheckerConfiguration checkerConfiguration, Action test) => new TestingEngine(checkerConfiguration, test); - + /// /// Creates a new systematic testing engine. /// - public static TestingEngine Create(CheckerConfiguration checkerConfiguration, Action test) => - new TestingEngine(checkerConfiguration, test); - - /// - /// Creates a new systematic testing engine. - /// - public static TestingEngine Create(CheckerConfiguration checkerConfiguration, Action test) => + public static TestingEngine Create(CheckerConfiguration checkerConfiguration, Action test) => new TestingEngine(checkerConfiguration, test); /// @@ -235,13 +225,7 @@ public static TestingEngine Create(CheckerConfiguration checkerConfiguration, Fu /// /// Creates a new systematic testing engine. /// - public static TestingEngine Create(CheckerConfiguration checkerConfiguration, Func test) => - new TestingEngine(checkerConfiguration, test); - - /// - /// Creates a new systematic testing engine. - /// - public static TestingEngine Create(CheckerConfiguration checkerConfiguration, Func test) => + internal static TestingEngine Create(CheckerConfiguration checkerConfiguration, Func test) => new TestingEngine(checkerConfiguration, test); /// @@ -381,7 +365,7 @@ public void Run() } - Error.ReportAndExit("Exception thrown during testing outside the context of an actor, " + + Error.ReportAndExit("Exception thrown during testing outside the context of an state machine, " + "possibly in a test method. Please use /debug /v:2 to print more information."); } } @@ -530,7 +514,7 @@ private void RunNextIteration(int schedule) try { // Creates a new instance of the controlled runtime. - runtime = new ControlledRuntime(_checkerConfiguration, Strategy, RandomValueGenerator); + runtime = new ControlledRuntime(_checkerConfiguration, Strategy); // Always output a json log of the error JsonLogger = new JsonWriter(); @@ -742,13 +726,6 @@ public void TryEmitTraces(string directory, string file) JsonSerializer.Serialize(jsonStreamFile, JsonLogger.Logs, jsonSerializerConfig); } - if (Graph != null) - { - var graphPath = directory + file + "_" + index + ".dgml"; - Graph.SaveDgml(graphPath, true); - Logger.WriteLine($"..... Writing {graphPath}"); - } - if (!_checkerConfiguration.PerformFullExploration) { // Emits the reproducable trace, if it exists. @@ -778,9 +755,9 @@ public void RegisterPerIterationCallBack(Action callback) /// private void InitializeCustomLogging(ControlledRuntime runtime) { - if (!string.IsNullOrEmpty(_checkerConfiguration.CustomActorRuntimeLogType)) + if (!string.IsNullOrEmpty(_checkerConfiguration.CustomStateMachineRuntimeLogType)) { - var log = Activate(_checkerConfiguration.CustomActorRuntimeLogType); + var log = Activate(_checkerConfiguration.CustomStateMachineRuntimeLogType); if (log != null) { runtime.RegisterLog(log); @@ -790,7 +767,7 @@ private void InitializeCustomLogging(ControlledRuntime runtime) if (_checkerConfiguration.IsDgmlGraphEnabled || _checkerConfiguration.ReportActivityCoverage) { // Registers an activity coverage graph builder. - runtime.RegisterLog(new ActorRuntimeLogGraphBuilder(false) + runtime.RegisterLog(new ControlledRuntimeLogGraphBuilder(false) { CollapseMachineInstances = _checkerConfiguration.ReportActivityCoverage }); @@ -799,13 +776,13 @@ private void InitializeCustomLogging(ControlledRuntime runtime) if (_checkerConfiguration.ReportActivityCoverage) { // Need this additional logger to get the event coverage report correct - runtime.RegisterLog(new ActorRuntimeLogEventCoverage()); + runtime.RegisterLog(new ControlledRuntimeLogEventCoverage()); } if (_checkerConfiguration.IsXmlLogEnabled) { XmlLog = new StringBuilder(); - runtime.RegisterLog(new ActorRuntimeLogXmlFormatter(XmlWriter.Create(XmlLog, + runtime.RegisterLog(new PCheckerLogXmlFormatter(XmlWriter.Create(XmlLog, new XmlWriterSettings() { Indent = true, IndentChars = " ", OmitXmlDeclaration = true }))); } } diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Traces/ScheduleStep.cs b/Src/PChecker/CheckerCore/SystematicTesting/Traces/ScheduleStep.cs index 59acffd098..ad1f5b936a 100644 --- a/Src/PChecker/CheckerCore/SystematicTesting/Traces/ScheduleStep.cs +++ b/Src/PChecker/CheckerCore/SystematicTesting/Traces/ScheduleStep.cs @@ -49,14 +49,14 @@ internal sealed class ScheduleStep /// /// Creates a schedule step. /// - internal static ScheduleStep CreateSchedulingChoice(int index, ulong scheduledActorId) + internal static ScheduleStep CreateSchedulingChoice(int index, ulong scheduledStateMachineId) { var scheduleStep = new ScheduleStep(); scheduleStep.Index = index; scheduleStep.Type = ScheduleStepType.SchedulingChoice; - scheduleStep.ScheduledOperationId = scheduledActorId; + scheduleStep.ScheduledOperationId = scheduledStateMachineId; scheduleStep.BooleanChoice = null; scheduleStep.IntegerChoice = null; diff --git a/Src/PChecker/CheckerCore/SystematicTesting/Traces/ScheduleTrace.cs b/Src/PChecker/CheckerCore/SystematicTesting/Traces/ScheduleTrace.cs index f4db754298..c039f66733 100644 --- a/Src/PChecker/CheckerCore/SystematicTesting/Traces/ScheduleTrace.cs +++ b/Src/PChecker/CheckerCore/SystematicTesting/Traces/ScheduleTrace.cs @@ -78,9 +78,9 @@ internal ScheduleTrace(string[] traceDump) /// /// Adds a scheduling choice. /// - internal void AddSchedulingChoice(ulong scheduledActorId) + internal void AddSchedulingChoice(ulong scheduledStateMachineId) { - var scheduleStep = ScheduleStep.CreateSchedulingChoice(Count, scheduledActorId); + var scheduleStep = ScheduleStep.CreateSchedulingChoice(Count, scheduledStateMachineId); Push(scheduleStep); } diff --git a/Src/PChecker/CheckerCore/Tasks/AsyncTaskMethodBuilder.cs b/Src/PChecker/CheckerCore/Tasks/AsyncTaskMethodBuilder.cs index ca915b4daa..6b55b888a1 100644 --- a/Src/PChecker/CheckerCore/Tasks/AsyncTaskMethodBuilder.cs +++ b/Src/PChecker/CheckerCore/Tasks/AsyncTaskMethodBuilder.cs @@ -84,15 +84,11 @@ private AsyncTaskMethodBuilder(TaskController taskManager) /// [DebuggerHidden] public static AsyncTaskMethodBuilder Create() - { - if (CoyoteRuntime.IsExecutionControlled) - { - return new AsyncTaskMethodBuilder(ControlledRuntime.Current.TaskController); - } - - return new AsyncTaskMethodBuilder(null); + { + return new AsyncTaskMethodBuilder(ControlledRuntime.Current.TaskController); } + /// /// Begins running the builder with the associated state machine. /// @@ -245,12 +241,7 @@ private AsyncTaskMethodBuilder(TaskController taskManager) [DebuggerHidden] public static AsyncTaskMethodBuilder Create() { - if (CoyoteRuntime.IsExecutionControlled) - { - return new AsyncTaskMethodBuilder(ControlledRuntime.Current.TaskController); - } - - return new AsyncTaskMethodBuilder(null); + return new AsyncTaskMethodBuilder(ControlledRuntime.Current.TaskController); } #pragma warning restore CA1000 // Do not declare static members on generic types diff --git a/Src/PChecker/CheckerCore/Tasks/Task.cs b/Src/PChecker/CheckerCore/Tasks/Task.cs index 261b063ab5..16f7480eae 100644 --- a/Src/PChecker/CheckerCore/Tasks/Task.cs +++ b/Src/PChecker/CheckerCore/Tasks/Task.cs @@ -165,12 +165,7 @@ public static Task FromException(Exception exception) => [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Task Run(Action action, CancellationToken cancellationToken) { - if (CoyoteRuntime.IsExecutionControlled) - { - return ControlledRuntime.Current.TaskController.ScheduleAction(action, null, cancellationToken); - } - - return new Task(null, SystemTasks.Task.Run(action, cancellationToken)); + return ControlledRuntime.Current.TaskController.ScheduleAction(action, null, cancellationToken); } /// @@ -193,12 +188,7 @@ public static Task Run(Action action, CancellationToken cancellationToken) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Task Run(Func function, CancellationToken cancellationToken) { - if (CoyoteRuntime.IsExecutionControlled) - { - return ControlledRuntime.Current.TaskController.ScheduleFunction(function, null, cancellationToken); - } - - return new Task(null, SystemTasks.Task.Run(async () => await function(), cancellationToken)); + return ControlledRuntime.Current.TaskController.ScheduleFunction(function, null, cancellationToken); } /// @@ -223,12 +213,7 @@ public static Task Run(Func function, CancellationToken cancellationToken) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Task Run(Func> function, CancellationToken cancellationToken) { - if (CoyoteRuntime.IsExecutionControlled) - { - return ControlledRuntime.Current.TaskController.ScheduleFunction(function, null, cancellationToken); - } - - return new Task(null, SystemTasks.Task.Run(async () => await function(), cancellationToken)); + return ControlledRuntime.Current.TaskController.ScheduleFunction(function, null, cancellationToken); } /// @@ -252,12 +237,7 @@ public static Task Run(Func> function, Cancellat [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Task Run(Func function, CancellationToken cancellationToken) { - if (CoyoteRuntime.IsExecutionControlled) - { - return ControlledRuntime.Current.TaskController.ScheduleDelegate(function, null, cancellationToken); - } - - return new Task(null, SystemTasks.Task.Run(function, cancellationToken)); + return ControlledRuntime.Current.TaskController.ScheduleDelegate(function, null, cancellationToken); } /// @@ -281,12 +261,7 @@ public static Task Run(Func function, CancellationTok [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Task Delay(int millisecondsDelay, CancellationToken cancellationToken) { - if (CoyoteRuntime.IsExecutionControlled) - { - return ControlledRuntime.Current.TaskController.ScheduleDelay(TimeSpan.FromMilliseconds(millisecondsDelay), cancellationToken); - } - - return new Task(null, SystemTasks.Task.Delay(millisecondsDelay, cancellationToken)); + return ControlledRuntime.Current.TaskController.ScheduleDelay(TimeSpan.FromMilliseconds(millisecondsDelay), cancellationToken); } /// @@ -312,12 +287,7 @@ public static Task Delay(int millisecondsDelay, CancellationToken cancellationTo [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Task Delay(TimeSpan delay, CancellationToken cancellationToken) { - if (CoyoteRuntime.IsExecutionControlled) - { - return ControlledRuntime.Current.TaskController.ScheduleDelay(delay, cancellationToken); - } - - return new Task(null, SystemTasks.Task.Delay(delay, cancellationToken)); + return ControlledRuntime.Current.TaskController.ScheduleDelay(delay, cancellationToken); } /// @@ -347,12 +317,7 @@ public static Task Delay(TimeSpan delay, CancellationToken cancellationToken) [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Task WhenAllTasksCompleteAsync(IEnumerable tasks) { - if (CoyoteRuntime.IsExecutionControlled) - { - return ControlledRuntime.Current.TaskController.WhenAllTasksCompleteAsync(tasks); - } - - return new Task(null, SystemTasks.Task.WhenAll(tasks.Select(t => t.InternalTask))); + return ControlledRuntime.Current.TaskController.WhenAllTasksCompleteAsync(tasks); } /// @@ -385,12 +350,7 @@ private static Task WhenAllTasksCompleteAsync(IEnumerable tasks) [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Task WhenAllTasksCompleteAsync(IEnumerable> tasks) { - if (CoyoteRuntime.IsExecutionControlled) - { - return ControlledRuntime.Current.TaskController.WhenAllTasksCompleteAsync(tasks); - } - - return new Task(null, SystemTasks.Task.WhenAll(tasks.Select(t => t.UncontrolledTask))); + return ControlledRuntime.Current.TaskController.WhenAllTasksCompleteAsync(tasks); } /// @@ -417,12 +377,7 @@ private static Task WhenAllTasksCompleteAsync(IEnumerable WhenAnyTaskCompletesAsync(IEnumerable tasks) { - if (CoyoteRuntime.IsExecutionControlled) - { - return ControlledRuntime.Current.TaskController.WhenAnyTaskCompletesAsync(tasks); - } - - return WhenAnyTaskCompletesInProductionAsync(tasks); + return ControlledRuntime.Current.TaskController.WhenAnyTaskCompletesAsync(tasks); } /// @@ -462,12 +417,7 @@ public static Task> WhenAny(IEnumerable> ta [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Task> WhenAnyTaskCompletesAsync(IEnumerable> tasks) { - if (CoyoteRuntime.IsExecutionControlled) - { - return ControlledRuntime.Current.TaskController.WhenAnyTaskCompletesAsync(tasks); - } - - return WhenAnyTaskCompletesInProductionAsync(tasks); + return ControlledRuntime.Current.TaskController.WhenAnyTaskCompletesAsync(tasks); } /// @@ -542,12 +492,7 @@ public static void WaitAll(Task[] tasks, CancellationToken cancellationToken) => [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool WaitAll(Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken) { - if (CoyoteRuntime.IsExecutionControlled) - { - return ControlledRuntime.Current.TaskController.WaitAllTasksComplete(tasks); - } - - return SystemTasks.Task.WaitAll(tasks.Select(t => t.UncontrolledTask).ToArray(), millisecondsTimeout, cancellationToken); + return ControlledRuntime.Current.TaskController.WaitAllTasksComplete(tasks); } /// @@ -612,12 +557,7 @@ public static int WaitAny(Task[] tasks, TimeSpan timeout) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int WaitAny(Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken) { - if (CoyoteRuntime.IsExecutionControlled) - { - return ControlledRuntime.Current.TaskController.WaitAnyTaskCompletes(tasks); - } - - return SystemTasks.Task.WaitAny(tasks.Select(t => t.UncontrolledTask).ToArray(), millisecondsTimeout, cancellationToken); + return ControlledRuntime.Current.TaskController.WaitAnyTaskCompletes(tasks); } /// @@ -626,12 +566,7 @@ public static int WaitAny(Task[] tasks, int millisecondsTimeout, CancellationTok [MethodImpl(MethodImplOptions.AggressiveInlining)] public static YieldAwaitable Yield() { - if (CoyoteRuntime.IsExecutionControlled) - { - return new YieldAwaitable(ControlledRuntime.Current.TaskController); - } - - return new YieldAwaitable(null); + return new YieldAwaitable(ControlledRuntime.Current.TaskController); } /// @@ -712,18 +647,7 @@ public TaskAwaiter GetAwaiter() /// public ConfiguredTaskAwaitable ConfigureAwait(bool continueOnCapturedContext) => new ConfiguredTaskAwaitable(TaskController, InternalTask, continueOnCapturedContext); - - /// - /// Injects a context switch point that can be systematically explored during testing. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void ExploreContextSwitch() - { - if (CoyoteRuntime.IsExecutionControlled) - { - ControlledRuntime.Current.ScheduleNextOperation(AsyncOperationType.Default); - } - } + /// /// Disposes the , releasing all of its unmanaged resources. diff --git a/Src/PChecker/CheckerCore/Tasks/TaskCompletionSource.cs b/Src/PChecker/CheckerCore/Tasks/TaskCompletionSource.cs index 2a109f05ca..dbd62072c1 100644 --- a/Src/PChecker/CheckerCore/Tasks/TaskCompletionSource.cs +++ b/Src/PChecker/CheckerCore/Tasks/TaskCompletionSource.cs @@ -22,8 +22,7 @@ public static class TaskCompletionSource /// /// The type of the result value assocatied with this task completion source. /// The task completion source. - public static TaskCompletionSource Create() => CoyoteRuntime.IsExecutionControlled ? - new Mock() : new TaskCompletionSource(new System.Threading.Tasks.TaskCompletionSource()); + public static TaskCompletionSource Create() => new Mock(); /// /// Mock implementation of that diff --git a/Src/PChecker/CheckerCore/Testing/TestingPortfolio.cs b/Src/PChecker/CheckerCore/Testing/TestingPortfolio.cs deleted file mode 100644 index e4f3b40693..0000000000 --- a/Src/PChecker/CheckerCore/Testing/TestingPortfolio.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace PChecker.Testing -{ - /// - /// A portfolio of systematic testing strategies. - /// - internal static class TestingPortfolio - { - /// - /// Configures the systematic testing strategy for the current testing process. - /// - internal static void ConfigureStrategyForCurrentProcess(CheckerConfiguration checkerConfiguration) - { - // random, fairpct[1], probabilistic[1], fairpct[5], probabilistic[2], fairpct[10], etc. - if (checkerConfiguration.TestingProcessId == 0) - { - checkerConfiguration.SchedulingStrategy = "random"; - } - else if (checkerConfiguration.TestingProcessId % 2 == 0) - { - checkerConfiguration.SchedulingStrategy = "probabilistic"; - checkerConfiguration.StrategyBound = (int)(checkerConfiguration.TestingProcessId / 2); - } - else if (checkerConfiguration.TestingProcessId == 1) - { - checkerConfiguration.SchedulingStrategy = "fairpct"; - checkerConfiguration.StrategyBound = 1; - } - else - { - checkerConfiguration.SchedulingStrategy = "fairpct"; - checkerConfiguration.StrategyBound = 5 * (int)((checkerConfiguration.TestingProcessId + 1) / 2); - } - } - } -} \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Testing/TestingProcess.cs b/Src/PChecker/CheckerCore/Testing/TestingProcess.cs index b43f6c552a..bbc45f0ca8 100644 --- a/Src/PChecker/CheckerCore/Testing/TestingProcess.cs +++ b/Src/PChecker/CheckerCore/Testing/TestingProcess.cs @@ -5,6 +5,7 @@ using System.IO; using System.Threading.Tasks; using PChecker.SystematicTesting; +using PChecker.Utilities; namespace PChecker.Testing { @@ -31,13 +32,23 @@ public class TestingProcess private readonly TestingEngine TestingEngine; /// - /// Creates a Coyote testing process. + /// Set if ctrl-c or ctrl-break occurred. + /// + public static bool IsProcessCanceled; + + /// + /// The testing profiler. + /// + private readonly Profiler Profiler; + + /// + /// Creates a testing process. /// public static TestingProcess Create(CheckerConfiguration checkerConfiguration) { return new TestingProcess(checkerConfiguration); } - + /// /// Get the current test report. /// @@ -50,11 +61,18 @@ public TestReport GetTestReport() private readonly TextWriter StdOut = Console.Out; /// - /// Runs the Coyote testing process. + /// Runs the testing process. /// public void Run() { + Profiler.StartMeasuringExecutionTime(); RunAsync().Wait(); + Profiler.StopMeasuringExecutionTime(); + if (!IsProcessCanceled) + { + // Merges and emits the test report. + EmitTestReport(); + } } private async Task RunAsync() @@ -90,11 +108,6 @@ private TestingProcess(CheckerConfiguration checkerConfiguration) { Name = Name + "." + checkerConfiguration.TestingProcessId; - if (checkerConfiguration.SchedulingStrategy is "portfolio") - { - TestingPortfolio.ConfigureStrategyForCurrentProcess(checkerConfiguration); - } - if (checkerConfiguration.RandomGeneratorSeed.HasValue) { checkerConfiguration.RandomGeneratorSeed = checkerConfiguration.RandomGeneratorSeed.Value + @@ -102,9 +115,11 @@ private TestingProcess(CheckerConfiguration checkerConfiguration) } checkerConfiguration.EnableColoredConsoleOutput = true; - + _checkerConfiguration = checkerConfiguration; TestingEngine = TestingEngine.Create(_checkerConfiguration); + Profiler = new Profiler(); + IsProcessCanceled = false; } @@ -120,5 +135,53 @@ private Task EmitTraces() TestingEngine.TryEmitTraces(_checkerConfiguration.OutputDirectory, file); return Task.CompletedTask; } + + /// + /// Emits the test report. + /// + private void EmitTestReport() + { + TestReport testReport = GetTestReport(); + if (testReport == null) + { + Environment.ExitCode = (int)ExitCode.InternalError; + return; + } + + if (_checkerConfiguration.ReportActivityCoverage) + { + Console.WriteLine($"... Emitting coverage report:"); + Reporter.EmitTestingCoverageReport(testReport); + } + + if (_checkerConfiguration.DebugActivityCoverage) + { + Console.WriteLine($"... Emitting debug coverage report:"); + Reporter.EmitTestingCoverageReport(testReport); + } + + Console.WriteLine(testReport.GetText(_checkerConfiguration, "...")); + + var file = Path.GetFileNameWithoutExtension(testReport.CheckerConfiguration.AssemblyToBeAnalyzed); + var directory = testReport.CheckerConfiguration.OutputDirectory; + var pintPath = directory + file + "_pchecker_summary.txt"; + Console.WriteLine($"..... Writing {pintPath}"); + File.WriteAllText(pintPath, testReport.GetSummaryText(Profiler)); + + Console.WriteLine($"... Elapsed {Profiler.GetElapsedTime()} sec."); + + if (testReport.InternalErrors.Count > 0) + { + Environment.ExitCode = (int)ExitCode.InternalError; + } + else if (testReport.NumOfFoundBugs > 0) + { + Environment.ExitCode = (int)ExitCode.BugFound; + } + else + { + Environment.ExitCode = (int)ExitCode.Success; + } + } } } \ No newline at end of file diff --git a/Src/PChecker/CheckerCore/Utilities/Profiler.cs b/Src/PChecker/CheckerCore/Utilities/Profiler.cs index ec9f031ee6..f9a6ba701d 100644 --- a/Src/PChecker/CheckerCore/Utilities/Profiler.cs +++ b/Src/PChecker/CheckerCore/Utilities/Profiler.cs @@ -7,7 +7,7 @@ namespace PChecker.Utilities { /// - /// The Coyote profiler. + /// The profiler. /// public class Profiler { diff --git a/Src/PChecker/CheckerCore/Utilities/Reporter.cs b/Src/PChecker/CheckerCore/Utilities/Reporter.cs index a3b80bfd69..e1a0b05d3a 100644 --- a/Src/PChecker/CheckerCore/Utilities/Reporter.cs +++ b/Src/PChecker/CheckerCore/Utilities/Reporter.cs @@ -9,7 +9,7 @@ namespace PChecker.Utilities { /// - /// The Coyote testing reporter. + /// The testing reporter. /// internal static class Reporter { @@ -17,22 +17,11 @@ internal static class Reporter /// Emits the testing coverage report. /// /// TestReport - /// Optional process id that produced the report - /// Is a debug report - internal static void EmitTestingCoverageReport(TestReport report, uint? processId = null, bool isDebug = false) + internal static void EmitTestingCoverageReport(TestReport report) { var file = Path.GetFileNameWithoutExtension(report.CheckerConfiguration.AssemblyToBeAnalyzed); - if (isDebug && processId != null) - { - file += "_" + processId; - } var directory = report.CheckerConfiguration.OutputDirectory; - if (isDebug) - { - directory += $"Debug{Path.DirectorySeparatorChar}"; - Directory.CreateDirectory(directory); - } EmitTestingCoverageOutputFiles(report, directory, file); } @@ -85,10 +74,6 @@ private static void EmitTestingCoverageOutputFiles(TestReport report, string dir var codeCoverageReporter = new ActivityCoverageReporter(report.CoverageInfo); var filePath = $"{directory}{file}"; - var graphFilePath = $"{filePath}.dgml"; - Console.WriteLine($"..... Writing {graphFilePath}"); - codeCoverageReporter.EmitVisualizationGraph(graphFilePath); - var coverageFilePath = $"{filePath}.coverage.txt"; Console.WriteLine($"..... Writing {coverageFilePath}"); codeCoverageReporter.EmitCoverageReport(coverageFilePath); diff --git a/Src/PCompiler/CompilerCore/Backend/CSharp/CSharpCodeGenerator.cs b/Src/PCompiler/CompilerCore/Backend/CSharp/CSharpCodeGenerator.cs index 3f5969ed3a..d7b935872c 100644 --- a/Src/PCompiler/CompilerCore/Backend/CSharp/CSharpCodeGenerator.cs +++ b/Src/PCompiler/CompilerCore/Backend/CSharp/CSharpCodeGenerator.cs @@ -119,7 +119,7 @@ private void WriteInitializeInterfaces(CompilationContext context, StringWriter { context.WriteLine(output, $"public class {context.Names.GetNameForDecl(iface)} : PMachineValue {{"); context.WriteLine(output, - $"public {context.Names.GetNameForDecl(iface)} (ActorId machine, List permissions) : base(machine, permissions) {{ }}"); + $"public {context.Names.GetNameForDecl(iface)} (StateMachineId machine, List permissions) : base(machine, permissions) {{ }}"); context.WriteLine(output, "}"); context.WriteLine(output); } @@ -150,18 +150,19 @@ private void WriteInitializeInterfaces(CompilationContext context, StringWriter private void WriteSourcePrologue(CompilationContext context, StringWriter output) { context.WriteLine(output, "using PChecker;"); - context.WriteLine(output, "using PChecker.Actors;"); - context.WriteLine(output, "using PChecker.Actors.Events;"); context.WriteLine(output, "using PChecker.Runtime;"); - context.WriteLine(output, "using PChecker.Specifications;"); + context.WriteLine(output, "using PChecker.Runtime.StateMachines;"); + context.WriteLine(output, "using PChecker.Runtime.Events;"); + context.WriteLine(output, "using PChecker.Runtime.Exceptions;"); + context.WriteLine(output, "using PChecker.Runtime.Values;"); + context.WriteLine(output, "using PChecker.Runtime.Specifications;"); + context.WriteLine(output, "using Monitor = PChecker.Runtime.Specifications.Monitor;"); context.WriteLine(output, "using System;"); + context.WriteLine(output, "using PChecker.SystematicTesting;"); context.WriteLine(output, "using System.Runtime;"); context.WriteLine(output, "using System.Collections.Generic;"); context.WriteLine(output, "using System.Linq;"); context.WriteLine(output, "using System.IO;"); - context.WriteLine(output, "using PChecker.PRuntime.Values;"); - context.WriteLine(output, "using PChecker.PRuntime;"); - context.WriteLine(output, "using PChecker.PRuntime.Exceptions;"); context.WriteLine(output, "using System.Threading;"); context.WriteLine(output, "using System.Threading.Tasks;"); context.WriteLine(output); @@ -206,7 +207,7 @@ private void WriteDecl(CompilationContext context, StringWriter output, IPDecl d break; - case PEvent pEvent: + case Event pEvent: if (!pEvent.IsBuiltIn) { WriteEvent(context, output, pEvent); @@ -263,7 +264,7 @@ private void WriteMonitor(CompilationContext context, StringWriter output, Machi WriteNameSpacePrologue(context, output); var declName = context.Names.GetNameForDecl(machine); - context.WriteLine(output, $"internal partial class {declName} : PMonitor"); + context.WriteLine(output, $"internal partial class {declName} : Monitor"); context.WriteLine(output, "{"); foreach (var field in machine.Fields) @@ -365,13 +366,13 @@ private void WriteInitializeEnums(CompilationContext context, StringWriter outpu //initialize the interfaces context.WriteLine(output, "public partial class PHelper {"); context.WriteLine(output, "public static void InitializeEnums() {"); - context.WriteLine(output, "PrtEnum.Clear();"); + context.WriteLine(output, "PEnum.Clear();"); foreach (var enumDecl in enums) { var enumElemNames = $"new [] {{{string.Join(",", enumDecl.Values.Select(e => $"\"{context.Names.GetNameForDecl(e)}\""))}}}"; var enumElemValues = $"new [] {{{string.Join(",", enumDecl.Values.Select(e => e.Value))}}}"; - context.WriteLine(output, $"PrtEnum.AddEnumElements({enumElemNames}, {enumElemValues});"); + context.WriteLine(output, $"PEnum.AddEnumElements({enumElemNames}, {enumElemValues});"); } context.WriteLine(output, "}"); @@ -385,9 +386,7 @@ private void WriteTestFunction(CompilationContext context, StringWriter output, { context.WriteLine(output); context.WriteLine(output, "[PChecker.SystematicTesting.Test]"); - context.WriteLine(output, "public static void Execute(IActorRuntime runtime) {"); - context.WriteLine(output, "runtime.RegisterLog(new PLogFormatter());"); - context.WriteLine(output, "runtime.RegisterLog(new PJsonFormatter());"); + context.WriteLine(output, "public static void Execute(ControlledRuntime runtime) {"); context.WriteLine(output, "PModule.runtime = runtime;"); context.WriteLine(output, "PHelper.InitializeInterfaces();"); context.WriteLine(output, "PHelper.InitializeEnums();"); @@ -396,7 +395,7 @@ private void WriteTestFunction(CompilationContext context, StringWriter output, context.WriteLine(output, "InitializeMonitorMap(runtime);"); context.WriteLine(output, "InitializeMonitorObserves();"); context.WriteLine(output, - $"runtime.CreateActor(typeof(_GodMachine), new _GodMachine.Config(typeof({main})));"); + $"runtime.CreateStateMachine(typeof({main}), \"{main}\");"); context.WriteLine(output, "}"); } @@ -418,7 +417,7 @@ private void WriteInitializeMonitorMap(CompilationContext context, StringWriter } } - context.WriteLine(output, "public static void InitializeMonitorMap(IActorRuntime runtime) {"); + context.WriteLine(output, "public static void InitializeMonitorMap(ControlledRuntime runtime) {"); context.WriteLine(output, "PModule.monitorMap.Clear();"); foreach (var machine in machineMap) { @@ -474,7 +473,7 @@ private void WriteInitializeLinkMap(CompilationContext context, StringWriter out context.WriteLine(output); } - private void WriteEvent(CompilationContext context, StringWriter output, PEvent pEvent) + private void WriteEvent(CompilationContext context, StringWriter output, Event pEvent) { WriteNameSpacePrologue(context, output); @@ -482,11 +481,11 @@ private void WriteEvent(CompilationContext context, StringWriter output, PEvent // initialize the payload type var payloadType = GetCSharpType(pEvent.PayloadType, true); - context.WriteLine(output, $"internal partial class {declName} : PEvent"); + context.WriteLine(output, $"internal partial class {declName} : Event"); context.WriteLine(output, "{"); context.WriteLine(output, $"public {declName}() : base() {{}}"); context.WriteLine(output, $"public {declName} ({payloadType} payload): base(payload)" + "{ }"); - context.WriteLine(output, $"public override IPrtValue Clone() {{ return new {declName}();}}"); + context.WriteLine(output, $"public override IPValue Clone() {{ return new {declName}();}}"); context.WriteLine(output, "}"); WriteNameSpaceEpilogue(context, output); @@ -497,7 +496,7 @@ private void WriteMachine(CompilationContext context, StringWriter output, Machi WriteNameSpacePrologue(context, output); var declName = context.Names.GetNameForDecl(machine); - context.WriteLine(output, $"internal partial class {declName} : PMachine"); + context.WriteLine(output, $"internal partial class {declName} : StateMachine"); context.WriteLine(output, "{"); foreach (var field in machine.Fields) @@ -508,14 +507,14 @@ private void WriteMachine(CompilationContext context, StringWriter output, Machi //create the constructor event var cTorType = GetCSharpType(machine.PayloadType, true); - context.Write(output, "public class ConstructorEvent : PEvent"); + context.Write(output, "public class ConstructorEvent : Event"); context.Write(output, "{"); - context.Write(output, $"public ConstructorEvent({cTorType} val) : base(val) {{ }}"); + context.Write(output, $"public ConstructorEvent(IPValue val) : base(val) {{ }}"); context.WriteLine(output, "}"); context.WriteLine(output); context.WriteLine(output, - $"protected override Event GetConstructorEvent(IPrtValue value) {{ return new ConstructorEvent(({cTorType})value); }}"); + $"protected override Event GetConstructorEvent(IPValue value) {{ return new ConstructorEvent((IPValue)value); }}"); // create the constructor to initialize the sends, creates and receives list WriteMachineConstructor(context, output, machine); @@ -560,17 +559,7 @@ private static void WriteMachineConstructor(CompilationContext context, StringWr private void WriteState(CompilationContext context, StringWriter output, State state) { - if (state.IsStart && !state.OwningMachine.IsSpec) - { - context.WriteLine(output, "[Start]"); - context.WriteLine(output, "[OnEntry(nameof(InitializeParametersFunction))]"); - context.WriteLine(output, - $"[OnEventGotoState(typeof(ConstructorEvent), typeof({context.Names.GetNameForDecl(state)}))]"); - context.WriteLine(output, "class __InitState__ : State { }"); - context.WriteLine(output); - } - - if (state.IsStart && state.OwningMachine.IsSpec) + if (state.IsStart) { context.WriteLine(output, "[Start]"); } @@ -686,7 +675,7 @@ private void WriteNamedFunctionWrapper(CompilationContext context, StringWriter context.WriteLine(output, $"{context.Names.GetNameForDecl(function.Owner)} currentMachine = this;"); } - var parameter = function.Signature.Parameters.Any() ? $"({GetCSharpType(function.Signature.ParameterTypes.First())})((PEvent)currentMachine_dequeuedEvent).Payload" : ""; + var parameter = function.Signature.Parameters.Any() ? $"({GetCSharpType(function.Signature.ParameterTypes.First())})((Event)currentMachine_dequeuedEvent).Payload" : ""; context.WriteLine(output, $"{awaitMethod}{functionName}({parameter});"); context.WriteLine(output, "}"); } @@ -735,7 +724,7 @@ private void WriteFunction(CompilationContext context, StringWriter output, Func { // for machine var seperator = functionParameters == "" ? "" : ", "; - var functionParameters_machine = functionParameters + string.Concat(seperator, "PMachine currentMachine"); + var functionParameters_machine = functionParameters + string.Concat(seperator, "StateMachine currentMachine"); context.WriteLine(output, $"public {staticKeyword}{asyncKeyword}{returnType} {functionName}({functionParameters_machine})"); WriteFunctionBody(context, output, function); @@ -743,7 +732,7 @@ private void WriteFunction(CompilationContext context, StringWriter output, Func // for monitor if (!(function.CanCreate || function.CanSend || function.IsNondeterministic || function.CanReceive)) { - var functionParameters_monitor = functionParameters + string.Concat(seperator, "PMonitor currentMachine"); + var functionParameters_monitor = functionParameters + string.Concat(seperator, "Monitor currentMachine"); context.WriteLine(output, $"public {staticKeyword}{asyncKeyword}{returnType} {functionName}({functionParameters_monitor})"); WriteFunctionBody(context, output, function); @@ -775,7 +764,7 @@ private void WriteFunctionBody(CompilationContext context, StringWriter output, { var param = function.Signature.Parameters.First(); context.WriteLine(output, - $"{GetCSharpType(param.Type)} {context.Names.GetNameForDecl(param)} = ({GetCSharpType(param.Type)})(gotoPayload ?? ((PEvent)currentMachine_dequeuedEvent).Payload);"); + $"{GetCSharpType(param.Type)} {context.Names.GetNameForDecl(param)} = ({GetCSharpType(param.Type)})(gotoPayload ?? ((Event)currentMachine_dequeuedEvent).Payload);"); context.WriteLine(output, "this.gotoPayload = null;"); } } @@ -801,7 +790,7 @@ private void WriteStmt(CompilationContext context, StringWriter output, Function { case AnnounceStmt announceStmt: context.Write(output, "currentMachine.Announce((Event)"); - WriteExpr(context, output, announceStmt.PEvent); + WriteExpr(context, output, announceStmt.Event); if (announceStmt.Payload != null) { context.Write(output, ", "); @@ -812,7 +801,7 @@ private void WriteStmt(CompilationContext context, StringWriter output, Function break; case AssertStmt assertStmt: - context.Write(output, "currentMachine.TryAssert("); + context.Write(output, "currentMachine.Assert("); WriteExpr(context, output, assertStmt.Assertion); context.Write(output, ","); context.Write(output, $"\"Assertion Failed: \" + "); @@ -871,7 +860,7 @@ private void WriteStmt(CompilationContext context, StringWriter output, Function if (ctorStmt.Arguments.Count > 1) { //create tuple from rvaluelist - context.Write(output, "new PrtTuple("); + context.Write(output, "new PTuple("); var septor = ""; foreach (var ctorExprArgument in ctorStmt.Arguments) { @@ -916,7 +905,7 @@ private void WriteStmt(CompilationContext context, StringWriter output, Function case GotoStmt gotoStmt: //last statement - context.Write(output, $"currentMachine.TryGotoState<{context.Names.GetNameForDecl(gotoStmt.State)}>("); + context.Write(output, $"currentMachine.RaiseGotoStateEvent<{context.Names.GetNameForDecl(gotoStmt.State)}>("); if (gotoStmt.Payload != null) { WriteExpr(context, output, gotoStmt.Payload); @@ -940,7 +929,7 @@ private void WriteStmt(CompilationContext context, StringWriter output, Function break; case AddStmt addStmt: - context.Write(output, "((PrtSet)"); + context.Write(output, "((PSet)"); WriteExpr(context, output, addStmt.Variable); context.Write(output, ").Add("); WriteExpr(context, output, addStmt.Value); @@ -949,7 +938,7 @@ private void WriteStmt(CompilationContext context, StringWriter output, Function case InsertStmt insertStmt: var isMap = PLanguageType.TypeIsOfKind(insertStmt.Variable.Type, TypeKind.Map); - var castOp = isMap ? "(PrtMap)" : "(PrtSeq)"; + var castOp = isMap ? "(PMap)" : "(PSeq)"; context.Write(output, $"({castOp}"); WriteExpr(context, output, insertStmt.Variable); if (isMap) @@ -994,14 +983,15 @@ private void WriteStmt(CompilationContext context, StringWriter output, Function case RaiseStmt raiseStmt: //last statement - context.Write(output, "currentMachine.TryRaiseEvent((Event)"); - WriteExpr(context, output, raiseStmt.PEvent); if (raiseStmt.Payload.Any()) { - context.Write(output, ", "); + WriteExpr(context, output, raiseStmt.Event); + context.Write(output, $".Payload = "); WriteExpr(context, output, raiseStmt.Payload.First()); + context.WriteLine(output, ";"); } - + context.Write(output, "currentMachine.RaiseEvent("); + WriteExpr(context, output, raiseStmt.Event); context.WriteLine(output, ");"); context.WriteLine(output, "return;"); break; @@ -1012,12 +1002,12 @@ private void WriteStmt(CompilationContext context, StringWriter output, Function .ToHashSet(); eventTypeNames.Add("PHalt"); // halt as a special case for receive var recvArgs = string.Join(", ", eventTypeNames.Select(name => $"typeof({name})")); - context.WriteLine(output, $"var {eventName} = await currentMachine.TryReceiveEvent({recvArgs});"); + context.WriteLine(output, $"var {eventName} = await currentMachine.ReceiveEventAsync({recvArgs});"); context.WriteLine(output, $"switch ({eventName}) {{"); // add halt as a special case if doesnt exist if (receiveStmt.Cases.All(kv => kv.Key.Name != "PHalt")) { - context.WriteLine(output,"case PHalt _hv: { currentMachine.TryRaiseEvent(_hv); break;} "); + context.WriteLine(output,"case PHalt _hv: { currentMachine.RaiseEvent(_hv); break;} "); } @@ -1052,10 +1042,10 @@ private void WriteStmt(CompilationContext context, StringWriter output, Function case RemoveStmt removeStmt: { var castOperation = PLanguageType.TypeIsOfKind(removeStmt.Variable.Type, TypeKind.Map) - ? "(PrtMap)" + ? "(PMap)" : PLanguageType.TypeIsOfKind(removeStmt.Variable.Type, TypeKind.Sequence) - ? "(PrtSeq)" - : "(PrtSet)"; + ? "(PSeq)" + : "(PSet)"; context.Write(output, $"({castOperation}"); switch (removeStmt.Variable.Type.Canonicalize()) { @@ -1105,36 +1095,17 @@ private void WriteStmt(CompilationContext context, StringWriter output, Function break; case SendStmt sendStmt: - context.Write(output, "currentMachine.TrySendEvent("); - WriteExpr(context, output, sendStmt.MachineExpr); - context.Write(output, ", (Event)"); - WriteExpr(context, output, sendStmt.Evt); - if (sendStmt.Arguments.Any()) { - context.Write(output, ", "); - if (sendStmt.Arguments.Count > 1) - { - //create tuple from rvaluelist - var argTypes = string.Join(",", - sendStmt.Arguments.Select(a => GetCSharpType(a.Type))); - var tupleType = $"PrtTuple"; - context.Write(output, $"new {tupleType}("); - var septor = ""; - foreach (var ctorExprArgument in sendStmt.Arguments) - { - context.Write(output, septor); - WriteExpr(context, output, ctorExprArgument); - septor = ","; - } - - context.Write(output, ")"); - } - else - { - WriteExpr(context, output, sendStmt.Arguments.First()); - } + WriteExpr(context, output, sendStmt.Evt); + context.Write(output, ".Payload = "); + WriteExpr(context, output, sendStmt.Arguments.First()); + context.WriteLine(output, ";"); } + context.Write(output, "currentMachine.SendEvent("); + WriteExpr(context, output, sendStmt.MachineExpr); + context.Write(output, ", (Event)"); + WriteExpr(context, output, sendStmt.Evt); context.WriteLine(output, ");"); break; @@ -1167,7 +1138,7 @@ private void WriteLValue(CompilationContext context, StringWriter output, IPExpr switch (lvalue) { case MapAccessExpr mapAccessExpr: - context.Write(output, "((PrtMap)"); + context.Write(output, "((PMap)"); WriteLValue(context, output, mapAccessExpr.MapExpr); context.Write(output, ")["); WriteExpr(context, output, mapAccessExpr.IndexExpr); @@ -1175,7 +1146,7 @@ private void WriteLValue(CompilationContext context, StringWriter output, IPExpr break; case SetAccessExpr setAccessExpr: - context.Write(output, "((PrtSet)"); + context.Write(output, "((PSet)"); WriteLValue(context, output, setAccessExpr.SetExpr); context.Write(output, ")["); WriteExpr(context, output, setAccessExpr.IndexExpr); @@ -1183,13 +1154,13 @@ private void WriteLValue(CompilationContext context, StringWriter output, IPExpr break; case NamedTupleAccessExpr namedTupleAccessExpr: - context.Write(output, "((PrtNamedTuple)"); + context.Write(output, "((PNamedTuple)"); WriteExpr(context, output, namedTupleAccessExpr.SubExpr); context.Write(output, $")[\"{namedTupleAccessExpr.FieldName}\"]"); break; case SeqAccessExpr seqAccessExpr: - context.Write(output, "((PrtSeq)"); + context.Write(output, "((PSeq)"); WriteLValue(context, output, seqAccessExpr.SeqExpr); context.Write(output, ")["); WriteExpr(context, output, seqAccessExpr.IndexExpr); @@ -1197,7 +1168,7 @@ private void WriteLValue(CompilationContext context, StringWriter output, IPExpr break; case TupleAccessExpr tupleAccessExpr: - context.Write(output, "((PrtTuple)"); + context.Write(output, "((PTuple)"); WriteExpr(context, output, tupleAccessExpr.SubExpr); context.Write(output, $")[{tupleAccessExpr.FieldNo}]"); break; @@ -1226,10 +1197,10 @@ private void WriteExpr(CompilationContext context, StringWriter output, IPExpr p if (binOpExpr.Operation == BinOpType.Eq || binOpExpr.Operation == BinOpType.Neq) { var negate = binOpExpr.Operation == BinOpType.Neq ? "!" : ""; - context.Write(output, $"({negate}PrtValues.SafeEquals("); + context.Write(output, $"({negate}PValues.SafeEquals("); if (PLanguageType.TypeIsOfKind(binOpExpr.Lhs.Type, TypeKind.Enum)) { - context.Write(output, "PrtValues.Box((long) "); + context.Write(output, "PValues.Box((long) "); WriteExpr(context, output, binOpExpr.Lhs); context.Write(output, "),"); } @@ -1241,7 +1212,7 @@ private void WriteExpr(CompilationContext context, StringWriter output, IPExpr p if (PLanguageType.TypeIsOfKind(binOpExpr.Rhs.Type, TypeKind.Enum)) { - context.Write(output, "PrtValues.Box((long) "); + context.Write(output, "PValues.Box((long) "); WriteExpr(context, output, binOpExpr.Rhs); context.Write(output, ")"); } @@ -1274,7 +1245,7 @@ private void WriteExpr(CompilationContext context, StringWriter output, IPExpr p break; case BoolLiteralExpr boolLiteralExpr: - context.Write(output, $"((PrtBool){(boolLiteralExpr.Value ? "true" : "false")})"); + context.Write(output, $"((PBool){(boolLiteralExpr.Value ? "true" : "false")})"); break; case CastExpr castExpr: @@ -1316,7 +1287,7 @@ private void WriteExpr(CompilationContext context, StringWriter output, IPExpr p case ChooseExpr chooseExpr: if (chooseExpr.SubExpr == null) { - context.Write(output, "((PrtBool)currentMachine.TryRandomBool())"); + context.Write(output, "((PBool)currentMachine.RandomBoolean())"); } else { @@ -1329,10 +1300,10 @@ private void WriteExpr(CompilationContext context, StringWriter output, IPExpr p case ContainsExpr containsExpr: var isMap = PLanguageType.TypeIsOfKind(containsExpr.Collection.Type, TypeKind.Map); var isSeq = PLanguageType.TypeIsOfKind(containsExpr.Collection.Type, TypeKind.Sequence); - var castOp = isMap ? "(PrtMap)" - : isSeq ? "(PrtSeq)" - : "(PrtSet)"; - context.Write(output, "((PrtBool)("); + var castOp = isMap ? "(PMap)" + : isSeq ? "(PSeq)" + : "(PSet)"; + context.Write(output, "((PBool)("); context.Write(output, $"({castOp}"); WriteExpr(context, output, containsExpr.Collection); if (isMap) @@ -1358,7 +1329,7 @@ private void WriteExpr(CompilationContext context, StringWriter output, IPExpr p if (ctorExpr.Arguments.Count > 1) { //create tuple from rvaluelist - context.Write(output, "new PrtTuple("); + context.Write(output, "new PTuple("); var septor = ""; foreach (var ctorExprArgument in ctorExpr.Arguments) { @@ -1384,7 +1355,7 @@ private void WriteExpr(CompilationContext context, StringWriter output, IPExpr p case EnumElemRefExpr enumElemRefExpr: var enumElem = enumElemRefExpr.Value; - context.Write(output, $"(PrtEnum.Get(\"{context.Names.GetNameForDecl(enumElem)}\"))"); + context.Write(output, $"(PEnum.Get(\"{context.Names.GetNameForDecl(enumElem)}\"))"); break; case EventRefExpr eventRefExpr: @@ -1408,11 +1379,11 @@ private void WriteExpr(CompilationContext context, StringWriter output, IPExpr p break; case FairNondetExpr _: - context.Write(output, "((PrtBool)currentMachine.TryRandomBool())"); + context.Write(output, "((PBool)currentMachine.RandomBoolean())"); break; case FloatLiteralExpr floatLiteralExpr: - context.Write(output, $"((PrtFloat){floatLiteralExpr.Value})"); + context.Write(output, $"((PFloat){floatLiteralExpr.Value})"); break; case FunCallExpr funCallExpr: @@ -1439,7 +1410,7 @@ private void WriteExpr(CompilationContext context, StringWriter output, IPExpr p break; case IntLiteralExpr intLiteralExpr: - context.Write(output, $"((PrtInt)({intLiteralExpr.Value}))"); + context.Write(output, $"((PInt)({intLiteralExpr.Value}))"); break; case KeysExpr keysExpr: @@ -1467,7 +1438,7 @@ private void WriteExpr(CompilationContext context, StringWriter output, IPExpr p break; case NondetExpr _: - context.Write(output, "((PrtBool)currentMachine.TryRandomBool())"); + context.Write(output, "((PBool)currentMachine.RandomBoolean())"); break; case NullLiteralExpr _: @@ -1475,13 +1446,13 @@ private void WriteExpr(CompilationContext context, StringWriter output, IPExpr p break; case SizeofExpr sizeofExpr: - context.Write(output, "((PrtInt)("); + context.Write(output, "((PInt)("); WriteExpr(context, output, sizeofExpr.Expr); context.Write(output, ").Count)"); break; case StringExpr stringExpr: - context.Write(output, $"((PrtString) String.Format("); + context.Write(output, $"((PString) String.Format("); context.Write(output, $"\"{stringExpr.BaseString}\""); foreach (var arg in stringExpr.Args) { @@ -1544,7 +1515,7 @@ private void WriteClone(CompilationContext context, StringWriter output, IExprTe } var varName = context.Names.GetNameForDecl(variableRef.Variable); - context.Write(output, $"(({GetCSharpType(variableRef.Type)})((IPrtValue){varName})?.Clone())"); + context.Write(output, $"(({GetCSharpType(variableRef.Type)})((IPValue){varName})?.Clone())"); } private string GetCSharpType(PLanguageType type, bool isVar = false) @@ -1552,55 +1523,55 @@ private string GetCSharpType(PLanguageType type, bool isVar = false) switch (type.Canonicalize()) { case DataType _: - return "IPrtValue"; + return "IPValue"; case EnumType _: - return "PrtInt"; + return "PInt"; case ForeignType _: return type.CanonicalRepresentation; case MapType _: - return "PrtMap"; + return "PMap"; case NamedTupleType _: - return "PrtNamedTuple"; + return "PNamedTuple"; case PermissionType _: return "PMachineValue"; case PrimitiveType primitiveType when primitiveType.IsSameTypeAs(PrimitiveType.Any): - return "IPrtValue"; + return "IPValue"; case PrimitiveType primitiveType when primitiveType.IsSameTypeAs(PrimitiveType.Bool): - return "PrtBool"; + return "PBool"; case PrimitiveType primitiveType when primitiveType.IsSameTypeAs(PrimitiveType.Int): - return "PrtInt"; + return "PInt"; case PrimitiveType primitiveType when primitiveType.IsSameTypeAs(PrimitiveType.Float): - return "PrtFloat"; + return "PFloat"; case PrimitiveType primitiveType when primitiveType.IsSameTypeAs(PrimitiveType.String): - return "PrtString"; + return "PString"; case PrimitiveType primitiveType when primitiveType.IsSameTypeAs(PrimitiveType.Event): - return "PEvent"; + return "Event"; case PrimitiveType primitiveType when primitiveType.IsSameTypeAs(PrimitiveType.Machine): return "PMachineValue"; case PrimitiveType primitiveType when primitiveType.IsSameTypeAs(PrimitiveType.Null): - return isVar ? "IPrtValue" : "void"; + return isVar ? "IPValue" : "void"; case SequenceType _: - return "PrtSeq"; + return "PSeq"; case SetType _: - return "PrtSet"; + return "PSet"; case TupleType _: - return "PrtTuple"; + return "PTuple"; default: throw new ArgumentOutOfRangeException(nameof(type)); @@ -1612,7 +1583,7 @@ private string GetDefaultValue(PLanguageType returnType) switch (returnType.Canonicalize()) { case EnumType enumType: - return $"((PrtInt){enumType.EnumDecl.Values.Min(elem => elem.Value)})"; + return $"((PInt){enumType.EnumDecl.Values.Min(elem => elem.Value)})"; case MapType mapType: return $"new {GetCSharpType(mapType)}()"; @@ -1636,16 +1607,16 @@ private string GetDefaultValue(PLanguageType returnType) return $"(new {GetCSharpType(tupleType)}({defaultTupleValues}))"; case PrimitiveType primitiveType when primitiveType.IsSameTypeAs(PrimitiveType.Bool): - return "((PrtBool)false)"; + return "((PBool)false)"; case PrimitiveType primitiveType when primitiveType.IsSameTypeAs(PrimitiveType.Int): - return "((PrtInt)0)"; + return "((PInt)0)"; case PrimitiveType primitiveType when primitiveType.IsSameTypeAs(PrimitiveType.Float): - return "((PrtFloat)0.0)"; + return "((PFloat)0.0)"; case PrimitiveType primitiveType when primitiveType.IsSameTypeAs(PrimitiveType.String): - return "((PrtString)\"\")"; + return "((PString)\"\")"; case PrimitiveType eventType when eventType.IsSameTypeAs(PrimitiveType.Event): case PermissionType _: diff --git a/Src/PCompiler/CompilerCore/Backend/CSharp/CSharpNameManager.cs b/Src/PCompiler/CompilerCore/Backend/CSharp/CSharpNameManager.cs index 01868c7b75..6fbab89989 100644 --- a/Src/PCompiler/CompilerCore/Backend/CSharp/CSharpNameManager.cs +++ b/Src/PCompiler/CompilerCore/Backend/CSharp/CSharpNameManager.cs @@ -49,7 +49,7 @@ protected override string ComputeNameForDecl(IPDecl decl) #pragma warning disable CCN0002 // Non exhaustive patterns in switch block switch (decl) { - case PEvent pEvent: + case Event pEvent: if (pEvent.IsNullEvent) { return "DefaultEvent"; diff --git a/Src/PCompiler/CompilerCore/Backend/CSharp/Constants.cs b/Src/PCompiler/CompilerCore/Backend/CSharp/Constants.cs index 595f3073eb..1094d641e7 100644 --- a/Src/PCompiler/CompilerCore/Backend/CSharp/Constants.cs +++ b/Src/PCompiler/CompilerCore/Backend/CSharp/Constants.cs @@ -26,7 +26,7 @@ internal class Constants using System; using System.IO; using System.Linq; -using PChecker.Actors; +using PChecker.Runtime.StateMachines; namespace PImplementation { @@ -39,7 +39,7 @@ public static void Main(string[] args) // update the path to the schedule file. string schedule = File.ReadAllText(""absolute path to *.schedule file""); configuration.WithReplayStrategy(schedule); - TestingEngine engine = TestingEngine.Create(configuration, (Action)PImplementation..Execute); + TestingEngine engine = TestingEngine.Create(configuration, (Action)PImplementation..Execute); engine.Run(); string bug = engine.TestReport.BugReports.FirstOrDefault(); if (bug != null) diff --git a/Src/PCompiler/CompilerCore/Backend/Debugging/IrToPseudoP.cs b/Src/PCompiler/CompilerCore/Backend/Debugging/IrToPseudoP.cs index a135656dae..23c7968fb9 100644 --- a/Src/PCompiler/CompilerCore/Backend/Debugging/IrToPseudoP.cs +++ b/Src/PCompiler/CompilerCore/Backend/Debugging/IrToPseudoP.cs @@ -147,7 +147,7 @@ private void WriteTree(IPAST tree) " };"); break; - case PEvent pEvent: + case Event pEvent: WriteStmt("event ", pEvent, " assert ", @@ -168,7 +168,7 @@ private void WriteTree(IPAST tree) break; case AnnounceStmt announceStmt: - WriteStmt("announce ", announceStmt.PEvent, ", ", announceStmt.Payload, ";"); + WriteStmt("announce ", announceStmt.Event, ", ", announceStmt.Payload, ";"); break; case AssertStmt assertStmt: @@ -235,7 +235,7 @@ private void WriteTree(IPAST tree) break; case RaiseStmt raiseStmt: - WriteStmt("raise ", raiseStmt.PEvent, ", ", raiseStmt.Payload, ";"); + WriteStmt("raise ", raiseStmt.Event, ", ", raiseStmt.Payload, ";"); break; case ReceiveStmt receiveStmt: diff --git a/Src/PCompiler/CompilerCore/Backend/IRTransformer.cs b/Src/PCompiler/CompilerCore/Backend/IRTransformer.cs index 943eba0df8..3de4fc381c 100644 --- a/Src/PCompiler/CompilerCore/Backend/IRTransformer.cs +++ b/Src/PCompiler/CompilerCore/Backend/IRTransformer.cs @@ -338,7 +338,7 @@ private List SimplifyStatement(IPStmt statement) case null: throw new ArgumentNullException(nameof(statement)); case AnnounceStmt announceStmt: - (var annEvt, var annEvtDeps) = SimplifyExpression(announceStmt.PEvent); + (var annEvt, var annEvtDeps) = SimplifyExpression(announceStmt.Event); (IExprTerm annPayload, List annPayloadDeps) = announceStmt.Payload == null ? (null, new List()) : SimplifyExpression(announceStmt.Payload); @@ -477,7 +477,7 @@ private List SimplifyStatement(IPStmt statement) return deps.Concat(new[] { new PrintStmt(location, newMessage) }).ToList(); case RaiseStmt raiseStmt: - (var raiseEvent, var raiseEventDeps) = SimplifyExpression(raiseStmt.PEvent); + (var raiseEvent, var raiseEventDeps) = SimplifyExpression(raiseStmt.Event); (var raiseEventTmp, var raiseEventTempDep) = SaveInTemporary(new CloneExpr(raiseEvent)); (var raiseArgs, var raiseArgDeps) = SimplifyArgPack(raiseStmt.Payload); diff --git a/Src/PCompiler/CompilerCore/Backend/Java/Constants.cs b/Src/PCompiler/CompilerCore/Backend/Java/Constants.cs index 20de91eb60..d3ab2b30e5 100644 --- a/Src/PCompiler/CompilerCore/Backend/Java/Constants.cs +++ b/Src/PCompiler/CompilerCore/Backend/Java/Constants.cs @@ -52,7 +52,7 @@ internal static IEnumerable ImportStatements() #region Event source generation - public static readonly string EventNamespaceName = "PEvents"; + public static readonly string EventNamespaceName = "Events"; public static readonly string EventDefnFileName = $"{EventNamespaceName}.java"; #endregion @@ -227,9 +227,9 @@ internal static string AsFFIComment(string line) internal static readonly string PValueClass = "prt.values.PValue"; /// - /// The fully-qualified class name of the Java P runtime's PEvent class. + /// The fully-qualified class name of the Java P runtime's Event class. /// - internal static readonly string PEventsClass = "prt.events.PEvent"; + internal static readonly string EventsClass = "prt.events.Event"; #endregion diff --git a/Src/PCompiler/CompilerCore/Backend/Java/EventGenerator.cs b/Src/PCompiler/CompilerCore/Backend/Java/EventGenerator.cs index b21a51cc5b..ba57cc4a91 100644 --- a/Src/PCompiler/CompilerCore/Backend/Java/EventGenerator.cs +++ b/Src/PCompiler/CompilerCore/Backend/Java/EventGenerator.cs @@ -28,9 +28,9 @@ protected override void GenerateCodeImpl() } - private IEnumerable monitoredEvents(IEnumerable machines) + private IEnumerable monitoredEvents(IEnumerable machines) { - var events = new HashSet(); + var events = new HashSet(); foreach (var m in machines.Where(m => m.IsSpec)) { @@ -43,7 +43,7 @@ private IEnumerable monitoredEvents(IEnumerable machines) return events; } - private void WriteEventDecl(PEvent e) + private void WriteEventDecl(Event e) { var eventName = Names.GetNameForDecl(e); var argType = Types.JavaTypeFor(e.PayloadType); @@ -51,7 +51,7 @@ private void WriteEventDecl(PEvent e) var payloadType = argType.TypeName; var payloadRefType = argType.ReferenceTypeName; - WriteLine($"public static class {eventName} extends {Constants.PEventsClass}<{payloadRefType}> implements Serializable {{"); + WriteLine($"public static class {eventName} extends {Constants.EventsClass}<{payloadRefType}> implements Serializable {{"); var hasPayload = !(argType is TypeManager.JType.JVoid); if (hasPayload) diff --git a/Src/PCompiler/CompilerCore/Backend/Java/MachineGenerator.cs b/Src/PCompiler/CompilerCore/Backend/Java/MachineGenerator.cs index d2b0ca52f4..a9cbadb528 100644 --- a/Src/PCompiler/CompilerCore/Backend/Java/MachineGenerator.cs +++ b/Src/PCompiler/CompilerCore/Backend/Java/MachineGenerator.cs @@ -69,7 +69,7 @@ protected override void GenerateCodeImpl() private void WriteMachineDecl() { - WriteLine($"// PMachine {_currentMachine.Name} elided "); + WriteLine($"// StateMachine {_currentMachine.Name} elided "); } private void WriteMonitorDecl() @@ -316,7 +316,7 @@ private void WriteStateBuilderEntryHandler(Function f) WriteLine($".withEntry(this::{fname})"); } - private void WriteStateBuilderEventHandler(PEvent e, IStateAction a) + private void WriteStateBuilderEventHandler(Event e, IStateAction a) { var ename = $"{Constants.EventNamespaceName}.{Names.GetNameForDecl(e)}"; @@ -492,7 +492,7 @@ private void WriteStmt(IPStmt stmt) case RaiseStmt raiseStmt: Write($"{Constants.TryRaiseEventMethodName}(new "); - WriteExpr(raiseStmt.PEvent); + WriteExpr(raiseStmt.Event); Write("("); foreach (var (sep, expr) in raiseStmt.Payload.WithPrefixSep(", ")) { diff --git a/Src/PCompiler/CompilerCore/Backend/Java/NameManager.cs b/Src/PCompiler/CompilerCore/Backend/Java/NameManager.cs index 7806e7dba9..f07332257b 100644 --- a/Src/PCompiler/CompilerCore/Backend/Java/NameManager.cs +++ b/Src/PCompiler/CompilerCore/Backend/Java/NameManager.cs @@ -95,9 +95,9 @@ protected override string ComputeNameForDecl(IPDecl decl) switch (decl) { - case PEvent { IsNullEvent: true }: + case Event { IsNullEvent: true }: return "DefaultEvent"; - case PEvent { IsHaltEvent: true }: + case Event { IsHaltEvent: true }: return "PHalt"; case Interface i: name = "I_" + i.Name; diff --git a/Src/PCompiler/CompilerCore/Backend/Java/TypeManager.cs b/Src/PCompiler/CompilerCore/Backend/Java/TypeManager.cs index b06f3a266c..1afbace9d1 100644 --- a/Src/PCompiler/CompilerCore/Backend/Java/TypeManager.cs +++ b/Src/PCompiler/CompilerCore/Backend/Java/TypeManager.cs @@ -102,7 +102,7 @@ internal string ReferenceTypeName internal class JAny : JType { - /// A JAny can either be a PEvent, a PValue, or a collection type like ArrayList, HashSet, etc. + /// A JAny can either be a Event, a PValue, or a collection type like ArrayList, HashSet, etc. /// For a complete list, see the implementation of `deepEquals()` and `deepClone` in the P java runtime: internal JAny() { @@ -179,7 +179,7 @@ internal static string ToJavaLiteral(string s) internal class JMachine : JType { - // Source/CheckerCore/Actors/ActorId.cs stores ActorID values as ulongs + // Source/CheckerCore/StateMachines/StateMachineId.cs stores StateMachineID values as ulongs internal JMachine() { @@ -304,7 +304,7 @@ internal class JEvent : JType { internal JEvent() { - _unboxedType = $"{Constants.PEventsClass}"; + _unboxedType = $"{Constants.EventsClass}"; } internal override bool IsPrimitive => false; } diff --git a/Src/PCompiler/CompilerCore/Backend/Symbolic/CompilationContext.cs b/Src/PCompiler/CompilerCore/Backend/Symbolic/CompilationContext.cs index 84944ef9cc..915e71d954 100644 --- a/Src/PCompiler/CompilerCore/Backend/Symbolic/CompilationContext.cs +++ b/Src/PCompiler/CompilerCore/Backend/Symbolic/CompilationContext.cs @@ -73,7 +73,7 @@ internal string GetNameForDecl(IPDecl decl) return $"{@interface.Name}"; case State state: return $"{state.Name}"; - case PEvent pEvent: + case Event pEvent: if (!pEvent.IsBuiltIn) return $"{pEvent.Name}"; else return $"_{pEvent.Name}"; diff --git a/Src/PCompiler/CompilerCore/Backend/Symbolic/Continuation.cs b/Src/PCompiler/CompilerCore/Backend/Symbolic/Continuation.cs index 56df9df642..f5a7d6662c 100644 --- a/Src/PCompiler/CompilerCore/Backend/Symbolic/Continuation.cs +++ b/Src/PCompiler/CompilerCore/Backend/Symbolic/Continuation.cs @@ -10,7 +10,7 @@ namespace Plang.Compiler.Backend.Symbolic { public class Continuation : Function { - public Continuation(string name, IReadOnlyDictionary cases, IPStmt after, ParserRuleContext location) : base(name, location) + public Continuation(string name, IReadOnlyDictionary cases, IPStmt after, ParserRuleContext location) : base(name, location) { Cases = cases; After = after; @@ -29,7 +29,7 @@ public void AddParameter(Variable local, Variable store) storeForLocal.Add(local, store); } - public IReadOnlyDictionary Cases { get; } + public IReadOnlyDictionary Cases { get; } public IPStmt After { get; } public IEnumerable StoreParameters => storeParameters; public IEnumerable LocalParameters => localParameters; diff --git a/Src/PCompiler/CompilerCore/Backend/Symbolic/SymbolicCodeGenerator.cs b/Src/PCompiler/CompilerCore/Backend/Symbolic/SymbolicCodeGenerator.cs index 4cf486a3fb..e4849cc161 100644 --- a/Src/PCompiler/CompilerCore/Backend/Symbolic/SymbolicCodeGenerator.cs +++ b/Src/PCompiler/CompilerCore/Backend/Symbolic/SymbolicCodeGenerator.cs @@ -222,7 +222,7 @@ private void WriteMainDriver(CompilationContext context, StringWriter output, Sc context.WriteLine(output); } - private void WriteEvent(CompilationContext context, StringWriter output, PEvent ev) + private void WriteEvent(CompilationContext context, StringWriter output, Event ev) { context.WriteLine(output, $"public static Event {context.GetNameForDecl(ev)} = new Event(\"{context.GetNameForDecl(ev)}\");"); } @@ -243,7 +243,7 @@ private void WriteDecl(CompilationContext context, StringWriter output, IPDecl d else WriteMachine(context, output, machine); break; - case PEvent ev: + case Event ev: WriteEvent(context, output, ev); break; case SafetyTest safety: @@ -500,7 +500,7 @@ private void WriteState(CompilationContext context, StringWriter output, State s context.Write(output, "}"); } - private void WriteEventHandler(CompilationContext context, StringWriter output, KeyValuePair handler, State state) + private void WriteEventHandler(CompilationContext context, StringWriter output, KeyValuePair handler, State state) { var eventTag = context.GetNameForDecl(handler.Key); switch (handler.Value) @@ -1039,7 +1039,7 @@ private void WriteStmt(Function function, CompilationContext context, StringWrit context.WriteLine(output, "// NOTE (TODO): We currently perform no typechecking on the payload!"); context.Write(output, $"outcome.raiseGuardedEvent({flowContext.pcScope.PathConstraintVar}, "); - WriteExpr(context, output, flowContext.pcScope, raiseStmt.PEvent); + WriteExpr(context, output, flowContext.pcScope, raiseStmt.Event); if (raiseStmt.Payload.Count > 0) { // TODO: Determine how multi-payload raise statements are supposed to work @@ -1312,7 +1312,7 @@ private void WriteStmt(Function function, CompilationContext context, StringWrit } case AnnounceStmt announceStmt: context.Write(output, $"{CompilationContext.SchedulerVar}.announce("); - WriteExpr(context, output, flowContext.pcScope, announceStmt.PEvent); + WriteExpr(context, output, flowContext.pcScope, announceStmt.Event); context.Write(output, ", "); if (announceStmt.Payload == null) context.Write(output, "null"); diff --git a/Src/PCompiler/CompilerCore/Backend/Symbolic/TransformASTPass.cs b/Src/PCompiler/CompilerCore/Backend/Symbolic/TransformASTPass.cs index a2b60ac3ea..7f20c153b0 100644 --- a/Src/PCompiler/CompilerCore/Backend/Symbolic/TransformASTPass.cs +++ b/Src/PCompiler/CompilerCore/Backend/Symbolic/TransformASTPass.cs @@ -346,7 +346,7 @@ static private IPStmt ReplaceVars(IPStmt stmt, Dictionary var case AddStmt addStmt: return new AddStmt(addStmt.SourceLocation, ReplaceVars(addStmt.Variable, varMap), ReplaceVars(addStmt.Value, varMap)); case AnnounceStmt announceStmt: - return new AnnounceStmt(announceStmt.SourceLocation, ReplaceVars(announceStmt.PEvent, varMap), ReplaceVars(announceStmt.Payload, varMap)); + return new AnnounceStmt(announceStmt.SourceLocation, ReplaceVars(announceStmt.Event, varMap), ReplaceVars(announceStmt.Payload, varMap)); case AssertStmt assertStmt: return new AssertStmt(assertStmt.SourceLocation, ReplaceVars(assertStmt.Assertion, varMap), ReplaceVars(assertStmt.Message, varMap)); case AssignStmt assignStmt: @@ -378,9 +378,9 @@ static private IPStmt ReplaceVars(IPStmt stmt, Dictionary var case RaiseStmt raiseStmt: var payload = new List(); foreach(var p in raiseStmt.Payload) payload.Add(ReplaceVars(p, varMap)); - return new RaiseStmt(raiseStmt.SourceLocation, ReplaceVars(raiseStmt.PEvent, varMap), payload); + return new RaiseStmt(raiseStmt.SourceLocation, ReplaceVars(raiseStmt.Event, varMap), payload); case ReceiveStmt receiveStmt: - var cases = new Dictionary(); + var cases = new Dictionary(); foreach(var entry in receiveStmt.Cases) { var replacement = new Function(entry.Value.Name, entry.Value.SourceLocation); @@ -515,7 +515,7 @@ static private IPStmt ReplaceBreaks(IPStmt stmt, List afterStmts) case IfStmt ifStmt: return new IfStmt(ifStmt.SourceLocation, ifStmt.Condition, ReplaceBreaks(ifStmt.ThenBranch, afterStmts), ReplaceBreaks(ifStmt.ElseBranch, afterStmts)); case ReceiveStmt receiveStmt: - var cases = new Dictionary(); + var cases = new Dictionary(); foreach(var entry in receiveStmt.Cases) { var replacement = new Function(entry.Value.Name, entry.Value.SourceLocation); @@ -602,7 +602,7 @@ static private IPStmt HandleReceives(IPStmt statement, Function function, Machin } break; case ReceiveStmt recv: - IDictionary cases = new Dictionary(); + IDictionary cases = new Dictionary(); var canReceiveInCase = false; foreach (var c in recv.Cases) { @@ -775,11 +775,11 @@ static private IPStmt HandleReceives(IPStmt statement, Function function, Machin } } - static private Continuation GetContinuation(Function function, IDictionary cases, IPStmt after, ParserRuleContext location) + static private Continuation GetContinuation(Function function, IDictionary cases, IPStmt after, ParserRuleContext location) { var continuationName = $"continuation_{continuationNumber}"; continuationNumber++; - var continuation = new Continuation(continuationName, new Dictionary(cases), after, location); + var continuation = new Continuation(continuationName, new Dictionary(cases), after, location); continuation.ParentFunction = function; function.AddCallee(continuation); function.Role = FunctionRole.Method; diff --git a/Src/PCompiler/CompilerCore/DefaultTranslationErrorHandler.cs b/Src/PCompiler/CompilerCore/DefaultTranslationErrorHandler.cs index cd2466484b..a9b99eee6e 100644 --- a/Src/PCompiler/CompilerCore/DefaultTranslationErrorHandler.cs +++ b/Src/PCompiler/CompilerCore/DefaultTranslationErrorHandler.cs @@ -218,7 +218,7 @@ public Exception NoMain(ParserRuleContext sourceLocation, string message) return IssueError(sourceLocation, $"Illegal main machine. {message}"); } - public Exception InvalidAssertExpr(ParserRuleContext location, Machine monitor, PEvent illegalEvent) + public Exception InvalidAssertExpr(ParserRuleContext location, Machine monitor, Event illegalEvent) { return IssueError(location, $"invalid assert operation. event {illegalEvent.Name} in observes set of {monitor.Name} is not in the sends set of the module"); @@ -313,7 +313,7 @@ public Exception StringAssignStmtLinearArgument(ParserRuleContext argSourceLocat return IssueError(argSourceLocation, "String interpolation does not support linear arguments."); } - public Exception DuplicateReceiveCase(ParserRuleContext location, PEvent pEvent) + public Exception DuplicateReceiveCase(ParserRuleContext location, Event pEvent) { return IssueError(location, $"Event {pEvent.Name} appears twice in receive statement argument list"); } @@ -344,7 +344,7 @@ private string DeclarationName(IPDecl method) return method.Name.Length > 0 ? method.Name : $"at {locationResolver.GetLocation(method.SourceLocation)}"; } - public string SpecObservesSetIncompleteWarning(ParserRuleContext ctx, PEvent ev, Machine machine) + public string SpecObservesSetIncompleteWarning(ParserRuleContext ctx, Event ev, Machine machine) { return $"[!Warning!]\n[{locationResolver.GetLocation(ctx, ctx.start)}] Event {ev.Name} is not in the observes list of the spec machine {machine.Name}. The event-handler is never triggered as the event is not observed by the spec.\n[!Warning!]"; diff --git a/Src/PCompiler/CompilerCore/ITranslationErrorHandler.cs b/Src/PCompiler/CompilerCore/ITranslationErrorHandler.cs index 371885fe8b..5aea56f1d9 100644 --- a/Src/PCompiler/CompilerCore/ITranslationErrorHandler.cs +++ b/Src/PCompiler/CompilerCore/ITranslationErrorHandler.cs @@ -61,7 +61,7 @@ Exception DuplicateStartState( // module system related Exception InvalidBindExpr(ParserRuleContext location, string message); - Exception InvalidAssertExpr(ParserRuleContext location, Machine monitor, PEvent illegalEvent); + Exception InvalidAssertExpr(ParserRuleContext location, Machine monitor, Event illegalEvent); Exception InvalidAssertExpr(ParserRuleContext location, Machine monitor); @@ -97,7 +97,7 @@ Exception DuplicateStartState( Exception ChangeStateInNonVoidFunction(ParserRuleContext context); - Exception DuplicateReceiveCase(ParserRuleContext location, PEvent pEvent); + Exception DuplicateReceiveCase(ParserRuleContext location, Event pEvent); Exception NoMain(ParserRuleContext sourceLocation, string v); @@ -119,7 +119,7 @@ Exception DuplicateStartState( Exception IllegalChooseSubExprValue(PParser.ChooseExprContext context, int numChoices); Exception IllegalFunctionUsedInSpecMachine(Function function, Machine callerOwner); - String SpecObservesSetIncompleteWarning(ParserRuleContext loc, PEvent ev, Machine machine); + String SpecObservesSetIncompleteWarning(ParserRuleContext loc, Event ev, Machine machine); Exception DuplicateBindings(ParserRuleContext loc, Interface @interface); } } \ No newline at end of file diff --git a/Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/PEvent.cs b/Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/Event.cs similarity index 90% rename from Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/PEvent.cs rename to Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/Event.cs index ab5d3cfdf7..961b2d0c46 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/PEvent.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/Event.cs @@ -4,9 +4,9 @@ namespace Plang.Compiler.TypeChecker.AST.Declarations { - public class PEvent : IPDecl + public class Event : IPDecl { - public PEvent(string name, ParserRuleContext sourceNode) + public Event(string name, ParserRuleContext sourceNode) { Debug.Assert("halt".Equals(name) && sourceNode == null || "null".Equals(name) && sourceNode == null || diff --git a/Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/NamedEventSet.cs b/Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/NamedEventSet.cs index 29ae11574e..e2b7ec2018 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/NamedEventSet.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/AST/Declarations/NamedEventSet.cs @@ -7,38 +7,38 @@ namespace Plang.Compiler.TypeChecker.AST.Declarations { public interface IEventSet { - IEnumerable Events { get; } + IEnumerable Events { get; } - bool AddEvent(PEvent pEvent); + bool AddEvent(Event pEvent); - void AddEvents(IEnumerable evts); + void AddEvents(IEnumerable evts); - bool Contains(PEvent pEvent); + bool Contains(Event pEvent); bool IsSame(IEventSet eventSet); bool IsSubsetEqOf(IEventSet eventSet); - bool IsSubsetEqOf(IEnumerable eventSet); + bool IsSubsetEqOf(IEnumerable eventSet); - bool Intersects(IEnumerable eventSet); + bool Intersects(IEnumerable eventSet); } public class EventSet : IEventSet { - private static readonly Comparer EventNameComparer = - Comparer.Create((ev1, ev2) => string.Compare(ev1.Name, ev2.Name, StringComparison.Ordinal)); + private static readonly Comparer EventNameComparer = + Comparer.Create((ev1, ev2) => string.Compare(ev1.Name, ev2.Name, StringComparison.Ordinal)); - private readonly SortedSet events = new SortedSet(EventNameComparer); + private readonly SortedSet events = new SortedSet(EventNameComparer); - public IEnumerable Events => events; + public IEnumerable Events => events; - public bool AddEvent(PEvent pEvent) + public bool AddEvent(Event pEvent) { return events.Add(pEvent); } - public void AddEvents(IEnumerable evts) + public void AddEvents(IEnumerable evts) { foreach (var pEvent in evts) { @@ -46,7 +46,7 @@ public void AddEvents(IEnumerable evts) } } - public bool Contains(PEvent pEvent) + public bool Contains(Event pEvent) { return events.Contains(pEvent); } @@ -61,12 +61,12 @@ public bool IsSubsetEqOf(IEventSet eventSet) return events.IsSubsetOf(eventSet.Events); } - public bool IsSubsetEqOf(IEnumerable eventsList) + public bool IsSubsetEqOf(IEnumerable eventsList) { return events.IsSubsetOf(eventsList); } - public bool Intersects(IEnumerable eventSet) + public bool Intersects(IEnumerable eventSet) { return events.Overlaps(eventSet); } @@ -89,14 +89,14 @@ sourceNode is PParser.SpecMachineDeclContext || SourceLocation = sourceNode; } - public IEnumerable Events => events.Events; + public IEnumerable Events => events.Events; - public bool AddEvent(PEvent evt) + public bool AddEvent(Event evt) { return events.AddEvent(evt); } - public bool Contains(PEvent pEvent) + public bool Contains(Event pEvent) { return events.Contains(pEvent); } @@ -106,7 +106,7 @@ public bool IsSame(IEventSet eventSet) return events.IsSame(eventSet); } - public void AddEvents(IEnumerable evts) + public void AddEvents(IEnumerable evts) { foreach (var pEvent in evts) { @@ -119,12 +119,12 @@ public bool IsSubsetEqOf(IEventSet eventSet) return events.IsSubsetEqOf(eventSet); } - public bool IsSubsetEqOf(IEnumerable eventsList) + public bool IsSubsetEqOf(IEnumerable eventsList) { return events.IsSubsetEqOf(eventsList); } - public bool Intersects(IEnumerable eventSet) + public bool Intersects(IEnumerable eventSet) { return events.Intersects(eventSet); } diff --git a/Src/PCompiler/CompilerCore/TypeChecker/AST/Expressions/EventRefExpr.cs b/Src/PCompiler/CompilerCore/TypeChecker/AST/Expressions/EventRefExpr.cs index fb26afeae7..6b0a97a21c 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/AST/Expressions/EventRefExpr.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/AST/Expressions/EventRefExpr.cs @@ -4,15 +4,15 @@ namespace Plang.Compiler.TypeChecker.AST.Expressions { - public class EventRefExpr : IStaticTerm + public class EventRefExpr : IStaticTerm { - public EventRefExpr(ParserRuleContext sourceLocation, PEvent value) + public EventRefExpr(ParserRuleContext sourceLocation, Event value) { Value = value; SourceLocation = sourceLocation; } - public PEvent Value { get; } + public Event Value { get; } public PLanguageType Type { get; } = PrimitiveType.Event; public ParserRuleContext SourceLocation { get; } diff --git a/Src/PCompiler/CompilerCore/TypeChecker/AST/IStateAction.cs b/Src/PCompiler/CompilerCore/TypeChecker/AST/IStateAction.cs index 36fa68cd41..a7c899ee81 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/AST/IStateAction.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/AST/IStateAction.cs @@ -4,6 +4,6 @@ namespace Plang.Compiler.TypeChecker.AST { public interface IStateAction : IPAST { - PEvent Trigger { get; } + Event Trigger { get; } } } \ No newline at end of file diff --git a/Src/PCompiler/CompilerCore/TypeChecker/AST/ModuleExprs/HideEventModuleExpr.cs b/Src/PCompiler/CompilerCore/TypeChecker/AST/ModuleExprs/HideEventModuleExpr.cs index 95943e5f7c..b6c090dfed 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/AST/ModuleExprs/HideEventModuleExpr.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/AST/ModuleExprs/HideEventModuleExpr.cs @@ -6,7 +6,7 @@ namespace Plang.Compiler.TypeChecker.AST.ModuleExprs { public class HideEventModuleExpr : IPModuleExpr { - public HideEventModuleExpr(ParserRuleContext sourceNode, IEnumerable events, IPModuleExpr module) + public HideEventModuleExpr(ParserRuleContext sourceNode, IEnumerable events, IPModuleExpr module) { SourceLocation = sourceNode; HideEvents = new EventSet(); diff --git a/Src/PCompiler/CompilerCore/TypeChecker/AST/Statements/AnnounceStmt.cs b/Src/PCompiler/CompilerCore/TypeChecker/AST/Statements/AnnounceStmt.cs index 46847981ec..eb6faecaa8 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/AST/Statements/AnnounceStmt.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/AST/Statements/AnnounceStmt.cs @@ -7,11 +7,11 @@ public class AnnounceStmt : IPStmt public AnnounceStmt(ParserRuleContext sourceLocation, IPExpr pEvent, IPExpr payload) { SourceLocation = sourceLocation; - PEvent = pEvent; + Event = pEvent; Payload = payload; } - public IPExpr PEvent { get; } + public IPExpr Event { get; } public IPExpr Payload { get; } public ParserRuleContext SourceLocation { get; } diff --git a/Src/PCompiler/CompilerCore/TypeChecker/AST/Statements/RaiseStmt.cs b/Src/PCompiler/CompilerCore/TypeChecker/AST/Statements/RaiseStmt.cs index 73bf19ca2d..09b7c1b162 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/AST/Statements/RaiseStmt.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/AST/Statements/RaiseStmt.cs @@ -8,11 +8,11 @@ public class RaiseStmt : IPStmt public RaiseStmt(ParserRuleContext sourceLocation, IPExpr pEvent, IReadOnlyList payload) { SourceLocation = sourceLocation; - PEvent = pEvent; + Event = pEvent; Payload = payload; } - public IPExpr PEvent { get; } + public IPExpr Event { get; } public IReadOnlyList Payload { get; } public ParserRuleContext SourceLocation { get; } diff --git a/Src/PCompiler/CompilerCore/TypeChecker/AST/Statements/ReceiveStmt.cs b/Src/PCompiler/CompilerCore/TypeChecker/AST/Statements/ReceiveStmt.cs index 4a661a0b08..dcc5535aa9 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/AST/Statements/ReceiveStmt.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/AST/Statements/ReceiveStmt.cs @@ -6,13 +6,13 @@ namespace Plang.Compiler.TypeChecker.AST.Statements { public class ReceiveStmt : IPStmt { - public ReceiveStmt(ParserRuleContext sourceLocation, IReadOnlyDictionary cases) + public ReceiveStmt(ParserRuleContext sourceLocation, IReadOnlyDictionary cases) { SourceLocation = sourceLocation; Cases = cases; } - public IReadOnlyDictionary Cases { get; } + public IReadOnlyDictionary Cases { get; } public ParserRuleContext SourceLocation { get; } } } \ No newline at end of file diff --git a/Src/PCompiler/CompilerCore/TypeChecker/AST/States/EventDefer.cs b/Src/PCompiler/CompilerCore/TypeChecker/AST/States/EventDefer.cs index e6b5bc09c1..f2080e1e73 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/AST/States/EventDefer.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/AST/States/EventDefer.cs @@ -5,13 +5,13 @@ namespace Plang.Compiler.TypeChecker.AST.States { public class EventDefer : IStateAction { - public EventDefer(ParserRuleContext sourceLocation, PEvent trigger) + public EventDefer(ParserRuleContext sourceLocation, Event trigger) { SourceLocation = sourceLocation; Trigger = trigger; } public ParserRuleContext SourceLocation { get; } - public PEvent Trigger { get; } + public Event Trigger { get; } } } \ No newline at end of file diff --git a/Src/PCompiler/CompilerCore/TypeChecker/AST/States/EventDoAction.cs b/Src/PCompiler/CompilerCore/TypeChecker/AST/States/EventDoAction.cs index 98dc3242b7..ec331a7f58 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/AST/States/EventDoAction.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/AST/States/EventDoAction.cs @@ -5,7 +5,7 @@ namespace Plang.Compiler.TypeChecker.AST.States { public class EventDoAction : IStateAction { - public EventDoAction(ParserRuleContext sourceLocation, PEvent trigger, Function target) + public EventDoAction(ParserRuleContext sourceLocation, Event trigger, Function target) { SourceLocation = sourceLocation; Trigger = trigger; @@ -14,6 +14,6 @@ public EventDoAction(ParserRuleContext sourceLocation, PEvent trigger, Function public Function Target { get; } public ParserRuleContext SourceLocation { get; } - public PEvent Trigger { get; } + public Event Trigger { get; } } } \ No newline at end of file diff --git a/Src/PCompiler/CompilerCore/TypeChecker/AST/States/EventGotoState.cs b/Src/PCompiler/CompilerCore/TypeChecker/AST/States/EventGotoState.cs index 9fabc07113..b2ec551644 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/AST/States/EventGotoState.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/AST/States/EventGotoState.cs @@ -5,7 +5,7 @@ namespace Plang.Compiler.TypeChecker.AST.States { public class EventGotoState : IStateAction { - public EventGotoState(ParserRuleContext sourceLocation, PEvent trigger, State target, + public EventGotoState(ParserRuleContext sourceLocation, Event trigger, State target, Function transitionFunction) { SourceLocation = sourceLocation; @@ -18,6 +18,6 @@ public EventGotoState(ParserRuleContext sourceLocation, PEvent trigger, State ta public Function TransitionFunction { get; } public ParserRuleContext SourceLocation { get; } - public PEvent Trigger { get; } + public Event Trigger { get; } } } \ No newline at end of file diff --git a/Src/PCompiler/CompilerCore/TypeChecker/AST/States/EventIgnore.cs b/Src/PCompiler/CompilerCore/TypeChecker/AST/States/EventIgnore.cs index af38eafa34..d419449780 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/AST/States/EventIgnore.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/AST/States/EventIgnore.cs @@ -5,13 +5,13 @@ namespace Plang.Compiler.TypeChecker.AST.States { public class EventIgnore : IStateAction { - public EventIgnore(ParserRuleContext sourceLocation, PEvent trigger) + public EventIgnore(ParserRuleContext sourceLocation, Event trigger) { SourceLocation = sourceLocation; Trigger = trigger; } public ParserRuleContext SourceLocation { get; } - public PEvent Trigger { get; } + public Event Trigger { get; } } } \ No newline at end of file diff --git a/Src/PCompiler/CompilerCore/TypeChecker/AST/States/State.cs b/Src/PCompiler/CompilerCore/TypeChecker/AST/States/State.cs index 3d1ecf70ba..15881aa6e3 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/AST/States/State.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/AST/States/State.cs @@ -7,7 +7,7 @@ namespace Plang.Compiler.TypeChecker.AST.States { public class State : IPDecl { - private readonly IDictionary actions = new Dictionary(); + private readonly IDictionary actions = new Dictionary(); public State(ParserRuleContext sourceNode, string name) { @@ -20,13 +20,13 @@ public State(ParserRuleContext sourceNode, string name) public bool IsStart { get; set; } public Function Entry { get; set; } - public IEnumerable> AllEventHandlers => actions; + public IEnumerable> AllEventHandlers => actions; public Function Exit { get; set; } public Machine OwningMachine { get; set; } public IStateContainer Container { get; set; } - public IStateAction this[PEvent index] + public IStateAction this[Event index] { get => actions[index]; set => actions[index] = value; @@ -51,7 +51,7 @@ public string QualifiedName public string Name { get; } public ParserRuleContext SourceLocation { get; } - public bool HasHandler(PEvent pEvent) + public bool HasHandler(Event pEvent) { return actions.ContainsKey(pEvent); } diff --git a/Src/PCompiler/CompilerCore/TypeChecker/DeclarationVisitor.cs b/Src/PCompiler/CompilerCore/TypeChecker/DeclarationVisitor.cs index 2e13102774..764282661f 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/DeclarationVisitor.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/DeclarationVisitor.cs @@ -46,7 +46,7 @@ public static void PopulateDeclarations( public override object VisitEventDecl(PParser.EventDeclContext context) { // EVENT name=Iden - var pEvent = (PEvent) nodesToDeclarations.Get(context); + var pEvent = (Event) nodesToDeclarations.Get(context); // cardinality? var hasAssume = context.cardinality()?.ASSUME() != null; @@ -84,7 +84,7 @@ public override object VisitInterfaceDecl(PParser.InterfaceDeclContext context) eventSet = new EventSet(); if (context.nonDefaultEventList()?._events is IList events) foreach (var eventContext in events) - eventSet.AddEvent((PEvent) Visit(eventContext)); + eventSet.AddEvent((Event) Visit(eventContext)); } mInterface.ReceivableEvents = eventSet; @@ -233,7 +233,7 @@ public override object VisitEventSetDecl(PParser.EventSetDeclContext context) // EVENTSET name=iden var es = (NamedEventSet) nodesToDeclarations.Get(context); // ASSIGN LBRACE eventSetLiteral RBRACE - es.AddEvents((PEvent[]) Visit(context.eventSetLiteral())); + es.AddEvents((Event[]) Visit(context.eventSetLiteral())); // SEMI return es; } @@ -241,14 +241,14 @@ public override object VisitEventSetDecl(PParser.EventSetDeclContext context) public override object VisitEventSetLiteral(PParser.EventSetLiteralContext context) { // events+=nonDefaultEvent (COMMA events+=nonDefaultEvent)* - return context._events.Select(Visit).Cast().ToArray(); + return context._events.Select(Visit).Cast().ToArray(); } public override object VisitNonDefaultEvent(PParser.NonDefaultEventContext context) { // HALT | iden var eventName = context.GetText(); - if (!CurrentScope.Lookup(eventName, out PEvent pEvent)) + if (!CurrentScope.Lookup(eventName, out Event pEvent)) throw Handler.MissingDeclaration(context, "event", eventName); return pEvent; } @@ -273,7 +273,7 @@ public override object VisitImplMachineDecl(PParser.ImplMachineDeclContext conte // receivesSends* foreach (var receivesSends in context.receivesSends()) { - var recvSendTuple = (Tuple) Visit(receivesSends); + var recvSendTuple = (Tuple) Visit(receivesSends); var eventSetType = recvSendTuple.Item1; if (eventSetType.Equals("RECV", StringComparison.InvariantCulture)) { @@ -312,16 +312,16 @@ public override object VisitImplMachineDecl(PParser.ImplMachineDeclContext conte public override object VisitMachineReceive(PParser.MachineReceiveContext context) { var events = context.eventSetLiteral() == null - ? new PEvent[0] - : (PEvent[]) Visit(context.eventSetLiteral()); + ? new Event[0] + : (Event[]) Visit(context.eventSetLiteral()); return Tuple.Create("RECV", events); } public override object VisitMachineSend(PParser.MachineSendContext context) { var events = context.eventSetLiteral() == null - ? new PEvent[0] - : (PEvent[]) Visit(context.eventSetLiteral()); + ? new Event[0] + : (Event[]) Visit(context.eventSetLiteral()); return Tuple.Create("SEND", events); } @@ -336,7 +336,7 @@ public override object VisitSpecMachineDecl(PParser.SpecMachineDeclContext conte // OBSERVES eventSetLiteral specMachine.Observes = new EventSet(); - foreach (var pEvent in (PEvent[]) Visit(context.eventSetLiteral())) specMachine.Observes.AddEvent(pEvent); + foreach (var pEvent in (Event[]) Visit(context.eventSetLiteral())) specMachine.Observes.AddEvent(pEvent); // machineBody using (currentScope.NewContext(specMachine.Scope)) @@ -506,7 +506,7 @@ public override object VisitStateDefer(PParser.StateDeferContext context) for (var i = 0; i < eventContexts.Count; i++) { var token = eventContexts[i]; - if (!CurrentScope.Lookup(token.GetText(), out PEvent evt)) + if (!CurrentScope.Lookup(token.GetText(), out Event evt)) throw Handler.MissingDeclaration(token, "event", token.GetText()); actions[i] = new EventDefer(token, evt); } @@ -520,7 +520,7 @@ public override object VisitStateIgnore(PParser.StateIgnoreContext context) var actions = new List(); foreach (var token in context.nonDefaultEventList()._events) { - if (!CurrentScope.Lookup(token.GetText(), out PEvent evt)) + if (!CurrentScope.Lookup(token.GetText(), out Event evt)) throw Handler.MissingDeclaration(token, "event", token.GetText()); actions.Add(new EventIgnore(token, evt)); } @@ -551,7 +551,7 @@ public override object VisitOnEventDoAction(PParser.OnEventDoActionContext conte var actions = new List(); foreach (var eventIdContext in context.eventList().eventId()) { - if (!CurrentScope.Lookup(eventIdContext.GetText(), out PEvent evt)) + if (!CurrentScope.Lookup(eventIdContext.GetText(), out Event evt)) throw Handler.MissingDeclaration(eventIdContext, "event", eventIdContext.GetText()); actions.Add(new EventDoAction(eventIdContext, evt, fun)); @@ -591,7 +591,7 @@ public override object VisitOnEventGotoState(PParser.OnEventGotoStateContext con var actions = new List(); foreach (var eventIdContext in context.eventList().eventId()) { - if (!CurrentScope.Lookup(eventIdContext.GetText(), out PEvent evt)) + if (!CurrentScope.Lookup(eventIdContext.GetText(), out Event evt)) throw Handler.MissingDeclaration(eventIdContext, "event", eventIdContext.GetText()); actions.Add(new EventGotoState(eventIdContext, evt, target, transitionFunction)); diff --git a/Src/PCompiler/CompilerCore/TypeChecker/ExprVisitor.cs b/Src/PCompiler/CompilerCore/TypeChecker/ExprVisitor.cs index 82fd330db8..01d2716f2f 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/ExprVisitor.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/ExprVisitor.cs @@ -513,7 +513,7 @@ public override IPExpr VisitPrimitive(PParser.PrimitiveContext context) return new EnumElemRefExpr(context, enumElem); } - if (table.Lookup(symbolName, out PEvent evt)) + if (table.Lookup(symbolName, out Event evt)) { return new EventRefExpr(context, evt); } @@ -565,7 +565,7 @@ public override IPExpr VisitPrimitive(PParser.PrimitiveContext context) if (context.HALT() != null) { - var success = table.Lookup("halt", out PEvent haltEvent); + var success = table.Lookup("halt", out Event haltEvent); Debug.Assert(success); return new EventRefExpr(context, haltEvent); } diff --git a/Src/PCompiler/CompilerCore/TypeChecker/InferMachineCreates.cs b/Src/PCompiler/CompilerCore/TypeChecker/InferMachineCreates.cs index bb8e434932..4327ed099c 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/InferMachineCreates.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/InferMachineCreates.cs @@ -47,7 +47,7 @@ private static IEnumerable InferCreates(IPAST tree, ITranslationError .Union(InferCreatesForExpr(addStmt.Value, handler)); case AnnounceStmt announce: - return InferCreatesForExpr(announce.PEvent, handler) + return InferCreatesForExpr(announce.Event, handler) .Union(InferCreatesForExpr(announce.Payload, handler)); case AssertStmt assertStmt: @@ -92,7 +92,7 @@ private static IEnumerable InferCreates(IPAST tree, ITranslationError return InferCreatesForExpr(printStmt.Message, handler); case RaiseStmt raiseStmt: - return InferCreatesForExpr(raiseStmt.PEvent, handler) + return InferCreatesForExpr(raiseStmt.Event, handler) .Union(raiseStmt.Payload.SelectMany(expr => InferCreatesForExpr(expr, handler))); case ReceiveStmt receiveStmt: diff --git a/Src/PCompiler/CompilerCore/TypeChecker/ModuleExprVisitor.cs b/Src/PCompiler/CompilerCore/TypeChecker/ModuleExprVisitor.cs index ce6bccb138..74e4e7220d 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/ModuleExprVisitor.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/ModuleExprVisitor.cs @@ -116,10 +116,10 @@ public override IPModuleExpr VisitComposeModuleExpr([NotNull] PParser.ComposeMod public override IPModuleExpr VisitHideEventsModuleExpr([NotNull] PParser.HideEventsModuleExprContext context) { - var eventList = new List(); + var eventList = new List(); foreach (var eventName in context.nonDefaultEventList()._events) { - if (!globalScope.Get(eventName.GetText(), out PEvent @event)) + if (!globalScope.Get(eventName.GetText(), out Event @event)) { throw handler.MissingDeclaration(eventName, "event", eventName.GetText()); } diff --git a/Src/PCompiler/CompilerCore/TypeChecker/ModuleSystemTypeChecker.cs b/Src/PCompiler/CompilerCore/TypeChecker/ModuleSystemTypeChecker.cs index d8cf61fd62..7ee7cdcdf3 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/ModuleSystemTypeChecker.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/ModuleSystemTypeChecker.cs @@ -4,6 +4,7 @@ using Plang.Compiler.TypeChecker.AST; using Plang.Compiler.TypeChecker.AST.Declarations; using Plang.Compiler.TypeChecker.AST.ModuleExprs; +using Plang.Compiler.TypeChecker.Types; namespace Plang.Compiler.TypeChecker { @@ -18,7 +19,7 @@ public ModuleSystemTypeChecker(ITranslationErrorHandler handler, Scope globalSco this.globalScope = globalScope; } - private IEnumerable GetPermissions(IEnumerable allowed) + private IEnumerable GetPermissions(IEnumerable allowed) { if (allowed == null) { @@ -189,13 +190,21 @@ internal void CheckSafetyTest(SafetyTest test) $"test module is not closed with respect to created interfaces; interface {@interface.First().Name} is created but not implemented inside the module"); } - //check that the test module main machine exists + // check that the test module main machine exists var hasMainMachine = test.ModExpr.ModuleInfo.InterfaceDef.Values.Any(m => m.Name == test.Main && !m.IsSpec); if (!hasMainMachine) { throw handler.NoMain(test.SourceLocation, $"machine {test.Main} does not exist in the test module"); } + + // make sure that the main machine does not take a parameter as input + globalScope.Get(test.Main, out Machine main); + if (!main.PayloadType.Equals(PrimitiveType.Null)) + { + throw handler.NoMain(test.SourceLocation, + $"main machine {test.Main} cannot take an input parameter in the entry function of the start state."); + } } internal void CheckImplementationDecl(Implementation impl) diff --git a/Src/PCompiler/CompilerCore/TypeChecker/Scope.cs b/Src/PCompiler/CompilerCore/TypeChecker/Scope.cs index 9eff2b90ce..da78441999 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/Scope.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/Scope.cs @@ -19,7 +19,7 @@ public class Scope private readonly IDictionary enumElems = new Dictionary(); private readonly IDictionary enums = new Dictionary(); - private readonly IDictionary events = new Dictionary(); + private readonly IDictionary events = new Dictionary(); private readonly IDictionary eventSets = new Dictionary(); private readonly IDictionary functions = new Dictionary(); private readonly ICompilerConfiguration config; @@ -42,7 +42,7 @@ private Scope(ICompilerConfiguration config, Scope parent = null) parent?.children.Add(this); var eventSetWithHalt = new EventSet(); - eventSetWithHalt.AddEvent(new PEvent("halt", null)); + eventSetWithHalt.AddEvent(new Event("halt", null)); UniversalEventSet = parent == null ? eventSetWithHalt : parent.UniversalEventSet; } @@ -68,7 +68,7 @@ private Scope(ICompilerConfiguration config, Scope parent = null) public IEnumerable EnumElems => enumElems.Values; public IEnumerable Enums => enums.Values; - public IEnumerable Events => events.Values; + public IEnumerable Events => events.Values; public IEnumerable EventSets => eventSets.Values; public IEnumerable Functions => functions.Values; public IEnumerable Interfaces => interfaces.Values; @@ -146,7 +146,7 @@ public bool Get(string name, out PEnum tree) return enums.TryGetValue(name, out tree); } - public bool Get(string name, out PEvent tree) + public bool Get(string name, out Event tree) { return events.TryGetValue(name, out tree); } @@ -244,7 +244,7 @@ public bool Lookup(string name, out PEnum tree) return false; } - public bool Lookup(string name, out PEvent tree) + public bool Lookup(string name, out Event tree) { var current = this; while (current != null) @@ -489,9 +489,9 @@ public PEnum Put(string name, PParser.EnumTypeDefDeclContext tree) return @enum; } - public PEvent Put(string name, PParser.EventDeclContext tree) + public Event Put(string name, PParser.EventDeclContext tree) { - var @event = new PEvent(name, tree); + var @event = new Event(name, tree); CheckConflicts(@event, Namespace(events), Namespace(enumElems)); events.Add(name, @event); return @event; diff --git a/Src/PCompiler/CompilerCore/TypeChecker/StatementVisitor.cs b/Src/PCompiler/CompilerCore/TypeChecker/StatementVisitor.cs index 1287e10ace..16604ee817 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/StatementVisitor.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/StatementVisitor.cs @@ -471,7 +471,7 @@ public override IPStmt VisitReceiveStmt(PParser.ReceiveStmtContext context) throw handler.IllegalMonitorOperation(context, context.RECEIVE().Symbol, machine); } - var cases = new Dictionary(); + var cases = new Dictionary(); foreach (var caseContext in context.recvCase()) { @@ -497,7 +497,7 @@ public override IPStmt VisitReceiveStmt(PParser.ReceiveStmtContext context) FunctionBodyVisitor.PopulateMethod(config, recvHandler); - if (!table.Lookup(eventIdContext.GetText(), out PEvent pEvent)) + if (!table.Lookup(eventIdContext.GetText(), out Event pEvent)) { throw handler.MissingDeclaration(eventIdContext, "event", eventIdContext.GetText()); } diff --git a/Src/PCompiler/CompilerCore/TypeChecker/Types/DataType.cs b/Src/PCompiler/CompilerCore/TypeChecker/Types/DataType.cs index 1a36c2c9d2..b07d706140 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/Types/DataType.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/Types/DataType.cs @@ -15,8 +15,8 @@ public DataType(NamedEventSet eventSet) : base(TypeKind.Data) public override string CanonicalRepresentation => "data"; - public override Lazy> AllowedPermissions => - new Lazy>(() => new List()); + public override Lazy> AllowedPermissions => + new Lazy>(() => new List()); public override bool IsAssignableFrom(PLanguageType otherType) { diff --git a/Src/PCompiler/CompilerCore/TypeChecker/Types/EnumType.cs b/Src/PCompiler/CompilerCore/TypeChecker/Types/EnumType.cs index 6e8a8e6865..ee0d6481bd 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/Types/EnumType.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/Types/EnumType.cs @@ -16,8 +16,8 @@ public EnumType(PEnum enumDecl) : base(TypeKind.Enum) public override string OriginalRepresentation => EnumDecl.Name; public override string CanonicalRepresentation => EnumDecl.Name; - public override Lazy> AllowedPermissions => - new Lazy>(() => new List()); + public override Lazy> AllowedPermissions => + new Lazy>(() => new List()); public override bool IsAssignableFrom(PLanguageType otherType) { diff --git a/Src/PCompiler/CompilerCore/TypeChecker/Types/ForeignType.cs b/Src/PCompiler/CompilerCore/TypeChecker/Types/ForeignType.cs index e8f123e482..28b5ef03bb 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/Types/ForeignType.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/Types/ForeignType.cs @@ -15,7 +15,7 @@ public ForeignType(string name) : base(TypeKind.Foreign) public override string OriginalRepresentation { get; } public override string CanonicalRepresentation { get; } - public override Lazy> AllowedPermissions { get; } = null; + public override Lazy> AllowedPermissions { get; } = null; public override bool IsAssignableFrom(PLanguageType otherType) { diff --git a/Src/PCompiler/CompilerCore/TypeChecker/Types/MapType.cs b/Src/PCompiler/CompilerCore/TypeChecker/Types/MapType.cs index 3e1f7d37a1..fcc16e50f3 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/Types/MapType.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/Types/MapType.cs @@ -17,7 +17,7 @@ public MapType(PLanguageType keyType, PLanguageType valueType) : base(TypeKind.M } else { - AllowedPermissions = new Lazy>(() => KeyType + AllowedPermissions = new Lazy>(() => KeyType .AllowedPermissions.Value.Concat(ValueType.AllowedPermissions.Value) .ToList()); } @@ -32,7 +32,7 @@ public MapType(PLanguageType keyType, PLanguageType valueType) : base(TypeKind.M public override string CanonicalRepresentation => $"map[{KeyType.CanonicalRepresentation},{ValueType.CanonicalRepresentation}]"; - public override Lazy> AllowedPermissions { get; } + public override Lazy> AllowedPermissions { get; } public override bool IsAssignableFrom(PLanguageType otherType) { diff --git a/Src/PCompiler/CompilerCore/TypeChecker/Types/NamedTupleType.cs b/Src/PCompiler/CompilerCore/TypeChecker/Types/NamedTupleType.cs index c5f4aeeb13..6810f56a16 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/Types/NamedTupleType.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/Types/NamedTupleType.cs @@ -20,7 +20,7 @@ public NamedTupleType(IReadOnlyList fields) : base(TypeKind.Nam $"({string.Join(",", Fields.Select(tn => $"{tn.Name}:{tn.Type.CanonicalRepresentation}"))})"; AllowedPermissions = Fields.Any(f => f.Type.AllowedPermissions == null) ? null - : new Lazy>( + : new Lazy>( () => Fields.SelectMany(f => f.Type.AllowedPermissions.Value).ToList()); } @@ -31,7 +31,7 @@ public NamedTupleType(IReadOnlyList fields) : base(TypeKind.Nam public override string OriginalRepresentation { get; } public override string CanonicalRepresentation { get; } - public override Lazy> AllowedPermissions { get; } + public override Lazy> AllowedPermissions { get; } public override bool IsAssignableFrom(PLanguageType otherType) { diff --git a/Src/PCompiler/CompilerCore/TypeChecker/Types/PLanguageType.cs b/Src/PCompiler/CompilerCore/TypeChecker/Types/PLanguageType.cs index 59d08a3b63..54288ad0da 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/Types/PLanguageType.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/Types/PLanguageType.cs @@ -29,7 +29,7 @@ protected PLanguageType(TypeKind kind) /// /// represents the permissions embedded in a type /// - public abstract Lazy> AllowedPermissions { get; } + public abstract Lazy> AllowedPermissions { get; } public abstract bool IsAssignableFrom(PLanguageType otherType); diff --git a/Src/PCompiler/CompilerCore/TypeChecker/Types/PermissionType.cs b/Src/PCompiler/CompilerCore/TypeChecker/Types/PermissionType.cs index 302e248dc1..6c96452550 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/Types/PermissionType.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/Types/PermissionType.cs @@ -13,25 +13,25 @@ public class PermissionType : PLanguageType public PermissionType(Machine machine) : base(TypeKind.Base) { origin = machine; - AllowedPermissions = new Lazy>(() => machine.Receives.Events.ToList()); + AllowedPermissions = new Lazy>(() => machine.Receives.Events.ToList()); } public PermissionType(Interface pInterface) : base(TypeKind.Base) { origin = pInterface; - AllowedPermissions = new Lazy>(() => pInterface.ReceivableEvents.Events.ToList()); + AllowedPermissions = new Lazy>(() => pInterface.ReceivableEvents.Events.ToList()); } public PermissionType(NamedEventSet eventSet) : base(TypeKind.Base) { origin = eventSet; - AllowedPermissions = new Lazy>(() => eventSet.Events.ToList()); + AllowedPermissions = new Lazy>(() => eventSet.Events.ToList()); } public override string OriginalRepresentation => origin.Name; public override string CanonicalRepresentation => origin.Name; - public override Lazy> AllowedPermissions { get; } + public override Lazy> AllowedPermissions { get; } public override bool IsAssignableFrom(PLanguageType otherType) { diff --git a/Src/PCompiler/CompilerCore/TypeChecker/Types/PrimitiveType.cs b/Src/PCompiler/CompilerCore/TypeChecker/Types/PrimitiveType.cs index 6bdfc4aecd..2ddb2db19d 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/Types/PrimitiveType.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/Types/PrimitiveType.cs @@ -28,7 +28,7 @@ private PrimitiveType(string name) : base(TypeKind.Base) break; default: - AllowedPermissions = new Lazy>(() => new List()); + AllowedPermissions = new Lazy>(() => new List()); break; } } @@ -36,7 +36,7 @@ private PrimitiveType(string name) : base(TypeKind.Base) public override string OriginalRepresentation { get; } public override string CanonicalRepresentation { get; } - public override Lazy> AllowedPermissions { get; } + public override Lazy> AllowedPermissions { get; } public override bool IsAssignableFrom(PLanguageType otherType) { diff --git a/Src/PCompiler/CompilerCore/TypeChecker/Types/SequenceType.cs b/Src/PCompiler/CompilerCore/TypeChecker/Types/SequenceType.cs index f2ca29484a..04259e2a6c 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/Types/SequenceType.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/Types/SequenceType.cs @@ -16,7 +16,7 @@ public SequenceType(PLanguageType elementType) : base(TypeKind.Sequence) public override string OriginalRepresentation => $"seq[{ElementType.OriginalRepresentation}]"; public override string CanonicalRepresentation => $"seq[{ElementType.CanonicalRepresentation}]"; - public override Lazy> AllowedPermissions => ElementType.AllowedPermissions; + public override Lazy> AllowedPermissions => ElementType.AllowedPermissions; public override bool IsAssignableFrom(PLanguageType otherType) { diff --git a/Src/PCompiler/CompilerCore/TypeChecker/Types/SetType.cs b/Src/PCompiler/CompilerCore/TypeChecker/Types/SetType.cs index 09bc7c912d..9bcac127dc 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/Types/SetType.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/Types/SetType.cs @@ -16,7 +16,7 @@ public SetType(PLanguageType elementType) : base(TypeKind.Set) public override string OriginalRepresentation => $"set[{ElementType.OriginalRepresentation}]"; public override string CanonicalRepresentation => $"set[{ElementType.CanonicalRepresentation}]"; - public override Lazy> AllowedPermissions => ElementType.AllowedPermissions; + public override Lazy> AllowedPermissions => ElementType.AllowedPermissions; public override bool IsAssignableFrom(PLanguageType otherType) { diff --git a/Src/PCompiler/CompilerCore/TypeChecker/Types/TupleType.cs b/Src/PCompiler/CompilerCore/TypeChecker/Types/TupleType.cs index b9919c0728..60e8676ca3 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/Types/TupleType.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/Types/TupleType.cs @@ -15,7 +15,7 @@ public TupleType(params PLanguageType[] types) : base(TypeKind.Tuple) CanonicalRepresentation = $"({string.Join(",", Types.Select(type => type.CanonicalRepresentation))})"; AllowedPermissions = Types.Any(t => t.AllowedPermissions == null) ? null - : new Lazy>(() => Types.SelectMany(t => t.AllowedPermissions.Value).ToList()); + : new Lazy>(() => Types.SelectMany(t => t.AllowedPermissions.Value).ToList()); } // Lifts a TupleType into an equivalent NamedTupleType, where the names of each field are numbers @@ -40,7 +40,7 @@ public NamedTupleType ToNamedTuple() public override string CanonicalRepresentation { get; } - public override Lazy> AllowedPermissions { get; } + public override Lazy> AllowedPermissions { get; } public override bool IsAssignableFrom(PLanguageType otherType) { diff --git a/Src/PCompiler/CompilerCore/TypeChecker/Types/TypeDefType.cs b/Src/PCompiler/CompilerCore/TypeChecker/Types/TypeDefType.cs index 6a2db4053a..9a49089b5f 100644 --- a/Src/PCompiler/CompilerCore/TypeChecker/Types/TypeDefType.cs +++ b/Src/PCompiler/CompilerCore/TypeChecker/Types/TypeDefType.cs @@ -17,7 +17,7 @@ public TypeDefType(TypeDef typeDef) : base(TypeKind.TypeDef) public override string OriginalRepresentation => TypeDefDecl.Name; public override string CanonicalRepresentation => TypeDefDecl.Type.CanonicalRepresentation; - public override Lazy> AllowedPermissions { get; } + public override Lazy> AllowedPermissions { get; } public override bool IsAssignableFrom(PLanguageType otherType) { diff --git a/Src/PCompiler/PCommandLine/CheckFileValidity.cs b/Src/PCompiler/PCommandLine/CheckFileValidity.cs index cc58d742a4..84e1700778 100644 --- a/Src/PCompiler/PCommandLine/CheckFileValidity.cs +++ b/Src/PCompiler/PCommandLine/CheckFileValidity.cs @@ -3,13 +3,13 @@ namespace Plang; -public class CheckFileValidity +public static partial class CheckFileValidity { #region Functions to check if the commandline inputs are legal public static bool IsLegalProjectName(string projectName) { - return Regex.IsMatch(projectName, "^[A-Za-z_][A-Za-z_0-9]*$"); + return MyRegex().IsMatch(projectName); } public static bool IsPFile(string fileName) @@ -68,5 +68,8 @@ public static bool IsLegalPProjFile(string fileName, out FileInfo file) return true; } + [GeneratedRegex("^[A-Za-z_][A-Za-z_0-9]*$")] + private static partial Regex MyRegex(); + #endregion Functions to check if the commandline inputs are legal } \ No newline at end of file diff --git a/Src/PCompiler/PCommandLine/CommandLine.cs b/Src/PCompiler/PCommandLine/CommandLine.cs index 5fc655fe0c..14c01e6b5e 100644 --- a/Src/PCompiler/PCommandLine/CommandLine.cs +++ b/Src/PCompiler/PCommandLine/CommandLine.cs @@ -3,7 +3,7 @@ using System.Linq; using PChecker; using PChecker.IO.Debugging; -using PChecker.Scheduling; +using PChecker.Testing; using Plang.Compiler; using Plang.Options; @@ -92,9 +92,9 @@ private static void RunChecker(string[] args) /// private static void OnProcessCanceled(object sender, EventArgs e) { - if (!TestingProcessScheduler.IsProcessCanceled) + if (!TestingProcess.IsProcessCanceled) { - TestingProcessScheduler.IsProcessCanceled = true; + TestingProcess.IsProcessCanceled = true; Shutdown(); } } diff --git a/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs b/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs index da2e3699a1..2175c5b28f 100644 --- a/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs +++ b/Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs @@ -184,7 +184,6 @@ private static void UpdateConfigurationWithParsedArgument(CheckerConfiguration c checkerConfiguration.IsVerbose = true; break; case "debug": - checkerConfiguration.EnableDebugging = true; Debug.IsEnabled = true; break; case "timeout": diff --git a/Tst/RegressionTests/Feature1SMLevelDecls/Correct/EntryNamedFunction/EntryNamedFunction.p b/Tst/RegressionTests/Feature1SMLevelDecls/Correct/EntryNamedFunction/EntryNamedFunction.p index b2cfd199ed..40b2c25811 100644 --- a/Tst/RegressionTests/Feature1SMLevelDecls/Correct/EntryNamedFunction/EntryNamedFunction.p +++ b/Tst/RegressionTests/Feature1SMLevelDecls/Correct/EntryNamedFunction/EntryNamedFunction.p @@ -1,21 +1,20 @@ - -/* PSrc/FrontDesk.p */ type tRoomInfo = (roomNumber: int, isAvailable: bool); machine Main { - var rooms: map[int, tRoomInfo]; + start state Init { + entry { + new m1(default(map[int, tRoomInfo])); + } + } +} +machine m1 { start state Init { entry Init_Entry; - exit { - assert true; - } } fun Init_Entry(initialRooms: map[int, tRoomInfo]) { - new Main(default(map[int, tRoomInfo])); + assert true; } -} - - +} \ No newline at end of file diff --git a/Tst/RegressionTests/Feature1SMLevelDecls/StaticError/StartMachineNullParam/StartMachineNullParam.p b/Tst/RegressionTests/Feature1SMLevelDecls/StaticError/StartMachineNullParam/StartMachineNullParam.p new file mode 100644 index 0000000000..08ff9d4f9d --- /dev/null +++ b/Tst/RegressionTests/Feature1SMLevelDecls/StaticError/StartMachineNullParam/StartMachineNullParam.p @@ -0,0 +1,8 @@ +machine Main { + start state Init { + entry (payload: int) {}; + exit { + assert true; + } + } +} diff --git a/Tst/RegressionTests/Feature2Stmts/Correct/goto2/goto2.p b/Tst/RegressionTests/Feature2Stmts/Correct/goto2/goto2.p new file mode 100644 index 0000000000..db886ff2ac --- /dev/null +++ b/Tst/RegressionTests/Feature2Stmts/Correct/goto2/goto2.p @@ -0,0 +1,16 @@ +/******************** + * This example tests goto with payload on state machine + * ******************/ + + machine Main { + start state Init { + entry { + goto S, 1000; + } + } + state S { + entry (payload: int) { + assert (payload == 1000), format ("Expected payload to be 1000, actual payload is {0}", payload); + } + } +} \ No newline at end of file diff --git a/Tst/RegressionTests/Feature2Stmts/Correct/goto3/goto3.p b/Tst/RegressionTests/Feature2Stmts/Correct/goto3/goto3.p new file mode 100644 index 0000000000..4bc5da285a --- /dev/null +++ b/Tst/RegressionTests/Feature2Stmts/Correct/goto3/goto3.p @@ -0,0 +1,29 @@ +/******************** + * This example tests goto with payload on monitor + * ******************/ + + event E1; + + machine Main { + start state Init { + entry { + send this, E1; + } + on E1 do { + } + } +} + spec M observes E1 { + start state Init { + on E1 do { + goto S, 1000; + } + } + state S { + entry (payload: int) { + assert (payload == 1000), format ("Expected payload to be 1000, actual payload is {0}", payload); + } + } +} + +test DefaultImpl [main=Main]: assert M in { Main }; \ No newline at end of file diff --git a/Tst/RegressionTests/Feature2Stmts/Correct/goto4/goto4.p b/Tst/RegressionTests/Feature2Stmts/Correct/goto4/goto4.p new file mode 100644 index 0000000000..054ea467d3 --- /dev/null +++ b/Tst/RegressionTests/Feature2Stmts/Correct/goto4/goto4.p @@ -0,0 +1,33 @@ +/******************** + * This example tests raise with payload on monitor + * ******************/ + + event E1; + + machine Main { + start state Init { + entry { + send this, E1; + } + on E1 do { + } + } +} + spec M observes E1 { + start state Init { + on E1 do { + testFunc(); + assert false; + } + } + state S { + entry (payload: int) { + assert (payload == 1000), format ("Expected payload to be 1000, actual payload is {0}", payload); + } + } + fun testFunc() { + goto S, 1000; + } +} + +test DefaultImpl [main=Main]: assert M in { Main }; \ No newline at end of file diff --git a/Tst/RegressionTests/Feature2Stmts/Correct/newMachine1/newMachine1.p b/Tst/RegressionTests/Feature2Stmts/Correct/newMachine1/newMachine1.p new file mode 100644 index 0000000000..c6cf46262d --- /dev/null +++ b/Tst/RegressionTests/Feature2Stmts/Correct/newMachine1/newMachine1.p @@ -0,0 +1,16 @@ +machine Main { + start state Init { + entry { + new M2((n=1, s="payload string")); + } + } +} + +machine M2 { + start state Init { + entry(payload : (n: int, s: string)) { + assert payload.n == 1, format("Expected param: 1, actual received: {0}", payload.n); + assert payload.s == "payload string", format("Expected param: 'payload string', actual received: '{0}'", payload.s); + } + } +} diff --git a/Tst/RegressionTests/Feature2Stmts/Correct/raise1/raise1.p b/Tst/RegressionTests/Feature2Stmts/Correct/raise1/raise1.p new file mode 100644 index 0000000000..4455a9db44 --- /dev/null +++ b/Tst/RegressionTests/Feature2Stmts/Correct/raise1/raise1.p @@ -0,0 +1,17 @@ +/******************** + * This example tests raise with payload on state machine + * ******************/ + + event E1: int; + + machine Main { + start state Init { + entry { + raise E1, 1000; + assert false; + } + on E1 do (payload: int) { + assert (payload == 1000), format ("Expected payload to be 1000, actual payload is {0}", payload); + } + } +} \ No newline at end of file diff --git a/Tst/RegressionTests/Feature2Stmts/Correct/raise2/raise2.p b/Tst/RegressionTests/Feature2Stmts/Correct/raise2/raise2.p new file mode 100644 index 0000000000..0f80187bfd --- /dev/null +++ b/Tst/RegressionTests/Feature2Stmts/Correct/raise2/raise2.p @@ -0,0 +1,29 @@ +/******************** + * This example tests raise with payload on monitor + * ******************/ + + event E1; + event E2: int; + + machine Main { + start state Init { + entry { + send this, E1; + } + on E1 do { + } + } +} + spec M observes E1, E2 { + start state Init { + on E1 do { + raise E2, 1000; + assert false; + } + on E2 do (payload: int) { + assert (payload == 1000), format ("Expected payload to be 1000, actual payload is {0}", payload); + } + } +} + +test DefaultImpl [main=Main]: assert M in { Main }; \ No newline at end of file diff --git a/Tst/RegressionTests/Feature2Stmts/Correct/raise3/raise3.p b/Tst/RegressionTests/Feature2Stmts/Correct/raise3/raise3.p new file mode 100644 index 0000000000..9846dcbc22 --- /dev/null +++ b/Tst/RegressionTests/Feature2Stmts/Correct/raise3/raise3.p @@ -0,0 +1,32 @@ +/******************** + * This example tests raise with payload on monitor + * ******************/ + + event E1; + event E2: int; + + machine Main { + start state Init { + entry { + send this, E1; + } + on E1 do { + } + } +} + spec M observes E1, E2 { + start state Init { + on E1 do { + testFunc(); + assert false; + } + on E2 do (payload: int) { + assert (payload == 1000), format ("Expected payload to be 1000, actual payload is {0}", payload); + } + } + fun testFunc() { + raise E2, 1000; + } +} + +test DefaultImpl [main=Main]: assert M in { Main }; \ No newline at end of file diff --git a/Tst/RegressionTests/Feature2Stmts/DynamicError/goto2/goto2.p b/Tst/RegressionTests/Feature2Stmts/DynamicError/goto2/goto2.p new file mode 100644 index 0000000000..ca3fe4497b --- /dev/null +++ b/Tst/RegressionTests/Feature2Stmts/DynamicError/goto2/goto2.p @@ -0,0 +1,16 @@ +/******************** + * This example tests goto with payload on state machine + * ******************/ + + machine Main { + start state Init { + entry { + goto S, 1000; + } + } + state S { + entry (payload: int) { + assert (payload != 1000), format ("Expected payload to be 1000, actual payload is {0}", payload); + } + } +} \ No newline at end of file diff --git a/Tst/RegressionTests/Feature2Stmts/DynamicError/goto3/goto3.p b/Tst/RegressionTests/Feature2Stmts/DynamicError/goto3/goto3.p new file mode 100644 index 0000000000..1d94e778c3 --- /dev/null +++ b/Tst/RegressionTests/Feature2Stmts/DynamicError/goto3/goto3.p @@ -0,0 +1,29 @@ +/******************** + * This example tests goto with payload on monitor + * ******************/ + + event E1; + + machine Main { + start state Init { + entry { + send this, E1; + } + on E1 do { + } + } +} + spec M observes E1 { + start state Init { + on E1 do { + goto S, 1000; + } + } + state S { + entry (payload: int) { + assert (payload != 1000), format ("Expected payload to be 1000, actual payload is {0}", payload); + } + } +} + +test DefaultImpl [main=Main]: assert M in { Main }; \ No newline at end of file diff --git a/Tst/RegressionTests/Feature2Stmts/DynamicError/goto4/goto4.p b/Tst/RegressionTests/Feature2Stmts/DynamicError/goto4/goto4.p new file mode 100644 index 0000000000..a407985420 --- /dev/null +++ b/Tst/RegressionTests/Feature2Stmts/DynamicError/goto4/goto4.p @@ -0,0 +1,33 @@ +/******************** + * This example tests raise with payload on monitor + * ******************/ + + event E1; + + machine Main { + start state Init { + entry { + send this, E1; + } + on E1 do { + } + } +} + spec M observes E1 { + start state Init { + on E1 do { + testFunc(); + assert false; + } + } + state S { + entry (payload: int) { + assert (payload != 1000), format ("Expected payload to be 1000, actual payload is {0}", payload); + } + } + fun testFunc() { + goto S, 1000; + } +} + +test DefaultImpl [main=Main]: assert M in { Main }; \ No newline at end of file diff --git a/Tst/RegressionTests/Feature2Stmts/DynamicError/newMachine1/newMachine1.p b/Tst/RegressionTests/Feature2Stmts/DynamicError/newMachine1/newMachine1.p new file mode 100644 index 0000000000..405b8d5ed5 --- /dev/null +++ b/Tst/RegressionTests/Feature2Stmts/DynamicError/newMachine1/newMachine1.p @@ -0,0 +1,16 @@ +machine Main { + start state Init { + entry { + new M2((n=1, s="payload string")); + } + } +} + +machine M2 { + start state Init { + entry(payload : (n: int, s: string)) { + assert payload.n != 1, format("Expected param not equal to: 1, actual received: {0}", payload.n); + assert payload.s != "payload string", format("Expected param not equal to: 'payload string', actual received: '{0}'", payload.s); + } + } +} diff --git a/Tst/RegressionTests/Feature2Stmts/DynamicError/raise1/raise1.p b/Tst/RegressionTests/Feature2Stmts/DynamicError/raise1/raise1.p new file mode 100644 index 0000000000..ca4ccfc7c5 --- /dev/null +++ b/Tst/RegressionTests/Feature2Stmts/DynamicError/raise1/raise1.p @@ -0,0 +1,16 @@ +/******************** + * This example tests raise with payload on state machine + * ******************/ + + event E1: int; + + machine Main { + start state Init { + entry { + raise E1, 1000; + } + on E1 do (payload: int) { + assert (payload != 1000), format ("Expected payload to be 1000, actual payload is {0}", payload); + } + } +} \ No newline at end of file diff --git a/Tst/RegressionTests/Feature2Stmts/DynamicError/raise2/raise2.p b/Tst/RegressionTests/Feature2Stmts/DynamicError/raise2/raise2.p new file mode 100644 index 0000000000..6fc6d66e17 --- /dev/null +++ b/Tst/RegressionTests/Feature2Stmts/DynamicError/raise2/raise2.p @@ -0,0 +1,28 @@ +/******************** + * This example tests raise with payload on monitor + * ******************/ + + event E1; + event E2: int; + + machine Main { + start state Init { + entry { + send this, E1; + } + on E1 do { + } + } +} + spec M observes E1, E2 { + start state Init { + on E1 do { + raise E2, 1000; + } + on E2 do (payload: int) { + assert (payload != 1000), format ("Expected payload to be 1000, actual payload is {0}", payload); + } + } +} + +test DefaultImpl [main=Main]: assert M in { Main }; \ No newline at end of file diff --git a/Tst/RegressionTests/Feature2Stmts/DynamicError/raise3/raise3.p b/Tst/RegressionTests/Feature2Stmts/DynamicError/raise3/raise3.p new file mode 100644 index 0000000000..712da9b7d3 --- /dev/null +++ b/Tst/RegressionTests/Feature2Stmts/DynamicError/raise3/raise3.p @@ -0,0 +1,32 @@ +/******************** + * This example tests raise with payload on monitor + * ******************/ + + event E1; + event E2: int; + + machine Main { + start state Init { + entry { + send this, E1; + } + on E1 do { + } + } +} + spec M observes E1, E2 { + start state Init { + on E1 do { + testFunc(); + assert false; + } + on E2 do (payload: int) { + assert (payload != 1000), format ("Expected payload to be 1000, actual payload is {0}", payload); + } + } + fun testFunc() { + raise E2, 1000; + } +} + +test DefaultImpl [main=Main]: assert M in { Main }; \ No newline at end of file diff --git a/Tst/RegressionTests/Feature2Stmts/StaticError/goto2/goto2.p b/Tst/RegressionTests/Feature2Stmts/StaticError/goto2/goto2.p new file mode 100644 index 0000000000..f93a37aefa --- /dev/null +++ b/Tst/RegressionTests/Feature2Stmts/StaticError/goto2/goto2.p @@ -0,0 +1,16 @@ +/******************** + * This example tests goto with payload on state machine + * ******************/ + + machine Main { + start state Init { + entry { + goto S; + } + } + state S { + entry (payload: int) { + assert (payload == 1000), format ("Expected payload to be 1000, actual payload is {0}", payload); + } + } +} \ No newline at end of file diff --git a/Tst/RegressionTests/Feature2Stmts/StaticError/goto3/goto3.p b/Tst/RegressionTests/Feature2Stmts/StaticError/goto3/goto3.p new file mode 100644 index 0000000000..0fba8eb29b --- /dev/null +++ b/Tst/RegressionTests/Feature2Stmts/StaticError/goto3/goto3.p @@ -0,0 +1,29 @@ +/******************** + * This example tests goto with payload on monitor + * ******************/ + + event E1; + + machine Main { + start state Init { + entry { + send this, E1; + } + on E1 do { + } + } +} + spec M observes E1 { + start state Init { + on E1 do { + goto S; + } + } + state S { + entry (payload: int) { + assert (payload == 1000), format ("Expected payload to be 1000, actual payload is {0}", payload); + } + } +} + +test DefaultImpl [main=Main]: assert M in { Main }; \ No newline at end of file diff --git a/Tst/RegressionTests/Feature2Stmts/StaticError/newMachine1/newMachine1.p b/Tst/RegressionTests/Feature2Stmts/StaticError/newMachine1/newMachine1.p new file mode 100644 index 0000000000..52107606df --- /dev/null +++ b/Tst/RegressionTests/Feature2Stmts/StaticError/newMachine1/newMachine1.p @@ -0,0 +1,14 @@ +machine Main { + start state Init { + entry { + new M2(); + } + } +} + +machine M2 { + start state Init { + entry(payload : (n: int, s: string)) { + } + } +} diff --git a/Tst/RegressionTests/Feature2Stmts/StaticError/newMachine2/newMachine2.p b/Tst/RegressionTests/Feature2Stmts/StaticError/newMachine2/newMachine2.p new file mode 100644 index 0000000000..39e2dd28e6 --- /dev/null +++ b/Tst/RegressionTests/Feature2Stmts/StaticError/newMachine2/newMachine2.p @@ -0,0 +1,14 @@ +machine Main { + start state Init { + entry { + new M2((n="payload string", s=1)); + } + } +} + +machine M2 { + start state Init { + entry { + } + } +} diff --git a/Tst/RegressionTests/Feature2Stmts/StaticError/newMachine3/newMachine3.p b/Tst/RegressionTests/Feature2Stmts/StaticError/newMachine3/newMachine3.p new file mode 100644 index 0000000000..e63b768576 --- /dev/null +++ b/Tst/RegressionTests/Feature2Stmts/StaticError/newMachine3/newMachine3.p @@ -0,0 +1,15 @@ + +machine Main { + start state Init { + entry { + new M2((n="payload string", s=1)); + } + } +} + +machine M2 { + start state Init { + entry(payload : (n: int, s: string)) { + } + } +} diff --git a/Tst/RegressionTests/Feature2Stmts/StaticError/raise1/raise1.p b/Tst/RegressionTests/Feature2Stmts/StaticError/raise1/raise1.p new file mode 100644 index 0000000000..5173e279de --- /dev/null +++ b/Tst/RegressionTests/Feature2Stmts/StaticError/raise1/raise1.p @@ -0,0 +1,16 @@ +/******************** + * This example tests raise with payload on state machine + * ******************/ + + event E1: int; + + machine Main { + start state Init { + entry { + raise E1; + } + on E1 do (payload: int) { + assert (payload == 1000), format ("Expected payload to be 1000, actual payload is {0}", payload); + } + } +} \ No newline at end of file diff --git a/Tst/RegressionTests/Feature2Stmts/StaticError/raise2/raise2.p b/Tst/RegressionTests/Feature2Stmts/StaticError/raise2/raise2.p new file mode 100644 index 0000000000..7ebba5c6b2 --- /dev/null +++ b/Tst/RegressionTests/Feature2Stmts/StaticError/raise2/raise2.p @@ -0,0 +1,28 @@ +/******************** + * This example tests raise with payload on monitor + * ******************/ + + event E1; + event E2: int; + + machine Main { + start state Init { + entry { + send this, E1; + } + on E1 do { + } + } +} + spec M observes E1, E2 { + start state Init { + on E1 do { + raise E2; + } + on E2 do (payload: int) { + assert (payload == 1000), format ("Expected payload to be 1000, actual payload is {0}", payload); + } + } +} + +test DefaultImpl [main=Main]: assert M in { Main }; \ No newline at end of file diff --git a/Tst/UnitTests/CSharpValuesTest.cs b/Tst/UnitTests/CSharpValuesTest.cs index dccb6e8aad..963c4a8fa4 100644 --- a/Tst/UnitTests/CSharpValuesTest.cs +++ b/Tst/UnitTests/CSharpValuesTest.cs @@ -1,6 +1,5 @@ using NUnit.Framework; -using PChecker.PRuntime; -using PChecker.PRuntime.Values; +using PChecker.Runtime.Values; namespace UnitTests { @@ -8,10 +7,10 @@ namespace UnitTests public class CSharpValuesTest { [Test] - public void TestPrtBoolOverloading() + public void TestPBoolOverloading() { - PrtBool boolT = true; - PrtBool boolF = false; + PBool boolT = true; + PBool boolF = false; Assert.AreEqual(boolT, boolF || boolT); Assert.AreEqual(boolT, boolT || boolF); Assert.AreEqual(boolT, !boolF); @@ -20,33 +19,33 @@ public void TestPrtBoolOverloading() } [Test] - public void TestPrtFloatComparisions() + public void TestPFloatComparisions() { - PrtBool boolT = true; - PrtBool boolF = false; - Assert.AreEqual(boolT, PrtValues.Box(1.0) < PrtValues.Box(2.0)); - Assert.AreEqual(boolF, PrtValues.Box(1.0) < PrtValues.Box(1.0)); - Assert.AreEqual(boolT, PrtValues.Box(1.0) <= PrtValues.Box(1.0)); - Assert.AreEqual(boolT, PrtValues.Box(1.0) <= PrtValues.Box(2.0)); - Assert.AreEqual(boolT, PrtValues.Box(1.0) == PrtValues.Box(1.0)); - Assert.AreEqual(boolT, PrtValues.Box(1.0) != PrtValues.Box(2.0)); - Assert.AreEqual(boolT, PrtValues.Box(1.0) >= PrtValues.Box(1.0)); - Assert.AreEqual(boolT, PrtValues.Box(1.0) >= PrtValues.Box(0.0)); - Assert.AreEqual(boolT, PrtValues.Box(1.0) > PrtValues.Box(0.0)); + PBool boolT = true; + PBool boolF = false; + Assert.AreEqual(boolT, PValues.Box(1.0) < PValues.Box(2.0)); + Assert.AreEqual(boolF, PValues.Box(1.0) < PValues.Box(1.0)); + Assert.AreEqual(boolT, PValues.Box(1.0) <= PValues.Box(1.0)); + Assert.AreEqual(boolT, PValues.Box(1.0) <= PValues.Box(2.0)); + Assert.AreEqual(boolT, PValues.Box(1.0) == PValues.Box(1.0)); + Assert.AreEqual(boolT, PValues.Box(1.0) != PValues.Box(2.0)); + Assert.AreEqual(boolT, PValues.Box(1.0) >= PValues.Box(1.0)); + Assert.AreEqual(boolT, PValues.Box(1.0) >= PValues.Box(0.0)); + Assert.AreEqual(boolT, PValues.Box(1.0) > PValues.Box(0.0)); } [Test] - public void TestPrtFloatOverloading() + public void TestPFloatOverloading() { - PrtFloat float1 = 1.0; - PrtFloat float2 = 2.0; - PrtFloat float3 = 3.0; + PFloat float1 = 1.0; + PFloat float2 = 2.0; + PFloat float3 = 3.0; Assert.AreEqual(float3, float1 + float2); Assert.AreEqual(float1, float3 - float2); Assert.AreEqual(float2, float1 * float2); - Assert.AreEqual(PrtValues.Box(1.5), float3 / float2); - Assert.AreEqual(PrtValues.Box(6.0), float1 + float2 + float3); - Assert.AreEqual(PrtValues.Box(6.0), float1 * float2 * float3); + Assert.AreEqual(PValues.Box(1.5), float3 / float2); + Assert.AreEqual(PValues.Box(6.0), float1 + float2 + float3); + Assert.AreEqual(PValues.Box(6.0), float1 * float2 * float3); Assert.AreEqual(float1, float3 / (float1 + float2)); Assert.AreEqual(-float1, float2 - float3); Assert.AreEqual(+float1, float1); @@ -54,33 +53,33 @@ public void TestPrtFloatOverloading() } [Test] - public void TestPrtIntComparisions() + public void TestPIntComparisions() { - PrtBool boolT = true; - PrtBool boolF = false; - Assert.AreEqual(boolT, PrtValues.Box(1) < PrtValues.Box(2)); - Assert.AreEqual(boolF, PrtValues.Box(1) < PrtValues.Box(1)); - Assert.AreEqual(boolT, PrtValues.Box(1) <= PrtValues.Box(1)); - Assert.AreEqual(boolT, PrtValues.Box(1) <= PrtValues.Box(2)); - Assert.AreEqual(boolT, PrtValues.Box(1) == PrtValues.Box(1)); - Assert.AreEqual(boolT, PrtValues.Box(1) != PrtValues.Box(2)); - Assert.AreEqual(boolT, PrtValues.Box(1) >= PrtValues.Box(1)); - Assert.AreEqual(boolT, PrtValues.Box(1) >= PrtValues.Box(0)); - Assert.AreEqual(boolT, PrtValues.Box(1) > PrtValues.Box(0)); + PBool boolT = true; + PBool boolF = false; + Assert.AreEqual(boolT, PValues.Box(1) < PValues.Box(2)); + Assert.AreEqual(boolF, PValues.Box(1) < PValues.Box(1)); + Assert.AreEqual(boolT, PValues.Box(1) <= PValues.Box(1)); + Assert.AreEqual(boolT, PValues.Box(1) <= PValues.Box(2)); + Assert.AreEqual(boolT, PValues.Box(1) == PValues.Box(1)); + Assert.AreEqual(boolT, PValues.Box(1) != PValues.Box(2)); + Assert.AreEqual(boolT, PValues.Box(1) >= PValues.Box(1)); + Assert.AreEqual(boolT, PValues.Box(1) >= PValues.Box(0)); + Assert.AreEqual(boolT, PValues.Box(1) > PValues.Box(0)); } [Test] - public void TestPrtIntOverloading() + public void TestPIntOverloading() { - PrtInt int1 = 1; - PrtInt int2 = 2; - PrtInt int3 = 3; + PInt int1 = 1; + PInt int2 = 2; + PInt int3 = 3; Assert.AreEqual(int3, int1 + int2); Assert.AreEqual(int1, int3 - int2); Assert.AreEqual(int2, int1 * int2); Assert.AreEqual(int1, int3 / int2); - Assert.AreEqual(PrtValues.Box(6), int1 + int2 + int3); - Assert.AreEqual(PrtValues.Box(6), int1 * int2 * int3); + Assert.AreEqual(PValues.Box(6), int1 + int2 + int3); + Assert.AreEqual(PValues.Box(6), int1 * int2 * int3); Assert.AreEqual(int1, int3 / (int1 + int2)); Assert.AreEqual(-int1, int2 - int3); Assert.AreEqual(+int1, int1);