184 lines
12 KiB
Markdown
184 lines
12 KiB
Markdown
# Requirements: Tally - Cross-Platform Calculator
|
|
|
|
## Overview
|
|
|
|
A calculator application with three frontends (CLI, TUI, Android) sharing a common Zig engine. Supports standard arithmetic, a programmer mode with struct layout visualization, and financial calculations.
|
|
|
|
---
|
|
|
|
## Functional Requirements
|
|
|
|
### FR-1: Standard Calculation Mode
|
|
|
|
- **FR-1.1**: Parse and evaluate infix mathematical expressions with correct operator precedence (PEMDAS).
|
|
- **FR-1.2**: Support operators: `+`, `-`, `*`, `/`, `%` (modulo), `^` (power), unary `-`.
|
|
- **FR-1.3**: Support parentheses for grouping.
|
|
- **FR-1.4**: Support built-in functions: `sin`, `cos`, `tan`, `asin`, `acos`, `atan`, `log` (base-10), `ln` (natural), `sqrt`, `cbrt`, `abs`, `ceil`, `floor`, `round`, `factorial`.
|
|
- **FR-1.5**: Support constants: `pi`, `e`, `tau`.
|
|
- **FR-1.6**: Support variable storage (Ans for last result, named variables A-F, X, Y, Z).
|
|
- **FR-1.7**: Maintain calculation history with replay capability.
|
|
- **FR-1.8**: Support implicit multiplication (e.g., `2pi`, `3(4+5)`).
|
|
|
|
### FR-2: Programmer Mode
|
|
|
|
- **FR-2.1**: Accept input in decimal, hexadecimal (`0x`), octal (`0o`), and binary (`0b`) formats.
|
|
- **FR-2.2**: Simultaneously display results in all four bases (dec, hex, oct, bin).
|
|
- **FR-2.3**: Support configurable bit widths: 8, 16, 32, 64-bit.
|
|
- **FR-2.4**: Support bitwise operators: AND (`&`), OR (`|`), XOR (`^`), NOT (`~`), left shift (`<<`), right shift (logical `>>>`), arithmetic right shift (`>>`), rotate left (`rol`), rotate right (`ror`).
|
|
- **FR-2.5**: Display both signed (two's complement) and unsigned interpretations of the current value.
|
|
- **FR-2.6**: Visualize the bit pattern as a grid (integer.exposed style) - bits individually addressable/toggleable in TUI and Android.
|
|
- **FR-2.7**: Quick toggle between base display formats via dedicated keyboard shortcuts (TUI).
|
|
|
|
### FR-3: Struct Layout Visualizer (Programmer Mode Extension)
|
|
|
|
- **FR-3.1**: Accept struct definitions in a mini-DSL:
|
|
```
|
|
struct {
|
|
u32 x;
|
|
u8 flags;
|
|
u16 id;
|
|
u64 timestamp;
|
|
}
|
|
```
|
|
- **FR-3.2**: Compute and display total struct size in bytes.
|
|
- **FR-3.3**: Display per-field information: offset, size, alignment requirement.
|
|
- **FR-3.4**: Identify and highlight padding bytes between fields and at the end (tail padding).
|
|
- **FR-3.5**: Render a byte-level memory map showing which bytes belong to which field and which are padding.
|
|
- **FR-3.6**: Default to x86-64 System V ABI alignment rules.
|
|
- **FR-3.7**: Support switching ABI/alignment profiles (extensible design - future: Windows x64, ARM AAPCS, packed).
|
|
- **FR-3.8**: Support switching endianness display (little-endian default, big-endian available).
|
|
- **FR-3.9**: Supported field types (initial set): `u8`, `u16`, `u32`, `u64`, `i8`, `i16`, `i32`, `i64`, `f32`, `f64`, `bool`, `ptr` (pointer-sized, arch-dependent).
|
|
- **FR-3.10**: Show a "packed" comparison - display what the struct would look like with no padding vs. natural alignment.
|
|
|
|
### FR-4: Unit Conversions
|
|
|
|
- **FR-4.1**: Support inline unit conversion syntax: `<value> <from_unit> to <to_unit>` (e.g., `100 km to miles`, `72 F to C`).
|
|
- **FR-4.2**: Support unit conversions within expressions: `5 kg + 3 lb` evaluates in the left-hand unit.
|
|
- **FR-4.3**: Length: mm, cm, m, km, in, ft, yd, mi, nm (nautical mile).
|
|
- **FR-4.4**: Mass/Weight: mg, g, kg, oz, lb, ton, tonne.
|
|
- **FR-4.5**: Temperature: C (Celsius), F (Fahrenheit), K (Kelvin).
|
|
- **FR-4.6**: Time: ms, s, min, hr, day, week, year.
|
|
- **FR-4.7**: Digital storage: bit, byte, KB, MB, GB, TB, PB (both SI and binary: KiB, MiB, GiB, TiB).
|
|
- **FR-4.8**: Speed: m/s, km/h, mph, knots.
|
|
- **FR-4.9**: Area: mm2, cm2, m2, km2, in2, ft2, acre, hectare.
|
|
- **FR-4.10**: Volume: ml, L, gal, qt, pt, fl_oz, cm3, m3.
|
|
- **FR-4.11**: Energy: J, kJ, cal, kcal, Wh, kWh, BTU.
|
|
- **FR-4.12**: Pressure: Pa, kPa, bar, atm, psi, mmHg.
|
|
- **FR-4.13**: Data rate: bps, Kbps, Mbps, Gbps, B/s, KB/s, MB/s, GB/s.
|
|
- **FR-4.14**: Angle: deg, rad, grad, turn.
|
|
- **FR-4.15**: In CLI, support `tally "100 km to miles"` and `tally convert 100 km miles`.
|
|
- **FR-4.16**: In TUI, dedicated conversion panel accessible from any mode.
|
|
- **FR-4.17**: Unit system extensible - adding a new category requires only a conversion table, no parser changes.
|
|
|
|
### FR-5: Financial Mode
|
|
|
|
- **FR-5.1**: Compute CAGR given start value, end value, and number of periods.
|
|
- **FR-5.2**: Compute compound interest (future value given principal, rate, periods, compounding frequency).
|
|
- **FR-5.3**: Compute present value (discount future cash flow).
|
|
- **FR-5.4**: Support TVM (Time Value of Money) solver - given any 4 of: N, I/Y, PV, PMT, FV, solve for the 5th.
|
|
- **FR-5.5**: Display intermediate calculation steps/formula used (transparency).
|
|
|
|
### FR-6: CLI Frontend
|
|
|
|
- **FR-6.1**: Invoke as `tally "<expression>"` for standard mode evaluation.
|
|
- **FR-6.2**: Flag `--programmer` or `-p` for programmer mode: `tally -p "0xFF & 0x0F"`.
|
|
- **FR-6.3**: Flag `--bits <8|16|32|64>` to set bit width in programmer mode (default: 64).
|
|
- **FR-6.4**: Flag `--base <dec|hex|oct|bin>` to control primary output format (default: show all).
|
|
- **FR-6.5**: Subcommand `tally struct <definition_or_file>` for struct layout - accepts inline DSL string or path to a file containing the definition.
|
|
- **FR-6.6**: Subcommand `tally cagr <start> <end> <periods>` for quick CAGR.
|
|
- **FR-6.7**: Subcommand `tally tvm` with named flags (`--pv`, `--fv`, `--n`, `--rate`, `--pmt`) - omit one to solve for it.
|
|
- **FR-6.8**: Subcommand `tally convert <value> <from_unit> <to_unit>` for unit conversion.
|
|
- **FR-6.9**: Output format flags: `--json` for machine-readable output, plain text default.
|
|
- **FR-6.10**: Exit code 0 on success, non-zero on parse/evaluation errors with stderr message.
|
|
|
|
### FR-7: TUI Frontend
|
|
|
|
- **FR-7.1**: Full-screen terminal UI with mode tabs (Standard, Programmer, Financial, Convert).
|
|
- **FR-7.2**: Standard mode: expression input line, result display, scrollable history.
|
|
- **FR-7.3**: Programmer mode: bit grid (navigable with arrow keys, toggle with Space/Enter), simultaneous base displays, expression input.
|
|
- **FR-7.4**: Programmer mode struct sub-view: field list editor, live-updating memory map visualization.
|
|
- **FR-7.5**: Financial mode: form-style input for parameters, result display with formula breakdown.
|
|
- **FR-7.6**: Convert mode: select category, input value, select from/to units, live result.
|
|
- **FR-7.7**: Keyboard-driven navigation; no mouse required (mouse optional enhancement).
|
|
- **FR-7.8**: Quick-switch keys for base display in programmer mode (e.g., `d`=dec, `h`=hex, `o`=oct, `b`=bin to highlight primary).
|
|
- **FR-7.9**: Support terminal resize gracefully.
|
|
- **FR-7.10**: Vi-style and Emacs-style keybinding options for expression input.
|
|
|
|
### FR-8: Android Frontend
|
|
|
|
- **FR-8.1**: Native Android app using Kotlin and Jetpack Compose.
|
|
- **FR-8.2**: Call into the Zig engine via JNI (C ABI shared library).
|
|
- **FR-8.3**: Bottom navigation bar for mode switching (Standard, Programmer, Financial, Convert).
|
|
- **FR-8.4**: Standard mode: traditional calculator layout with button grid, expression display at top, result below.
|
|
- **FR-8.5**: Programmer mode: tappable bit grid, segmented control for bit width, base display cards, operator button row for bitwise ops.
|
|
- **FR-8.6**: Programmer mode struct sub-screen: text field for struct input, scrollable field table, color-coded memory map rendered as a custom Canvas composable.
|
|
- **FR-8.7**: Financial mode: card-based UI with input fields, dropdown for function selection (CAGR, TVM, etc.), compute button, result card with formula.
|
|
- **FR-8.8**: Convert mode: category picker (horizontal chips), from/to unit selectors, live conversion as user types.
|
|
- **FR-8.9**: Responsive layout for phone and tablet (multi-pane on tablet).
|
|
- **FR-8.10**: Follow Material Design 3 guidelines with dynamic color (Android 12+).
|
|
- **FR-8.11**: Haptic feedback on bit toggle and button presses.
|
|
- **FR-8.12**: Support landscape orientation with adapted layouts (wider bit grid, side-by-side panels).
|
|
|
|
---
|
|
|
|
## Non-Functional Requirements
|
|
|
|
### NFR-1: Performance
|
|
|
|
- Expression parsing and evaluation must complete in < 1ms for typical expressions.
|
|
- TUI must render at >= 30fps during interaction (bit toggling, navigation).
|
|
- Struct layout computation must handle structs with up to 256 fields without perceptible delay.
|
|
|
|
### NFR-2: Portability
|
|
|
|
- Engine, CLI, and TUI must compile and run on: Linux (x86-64, aarch64), macOS (aarch64, x86-64), Windows (x86-64).
|
|
- Android engine .so must target: arm64-v8a, armeabi-v7a, x86_64.
|
|
- Single `zig build` invocation to produce all desktop targets (cross-compilation).
|
|
|
|
### NFR-3: Correctness
|
|
|
|
- Floating-point arithmetic uses IEEE 754 double precision (64-bit).
|
|
- Programmer mode integer operations must be exact (no floating-point).
|
|
- Struct layout computation must match the actual layout produced by a C compiler under the specified ABI.
|
|
|
|
### NFR-4: Extensibility
|
|
|
|
- Adding a new ABI profile for struct layout requires implementing a single interface (alignment rules + pointer size).
|
|
- Adding new financial functions requires no changes to the parser - use a function-call syntax.
|
|
- Adding new unit categories/units requires only table entries, no parser changes.
|
|
- Engine exposes a stable C ABI for future frontends (e.g., WASM, iOS).
|
|
|
|
### NFR-5: Testability
|
|
|
|
- Engine must be testable in isolation (no I/O dependencies).
|
|
- Struct layout results must be verifiable against `pahole` or compiler output for reference structs.
|
|
- Engine test coverage target: >= 80% line coverage. The engine is pure computation with no I/O, so this is achievable and expected.
|
|
- Frontend coverage: best-effort via integration and smoke tests (TUI key-sequence tests, Android instrumented tests). No hard coverage target on frontend code.
|
|
- All public engine API functions must have corresponding unit tests covering happy path, error cases, and edge cases.
|
|
|
|
### NFR-6: Build & Distribution
|
|
|
|
- **Zig build system for everything.** A single `zig build` invocation at the workspace root handles all targets: engine, CLI, TUI, and Android .so cross-compilation. No Gradle required for the native library build - Gradle only wraps the prebuilt .so into the APK.
|
|
- **Mise for toolchain management.** All required toolchains (Zig version, Android NDK if needed for validation) are declared in `.mise.toml` at the project root. A developer needs only `mise` installed - running `mise install` provisions everything else.
|
|
- **No other system-level dependencies.** Outside of mise, a developer should not need to manually install Zig, Android SDK/NDK, or any other toolchain. The `.mise.toml` is the single source of truth for tool versions.
|
|
- **libvaxis for TUI.** The TUI frontend uses libvaxis (pulled as a Zig build dependency). No other TUI framework.
|
|
- Produce statically-linked binaries for CLI and TUI (no shared library dependencies on end-user system).
|
|
- Android: produce .so files for arm64-v8a, x86_64 via `zig build -Dtarget=aarch64-linux-android` (or similar). The Gradle project in `android/` consumes these prebuilt artifacts.
|
|
- Minimal runtime dependencies: Zig stdlib + libvaxis (TUI only). No other native deps.
|
|
|
|
### NFR-7: Number Display & Formatting
|
|
|
|
- Decimal numbers must use comma grouping for display (e.g., `4,294,967,295`).
|
|
- Scientific notation only when value exceeds 15 significant digits or absolute value > 10^15 / < 10^-15. Never jump to scientific notation for values that fit in a readable decimal.
|
|
- Programmer mode hex values display with underscore grouping per 16-bit word (e.g., `0xFFFF_FFFF`).
|
|
- Programmer mode binary values display grouped by nibble with spaces (e.g., `1111 1111`).
|
|
- All frontends must distinguish between "display format" (with separators) and "clipboard format" (raw, no separators).
|
|
- Android: long-press any result to copy the raw (no-separator) value to clipboard.
|
|
- TUI: yank command copies raw value to system clipboard.
|
|
- CLI: stdout output uses display format by default; `--raw` flag or `--json` gives unformatted values.
|
|
|
|
### NFR-8: Security
|
|
|
|
- C API must not use null-terminated strings. All string inputs take `(pointer, length)` pairs to prevent buffer overread.
|
|
- Engine must validate all input lengths before processing.
|
|
- No unbounded allocations from untrusted input (enforce maximum expression length, maximum struct field count).
|