model library Null safety

The model for the calculator, centered around Model. It retains the state of the calculator, most of which is saved persistently. It also functions as a helper to the controller, by providing states using the state pattern for calculator modes, like the DisplayMode and the SignMode. The overall structure looks like this:

The [Model] has a [Memory], which is the 406 nybble storage that's shared between [ProgramMemory] and [Registers]. Part of the model is the [LcdContents], which holds the data that ultimately gets displayed in the view's `LcdDisplay`. The model is only loosely coupled to the view, by making the display contents [Observable].


An error that should result in "Error x" being displayed on the LCD Display
A memento of a calculator state, plus the keystrokes after the state was captured. It's meant to be a tool to facilitate bug reports.
A logical model of what's being displayed on the LCD display. Handles flashing and blinking, and delayed display (like when clear-prefix is released).
DisplayModeSelector<R, A>
Helper to select something based on whether the calculator's display mode is one of the int modes, or float mode. We use a factory template to pull off dependency inversion between the model (us) and the controller, for the sake of OO purity. [...]
An object for helping with the "double" integer functions, double multiply, double divide and double remainder
Key<OT extends ProgramOperation>
The model's view of a key on the keyboard. The model needs to know where ProgramOperations are on the portrait layout of the keyboard, because they are displayed on the LCD display as row-column numbers.
A comparable data holder for the contents of what is displayed on the LCD
Memory<OT extends ProgramOperation>
The calculator's 406 nybble internal memory that holds registers and programs.
Model<OT extends ProgramOperation>
Our model, the main entry point to this module. See the library-level documentation for a description, and an explanation of the model's structure.
A bit of interface segregation: A reduced API of just the stuff int operations need from the model. This comes in handy for the double operations, and for dealing with the I register. I is always 68 bits long, regardless of the calculator's current word size.
A pretty bog-standard observable. Odd that Dart doesn't have one in the core library. [...]
OperationMap<OT extends ProgramOperation>
A representation of all of the operations. This is used by the model to assign op codes and labels to ProgramOperations.
ProgramInstruction<OT extends ProgramOperation>
An instruction in a program, consisting of a ProgramOperation and, sometimes, an argument value.
A listener that receives callbacks when a program delivers results to the user. This is used for testing.
ProgramMemory<OT extends ProgramOperation>
A representation of the calculator's 406 nybble data store as a list of program instructions. ProgramMemory takes over space from register storage as needed. We also keep the return stack for GSB instructions here, and the current program line.
The model's view of an operation.
A representation of the available memory as registers. "Available memory" is what's left over of the 406 nybble data store after the program's storage is deducted.
User settings that control the calculator's appearance or behavior
The state of which shift key was last pressed, if any.
Immutable calculator value [...]


Superclass for things that can be selected based on whether the f or g key, or neither, has been pressed. See It's a little like the Visitor pattern - a tyepsafe way of avoiding a switch statement on the shift key.