# Status

`Status` is an error-accumulation object, not an exception. Functions that can fail report success or failure through their own `bool` return value; `Status` is passed alongside, by reference, purely to collect a human-readable message trail (and an error code) explaining *why*. This keeps the common control-flow path (checking `if (!foo(...))`) free of exception overhead while still letting an error be described in detail once it reaches code that reports it to the user. `Status` is declared in `status.h` and implemented in `status.cpp`.

## Codes

`Status::Code` enumerates the kinds of failure the simulator distinguishes: `OK`, `NotFound`, `Conflicting`, `BadVersion`, `BadArguments`, `BadConversion`, `CreationFailed`, `Redefinition`, `Syntax`, `Unsupported`, `Exception`, `DivZero`, `Range`, `LinearSolver`, `NonlinearSolver`, `Save`, `Domain`, `Recursion`, `Force`, `Analysis`, `Homotopy`, `AbortRequested`, `FinishRequested`, `StopRequested`, `Process`, and `InternalError`. Only the first code recorded by a chain of `set()` calls is meaningful for classifying the failure; later calls only add more message text (see below).

## Accumulating a message

A `Status` does not hold a stack of errors, just one growing `message_` string plus an `error` flag. The mutators differ in how they extend that string:

- **`set(Code c, msg)`** appends `msg` as a new line and, if `c != OK`, marks the status as an error. This is the call a function makes at the point where it first detects a failure.
- **`set(const Status& other)`** appends `other`'s message (if any) and ORs in its error flag. This is how a nested `Status` gets folded into the caller's `Status` when a helper builds its own local `Status` instead of receiving one.
- **`extend(msg)`** is `set(OK, msg)` - it appends a line without touching the error flag or introducing a new code. Callers up the stack use it to add context ("Failed to rebuild analysis structures.", "Failed to bind analysis outputs.", ...) as an error unwinds, without reclassifying the error itself. See the chain of `s.extend(...)` calls in `an.cpp` for the pattern.
- **`extend(const Loc& point)`** appends `point.toString()`, but only if `point` is a valid source location (`Loc::operator bool()`); a default/empty `Loc` is silently skipped. This attaches "at this point in the netlist" context to a message.
- **`prefix(msg)`** does the opposite of `extend()`: it puts `msg` *before* the existing message rather than after, for adding a heading in front of detail that has already accumulated.

Because messages are only ever appended to or prefixed, and the first non-`OK` code is what sets `error`, a `Status` records an ordered narrative of one failure as it propagates outward, not a structured list of distinct errors.

## The ignore mode and `Status::ignore`

Every mutator (`set`, `extend`, `prefix`, `clear`, move-assignment) checks `ignoreFlag` first and is a no-op when it is set. `Status::ignore` is a shared static instance constructed with `ignoreFlag=true`, and it is the default argument for essentially every `Status&` parameter in the codebase (e.g. `bool rebuild(Status& s=Status::ignore)`). This lets a caller that does not care about the failure reason simply omit the argument: the callee still calls `s.set(...)`/`s.extend(...)` as usual, but those calls do nothing because `s` is `Status::ignore`, and no message ever accumulates. `ignored()` reports whether a given `Status` is in this mode.

## Checking success

`Status` has no public way to ask "did an error occur" - the commented-out `operator bool()` in `status.h` is intentionally unused. The convention throughout the codebase is that the function being called reports success or failure through its own `bool` return value; `Status` is consulted only after that return value indicates failure, typically to print `status.message()` (see `simulator/main.cpp`, `an.cpp`, `corehb.cpp`):

```cpp
if (!Simulator::setup(modStr, incStr, status)) {
    Simulator::err() << status.message() << "\n";
    return 1;
}
```

## Other operations

- `message()` returns the accumulated text.
- `clear()` resets the message and error flag (a no-op when ignoring).
- `Status` is move-only: the copy constructor and copy assignment are deleted, and move assignment respects `ignoreFlag` the same way the mutators do (an ignoring `Status` discards the moved-from value instead of adopting it).
