12 KiB
12 KiB
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 lbevaluates 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"andtally 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
--programmeror-pfor 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 tvmwith 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:
--jsonfor 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 buildinvocation 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
paholeor 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 buildinvocation 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.tomlat the project root. A developer needs onlymiseinstalled - runningmise installprovisions 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.tomlis 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 inandroid/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;
--rawflag or--jsongives 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).