492 lines
26 KiB
Markdown
492 lines
26 KiB
Markdown
# Tasks: Tally - Cross-Platform Calculator
|
|
|
|
## References
|
|
|
|
- #[[file:.kiro/specs/calculator/requirements.md]]
|
|
- #[[file:.kiro/specs/calculator/design.md]]
|
|
|
|
---
|
|
|
|
## Phase 1: Project Scaffolding & Engine Foundation
|
|
|
|
### Task 1.1: Initialize workspace build structure [DONE]
|
|
- Create `.mise.toml` declaring Zig version (pin to specific release)
|
|
- Create top-level `build.zig` with module declarations for engine, cli, tui
|
|
- Add Android cross-compilation targets to `build.zig` (`-Dtarget=aarch64-linux-android`, `-Dtarget=x86_64-linux-android`)
|
|
- Create `engine/build.zig` producing static lib and shared lib targets
|
|
- Create `cli/build.zig` linking engine
|
|
- Create `tui/build.zig` linking engine + libvaxis dependency
|
|
- Add `.gitignore`, `README.md` (minimal), `LICENSE`
|
|
- Verify: `mise install` provisions Zig, `zig build` compiles without errors on empty main files
|
|
|
|
NOTE: Actual structure diverged from spec - single binary at `src/main.zig`
|
|
(CLI + TUI combined), engine as static lib + shared lib. No separate cli/ or
|
|
tui/ build files. kcov-based coverage wired in via `build/Coverage.zig`.
|
|
|
|
### Task 1.2: Implement core types module [DONE]
|
|
- Create `engine/src/types.zig`
|
|
- Define `Value` union, `Integer` struct, `BitWidth`, `Signedness`, `Endianness` enums
|
|
- Define `MultiBaseResult` struct
|
|
- Define `CalcError` error set and `ErrorInfo` struct
|
|
- Define `Mode` enum (standard, programmer, financial)
|
|
- Verify: compiles, types are importable from other engine modules
|
|
|
|
### Task 1.3: Implement tokenizer [DONE]
|
|
- Create `engine/src/tokenizer.zig`
|
|
- Token types: numbers (dec, hex `0x`, oct `0o`, bin `0b`), operators, parens, identifiers, comma, semicolon, EOF
|
|
- Handle implicit multiplication detection (emit synthetic `*` token)
|
|
- Handle multi-character operators: `**`, `<<`, `>>`, `>>>`, `rol`, `ror`
|
|
- Support `_` and `,` as digit separators in number literals (e.g., `1_000_000`, `1,000,000`)
|
|
- Verify: unit tests for tokenizing expressions in all bases, edge cases (negative numbers, adjacent tokens for implicit mult)
|
|
|
|
NOTE: Implicit multiplication handled in parser rather than tokenizer.
|
|
Comma-as-separator only consumed when followed by a digit (avoids eating
|
|
function arg commas).
|
|
|
|
### Task 1.4: Implement Pratt parser [DONE]
|
|
- Create `engine/src/ast.zig` with AST node definitions
|
|
- Create `engine/src/parser.zig`
|
|
- Implement Pratt parser with precedence table from design doc
|
|
- Accept `Mode` parameter to resolve `^` ambiguity (power vs XOR)
|
|
- Handle function calls: `name(arg1, arg2, ...)`
|
|
- Handle variable assignment: `X = expr`
|
|
- Handle implicit multiplication
|
|
- Verify: unit tests parsing complex expressions, operator precedence, all bases, function calls, mode-dependent `^`
|
|
|
|
### Task 1.5: Implement standard mode evaluator [DONE]
|
|
- Create `engine/src/evaluator.zig`
|
|
- Environment struct with variables, history, config (in evaluator.zig, not separate file)
|
|
- Evaluate AST to `f64` for standard mode
|
|
- Implement built-in functions: sin, cos, tan, asin, acos, atan, log, ln, sqrt, cbrt, abs, ceil, floor, round, factorial
|
|
- Implement constants: pi, e, tau
|
|
- Implement variable storage and `Ans`
|
|
- Implement history recording
|
|
- Verify: unit tests for arithmetic, precedence, functions, variables, history recall
|
|
|
|
### Task 1.6: Implement programmer mode evaluator [DONE]
|
|
- Create `engine/src/programmer.zig`
|
|
- All operations on `Integer` (u64 storage, masked to bit_width)
|
|
- Implement bitwise operators: AND, OR, XOR, NOT, shifts, rotates
|
|
- Implement base conversion output (produce `MultiBaseResult`)
|
|
- Implement bit_pattern array generation
|
|
- Handle overflow/truncation per configured bit_width
|
|
- Signed vs unsigned interpretation
|
|
- Verify: unit tests for bitwise ops at all widths, base conversions, overflow behavior, sign extension
|
|
|
|
### Task 1.7: Implement number display formatter [DONE]
|
|
- Create `engine/src/formatter.zig`
|
|
- Define `FormattedValue` struct with `display` (human-readable) and `raw` (clipboard) strings
|
|
- Decimal formatting: comma-separated groups of 3 (`4,294,967,295`)
|
|
- Scientific notation only when value > 10^15 or < 10^-15 or > 15 significant digits
|
|
- Hex formatting: underscore per 16-bit word for value view (`0xFFFF_FFFF`), space per byte for memory view (`FF FF FF FF`)
|
|
- Binary formatting: space per nibble (`1111 1111 1111 1111`)
|
|
- Octal formatting: underscore per 3-digit group (`0o37_777_777_777`)
|
|
- All formatters produce both `display` and `raw` variants
|
|
- Respect bit width (don't show leading zeros beyond the configured width in short-form contexts)
|
|
- Verify: unit tests for all bases at all bit widths, edge cases (0, max values, negative signed values), scientific notation threshold
|
|
|
|
---
|
|
|
|
## Phase 2: Struct Layout & Financial Engines
|
|
|
|
### Task 2.1: Implement struct DSL tokenizer and parser
|
|
- Create `engine/src/struct_layout.zig`
|
|
- Tokenize: `struct`, `{`, `}`, `;`, type names, identifiers, `[`, `]`, numbers (for arrays)
|
|
- Parse into a list of `FieldDef` structs: `{ name, type, array_count? }`
|
|
- Support types: u8, u16, u32, u64, i8, i16, i32, i64, f32, f64, bool, ptr
|
|
- Verify: unit tests parsing valid structs, error messages for malformed input
|
|
|
|
### Task 2.2: Implement ABI profile interface and x86-64 System V profile
|
|
- Define `AbiProfile` struct with function pointers/vtable (field_layout, struct_alignment, tail_padding, pointer_size)
|
|
- Implement `x86_64_sysv` profile:
|
|
- u8/i8/bool -> size 1, align 1
|
|
- u16/i16 -> size 2, align 2
|
|
- u32/i32/f32 -> size 4, align 4
|
|
- u64/i64/f64/ptr -> size 8, align 8
|
|
- Struct alignment = max of field alignments
|
|
- Tail padding to struct alignment boundary
|
|
- Implement `packed` profile (all alignment = 1, no padding)
|
|
- Verify: unit tests matching `pahole` output for known structs
|
|
|
|
### Task 2.3: Implement layout computation
|
|
- Implement `compute_layout(fields, abi) -> StructLayoutResult`
|
|
- Generate per-field: offset, size, alignment, padding_before
|
|
- Generate byte-level map (`[]ByteInfo`) for visualization
|
|
- Compute totals: size, alignment, total padding bytes, padding percentage
|
|
- Compute "packed comparison" size
|
|
- Verify: unit tests with structs of varying complexity, compare against known C compiler layouts
|
|
|
|
### Task 2.4: Implement endianness display
|
|
- Given a `StructLayoutResult` and a set of field values (optional), show byte ordering
|
|
- Little-endian (default): LSB at lowest address
|
|
- Big-endian: MSB at lowest address
|
|
- This affects the byte-map visualization labels, not the layout computation itself
|
|
- Verify: unit test showing a u32 value's bytes in both endiannesses
|
|
|
|
### Task 2.5: Implement financial module
|
|
- Create `engine/src/financial.zig`
|
|
- Implement CAGR: `(end/start)^(1/n) - 1`
|
|
- Implement compound interest (future value): `PV * (1 + r/m)^(m*t)`
|
|
- Implement present value: `FV / (1 + r/m)^(m*t)`
|
|
- Implement TVM solver:
|
|
- Closed-form for FV, PV, PMT, N
|
|
- Newton-Raphson for I/Y (rate) with convergence check, max 1000 iterations, tolerance 1e-10
|
|
- Return step-by-step formula string alongside numeric result
|
|
- Verify: unit tests against known financial calculation results (textbook examples)
|
|
|
|
### Task 2.6: Implement unit conversion engine
|
|
- Create `engine/src/units.zig`
|
|
- Define `UnitCategory` enum and `UnitDef` struct (name, aliases, category, conversion factors)
|
|
- Implement conversion tables for all categories: length, mass, temperature, time, digital storage, speed, area, volume, energy, pressure, data rate, angle
|
|
- Implement `convert(value: f64, from: UnitDef, to: UnitDef) !f64`
|
|
- Temperature special case: formula-based conversion (C/F/K with offsets)
|
|
- Implement unit name resolution: given a string, find the matching `UnitDef` (supports aliases)
|
|
- Verify: unit tests for all conversion categories, round-trip accuracy, unknown unit error handling
|
|
|
|
---
|
|
|
|
## Phase 3: Engine Public API & C ABI
|
|
|
|
### Task 3.1: Implement engine public API
|
|
- Create `engine/src/engine.zig`
|
|
- `pub fn evaluate(env: *Environment, input: []const u8) !Value`
|
|
- `pub fn computeStructLayout(definition: []const u8, abi: AbiProfile, endian: Endianness) !StructLayoutResult`
|
|
- `pub fn computeCagr(start: f64, end: f64, periods: f64) !f64`
|
|
- `pub fn solveTvm(params: TvmParams) !TvmResult`
|
|
- `pub fn convert(value: f64, from_unit: []const u8, to_unit: []const u8) !ConvertResult`
|
|
- `pub fn formatMultiBase(integer: Integer) MultiBaseResult`
|
|
- Verify: integration tests exercising the full pipeline (string in -> result out)
|
|
|
|
### Task 3.2: Implement C API
|
|
- Create `engine/src/c_api.zig`
|
|
- Define `CalcString` (ptr + len) and `CalcResult` (json ptr/len + error ptr/len) extern structs
|
|
- `export fn tally_eval(expr_ptr, expr_len, mode, config_ptr, config_len) CalcResult`
|
|
- `export fn tally_struct_layout(def_ptr, def_len, abi_ptr, abi_len, endian) CalcResult`
|
|
- `export fn tally_convert(value, from_ptr, from_len, to_ptr, to_len) CalcResult`
|
|
- `export fn tally_result_free(result) void`
|
|
- `export fn tally_version(out_len) [*]const u8`
|
|
- **No null-terminated strings** - all inputs are (ptr, len) pairs
|
|
- JSON serialization for all result types
|
|
- Input length validation (reject > max expression length)
|
|
- Verify: build shared library, write a C test program that calls the API with known inputs and validates JSON output
|
|
|
|
### Task 3.3: Cross-compilation verification
|
|
- Verify `zig build` produces binaries for:
|
|
- `x86_64-linux-gnu`
|
|
- `aarch64-linux-gnu`
|
|
- `x86_64-macos`
|
|
- `aarch64-macos`
|
|
- `x86_64-windows-gnu`
|
|
- Verify `zig build` produces .so for Android targets:
|
|
- `aarch64-linux-android`
|
|
- `x86_64-linux-android`
|
|
- All targets invocable from the same `build.zig` via `-Dtarget=<triple>`
|
|
- Verify mise-provisioned Zig handles all targets without additional toolchain installs
|
|
- Document any target-specific issues or workarounds needed
|
|
|
|
---
|
|
|
|
## Phase 4: CLI Frontend
|
|
|
|
### Task 4.1: Implement CLI argument parsing [DONE]
|
|
- Single binary at `src/main.zig` (not separate cli/)
|
|
- Parse args: positional expression (multi-arg joined with spaces), `-p`/`--programmer`, `--help`, `--version`
|
|
- Subcommands (`struct`, `cagr`, `tvm`, `convert`) NOT YET IMPLEMENTED
|
|
- Verify: unit tests for arg parsing; `--help` prints usage
|
|
|
|
NOTE: Multi-arg joining implemented (`tally 2 + 2` works same as `tally "2+2"`).
|
|
Subcommands deferred until Phase 2 engine work is done.
|
|
|
|
### Task 4.2: Implement CLI output formatting [DONE]
|
|
- Standard mode: print result with comma formatting
|
|
- Programmer mode: print multi-base table (dec signed, dec unsigned, hex, bin)
|
|
- Struct mode: NOT YET IMPLEMENTED
|
|
- Financial mode: NOT YET IMPLEMENTED
|
|
- `--json` flag: NOT YET IMPLEMENTED
|
|
- Verify: unit tests for evaluate function output
|
|
|
|
### Task 4.3: CLI integration and error handling [DONE]
|
|
- Wire arg parser -> engine calls -> output formatter
|
|
- Map `CalcError` to user-friendly stderr messages
|
|
- Set exit codes: 0 success, 1 error
|
|
- Verify: unit tests for error paths
|
|
|
|
---
|
|
|
|
## Phase 5: TUI Frontend
|
|
|
|
### Task 5.1: Set up TUI skeleton [DONE]
|
|
- Single binary at `src/main.zig` + `src/tui.zig` (not separate tui/)
|
|
- libvaxis vxfw.App with custom Widget (eventHandler + drawFn)
|
|
- No args launches TUI; with args runs CLI
|
|
- Molokai color theme
|
|
- Verify: TUI launches, responds to Ctrl-C (quit)
|
|
|
|
### Task 5.2: Implement standard mode TUI view [DONE]
|
|
- Expression input via vxfw.TextField (gap buffer)
|
|
- Result display in scrollable history panel
|
|
- History navigation with up/down arrows (saves/restores current input)
|
|
- Ctrl-L clears history
|
|
- ? shows help overlay (keybindings, functions, constants, operators)
|
|
- Variables persist across expressions (assignment + Ans)
|
|
- Verify: can type expressions, see results, browse history
|
|
|
|
### Task 5.2.1: Inline multi-base result in standard mode [DONE]
|
|
- Engine: added `evalStringInfo` returning value + `has_nondecimal_literal` flag
|
|
(walks AST via `hasNonDecimalLiteral` to detect any hex/oct/bin number literal)
|
|
- Added `BitWidth.smallestFor(value)` helper
|
|
- CLI: when flag is true and result is a non-negative integer, shows hex/oct/bin below decimal
|
|
- TUI: history entries carry optional `details` lines; drawHistory reworked to
|
|
render variable-height entries (flat line list, newest anchored at bottom)
|
|
- Uses smallest standard bit width that holds the value
|
|
- Does NOT change evaluation (still f64, `^` still power) - display only
|
|
- Fractional/negative results show decimal only
|
|
- Verify: `0o777 - 0x0f` shows 496 plus hex/oct/bin; `3.14` decimal only;
|
|
`2 + 2` decimal only; `0xFF / 2` = 127.5 decimal only
|
|
|
|
### Task 5.3: Implement programmer mode TUI view - expression & base display [PARTIAL]
|
|
- Programmer mode accessible via Tab key
|
|
- Multi-base result display (dec signed, unsigned, hex, oct, bin)
|
|
- Bit grid with navigation (arrows) and toggling (Space)
|
|
- Width toggle (Ctrl-W cycles 8->16->32->64)
|
|
- Ctrl-B toggles focus between input and bit grid
|
|
- Expression evaluation through programmer engine
|
|
- DONE: basic passive display + expression input + bit grid toggling
|
|
- NOT DONE: editable fields (see Task 5.3.1)
|
|
|
|
### Task 5.3.1: Programmer mode editable fields rework [DONE]
|
|
- Replaced `bit_grid_active: bool` with `prog_field: ProgField` enum tracking focused field
|
|
- Up/Down arrows navigate between fields (bits, dec_signed, dec_unsigned, hex, oct, bin, expression)
|
|
- When a text field is focused, the input line shows the field label as prompt (e.g. "HEX> ")
|
|
- Enter in a non-expression field parses input as that base and updates prog_value
|
|
- Bit grid: left/right navigates bits, space toggles, up/down exits to adjacent field when at grid edge
|
|
- Focused field is visually highlighted (label gets inverse color)
|
|
- Removed Ctrl-B (field navigation replaces it)
|
|
- Expression field works as before (full programmer-mode expression evaluation)
|
|
- ASCII row under HEX (read-only, xxd-style, aligned column-for-column)
|
|
- Endianness toggle (Ctrl-E): flips HEX and ASCII byte order, header shows LE/BE.
|
|
Default big-endian so HEX reads as the number (matching DEC/OCT/BIN); LE is the
|
|
opt-in x86-64 memory-layout view. DEC/OCT/BIN and the hex `raw`/clipboard form
|
|
are unaffected. Covered by formatter unit tests (BE and LE for hex and ascii).
|
|
- Verify: can arrow between fields, type hex value and see all fields update, toggle bits
|
|
|
|
### Task 5.3.2: Implement text/ASCII literal parsing [DONE]
|
|
- Added single-quote string token to the tokenizer (`'hello'`)
|
|
- Parser recognizes string literals as a new AST node type
|
|
- Programmer evaluator packs ASCII bytes into u128 value (BE packing: first char -> MSB)
|
|
- Standard evaluator also supports it (returns f64)
|
|
- Enforces max length = bit_width / 8 (Overflow error if too many chars)
|
|
- Rejects non-ASCII characters (> 0x7F)
|
|
- 128-bit width also added (u64 -> u128 throughout engine)
|
|
- Verify: `'A'` = 0x41, `'ELF'` = 0x454C46, overflow on too-long strings
|
|
|
|
### Task 5.3.3: Implement IEEE 754 float interpretation [NOT STARTED]
|
|
- Add float interpretation engine module (`engine/src/float_interp.zig`)
|
|
- Given a u32 or u64 bit pattern, decompose into sign, exponent, significand
|
|
- Compute exact decimal value (including denormals, infinities, NaN)
|
|
- Compute ULP (delta to next/previous representable value)
|
|
- Classify: normal, denormal, zero, +inf, -inf, quiet NaN, signaling NaN
|
|
- Given a decimal float, find the closest IEEE 754 bit pattern and report rounding
|
|
- TUI sub-view (Ctrl-F toggles float interpretation overlay in programmer mode):
|
|
- Color-coded bit grid (sign=pink, exponent=cyan, significand=green)
|
|
- Formula display, classification, ULP, exact value
|
|
- Typing a float value shows its bit pattern
|
|
- Auto-switch to 32-bit or 64-bit width based on selected float format
|
|
- Support float32 and float64 formats
|
|
- Verify: 0x3F800000 = 1.0 (float32), special values display correctly,
|
|
bit toggling updates float display, `3.14` shows nearest representation
|
|
|
|
### Task 5.4: Implement programmer mode TUI view - bit grid [DONE - merged into 5.3]
|
|
- Bit grid widget: 8 bits per group, groups separated by space
|
|
- Arrow key navigation (left/right moves cursor across bits, up/down between rows for 32/64-bit)
|
|
- Space/Enter toggles the bit under cursor
|
|
- Bit changes immediately reflected in all base displays
|
|
- Typing a value in the expression input updates the grid
|
|
- Toggling bits updates the expression/result displays
|
|
- Verify: can navigate grid, toggle bits, see values change in real-time
|
|
|
|
### Task 5.5: Implement struct visualizer TUI view
|
|
- Create `tui/src/views/struct_viz.zig`
|
|
- Text input for struct definition (multi-line mini editor or single-line with parsing)
|
|
- Live-updating field table (offset, size, align, padding)
|
|
- Memory map visualization (byte grid with color-coded fields and padding)
|
|
- ABI toggle (`a` key), endian toggle (`e` key)
|
|
- "Packed comparison" shown at bottom
|
|
- Transition: from programmer mode, press a key (e.g., `S`) to enter struct sub-view, Esc to return
|
|
- Verify: can enter struct definition, see layout update, toggle ABI/endian
|
|
|
|
### Task 5.6: Implement financial mode TUI view
|
|
- Create `tui/src/views/financial.zig`
|
|
- Form-style interface: labeled input fields for each financial function
|
|
- Sub-mode selector: CAGR, Compound Interest, TVM
|
|
- For TVM: 5 input fields, leave one empty to solve
|
|
- Result display with formula breakdown
|
|
- Verify: can input values, compute results, see formula steps
|
|
|
|
### Task 5.7: Implement unit conversion TUI view
|
|
- Create `tui/src/views/convert.zig`
|
|
- Category selector (navigable list or hotkeys)
|
|
- From-value input field, from-unit selector
|
|
- To-unit selector, live-updating result
|
|
- Quick swap (from ↔ to) key
|
|
- Show conversion factor used
|
|
- Verify: can select category, units, enter value, see live result update
|
|
|
|
### Task 5.8: TUI polish and keybindings
|
|
- Implement `?` for help overlay showing all keybindings
|
|
- Implement vi-style input mode (optional: Esc for normal mode, i for insert) - configurable
|
|
- Mouse support: click on bit grid to toggle, click on tabs to switch modes
|
|
- Color theme (sensible defaults, respects terminal capabilities)
|
|
- Verify: help overlay works, mouse interactions work, looks reasonable in 80x24 terminal
|
|
|
|
---
|
|
|
|
## Phase 6: Android App
|
|
|
|
### Task 6.1: Set up Android project structure
|
|
- Create `android/` directory with Gradle project (Kotlin DSL)
|
|
- Configure for Compose, minimum SDK 26 (Android 8.0), Material 3
|
|
- Create JNI bridge class `TallyEngine.kt` with `external fun` declarations
|
|
- Set up `jniLibs/` directory structure for arm64-v8a, x86_64
|
|
- Native .so files produced by `zig build -Dtarget=aarch64-linux-android` (etc.) - Gradle does not invoke Zig, it consumes prebuilt artifacts
|
|
- Set up bottom navigation bar (Standard, Programmer, Financial, Convert)
|
|
- Verify: `zig build -Dtarget=aarch64-linux-android` produces libtally.so; Gradle project builds and empty app launches with nav bar
|
|
|
|
### Task 6.2: Implement JNI bridge
|
|
- Kotlin side: `TallyEngine.evaluate(expr, mode, config): String` (returns JSON)
|
|
- Kotlin side: `TallyEngine.structLayout(definition, abi, endian): String`
|
|
- Kotlin side: `TallyEngine.convert(value, fromUnit, toUnit): String`
|
|
- JSON deserialization into Kotlin data classes (Value, MultiBaseResult, StructLayoutResult, ConvertResult, etc.)
|
|
- Error handling: parse error JSON, surface to UI
|
|
- Verify: unit tests calling native functions with known inputs, validating deserialized results
|
|
|
|
### Task 6.3: Implement standard calculator screen
|
|
- Compose UI: expression display at top (scrollable, natural format), live result preview
|
|
- Button grid: digits, operators, functions (swipeable function row for sin/cos/log/etc.)
|
|
- History peek below expression (last 2-3 results), pull-down for full history
|
|
- ViewModel: manages expression state, calls engine, stores history
|
|
- Long-press `=` to copy result, tap history items to recall
|
|
- Verify: can perform calculations, see results, scroll history
|
|
|
|
### Task 6.4: Implement programmer mode screen
|
|
- Compose UI: segmented control for bit width (8/16/32/64)
|
|
- Value display cards: DEC, HEX, OCT, BIN, signed/unsigned (tappable to switch primary input base)
|
|
- Bit grid: custom Canvas composable, tappable cells with bit index labels, haptic on toggle
|
|
- Operator button row: AND, OR, XOR, NOT, <<, >>, ROL, ROR
|
|
- Hex digit buttons (A-F) + numeric keypad + base prefix buttons (0x, 0b)
|
|
- All displays update instantly on bit toggle or expression entry
|
|
- FAB/toolbar button navigating to struct layout sub-screen
|
|
- Verify: bit toggling works, base displays update, expressions evaluate
|
|
|
|
### Task 6.5: Implement struct visualizer screen
|
|
- Navigation: accessed from programmer mode via toolbar button
|
|
- Form-based struct builder: type dropdown + name field per row, add/remove/reorder fields
|
|
- Toggle for raw DSL text input (for power users / copy-paste from code)
|
|
- Memory map: custom Canvas composable with color-coded byte bar, tappable segments highlighting field info
|
|
- Summary card: total size, alignment, padding bytes/percentage, packed comparison
|
|
- ABI dropdown selector, endian dropdown selector
|
|
- Verify: can add fields visually, see layout update, toggle between form and raw DSL
|
|
|
|
### Task 6.6: Implement financial calculator screen
|
|
- Compose UI: scrollable chip row for function selection (CAGR, TVM, Compound Interest, Present Value)
|
|
- Card-based input form adapting to selected function
|
|
- For TVM: 5 labeled input fields, user leaves one blank to indicate solve target
|
|
- Compute button, result card with animated appearance
|
|
- Expandable formula breakdown section
|
|
- Long-press result to copy
|
|
- Verify: all financial calculations produce correct results, formula display works
|
|
|
|
### Task 6.7: Implement unit conversion screen
|
|
- Compose UI: scrollable category chip row at top
|
|
- Large editable number input (top), from-unit selector dropdown
|
|
- Swap button (animated rotation) between from/to
|
|
- Live result display (bottom), to-unit selector dropdown
|
|
- Numeric keypad (no expression input needed - just digits, decimal, sign)
|
|
- Unit selectors open searchable bottom sheets
|
|
- Conversion updates live as user types (no "calculate" button)
|
|
- Verify: live conversion works, category switching filters units, swap works
|
|
|
|
### Task 6.8: Android polish
|
|
- Material 3 theming (dynamic color on Android 12+)
|
|
- Tablet layout: two-pane (input left, results/visualization right)
|
|
- Landscape orientation: adapted layouts (wider bit grid, side-by-side panels)
|
|
- Haptic feedback on bit toggle and button presses
|
|
- Screen rotation state preservation
|
|
- App icon, splash screen
|
|
- Verify: looks correct on phone and tablet, handles rotation, haptics fire
|
|
|
|
---
|
|
|
|
## Phase 7: Testing & Release
|
|
|
|
### Task 7.1: Comprehensive engine test suite [DONE]
|
|
- **Target: >= 80% line coverage on engine code** -- ACHIEVED: 99.69% (1607/1612 lines)
|
|
- 222 unit tests passing across engine + CLI modules (208 in the engine coverage run)
|
|
- Tokenizer tests: all bases, underscores/commas/spaces separators, string literals,
|
|
invalid/unrecognized characters, bare `<`/`>`, lone dot, huge-decimal float fallback
|
|
- Parser tests: precedence/associativity, unary ops, function calls (incl. unmatched
|
|
paren in args), keyword operators, assignment, error paths, infix-position identifier
|
|
- Evaluator tests: arithmetic, precedence, functions, variables/Ans, string literals in
|
|
standard mode (ASCII packing + non-ASCII rejection), zero/two/three-arg unknown fns, rand()
|
|
- Programmer tests: bitwise/shift/rotate at all widths, two's-complement negation, ASCII
|
|
literal packing + overflow, float-literal truncation, shift-amount >= width clamping
|
|
- Formatter tests: all bases, all bit widths, scientific notation threshold boundaries
|
|
- Coverage measured via `zig build coverage` (kcov-based)
|
|
- Remaining 5 uncovered lines are unreachable defensive branches (parser `tokenToBinaryOp`/
|
|
`keywordBinaryOp` fallbacks, gated by `infixPrecedence`) and `or` short-circuits inside
|
|
test assertions -- not worth contorting the code to reach
|
|
- Verify: coverage report shows 99.69% on engine modules (well above the >= 80% gate)
|
|
|
|
### Task 7.2: Integration tests
|
|
- CLI end-to-end tests (run binary, check stdout/stderr/exit code)
|
|
- TUI smoke tests (script key sequences, verify screen output via libvaxis test mode if available)
|
|
- Android instrumented tests for JNI bridge
|
|
|
|
### Task 7.3: CI/CD setup
|
|
- Forgejo Actions workflow (at `git.lerch.org/lobo/tally`):
|
|
- Use mise to provision toolchains (same `.mise.toml` as local dev)
|
|
- Build + test on Linux, macOS, Windows
|
|
- Enforce >= 80% engine coverage (fail CI if below)
|
|
- Cross-compile all targets
|
|
- Build Android .so files
|
|
- Release workflow: produce platform binaries as Forgejo release artifacts
|
|
- Android: produce signed APK/AAB
|
|
|
|
### Task 7.4: Documentation
|
|
- `README.md`: project overview, build instructions, usage examples
|
|
- `CONTRIBUTING.md`: dev setup, architecture overview, how to add an ABI profile
|
|
- CLI `--help` text finalized
|
|
- Struct DSL syntax reference (in README or separate doc)
|
|
|
|
---
|
|
|
|
## Dependency Graph
|
|
|
|
```
|
|
Phase 1 (foundation) --> Phase 2 (struct + financial) --> Phase 3 (API)
|
|
|
|
|
+---------------+---------------+
|
|
v v v
|
|
Phase 4 (CLI) Phase 5 (TUI) Phase 6 (Android)
|
|
| | |
|
|
+---------------+---------------+
|
|
v
|
|
Phase 7 (Testing & Release)
|
|
```
|
|
|
|
Phases 4, 5, and 6 can be worked on in parallel once Phase 3 is complete.
|
|
|
|
---
|
|
|
|
## Estimated Effort
|
|
|
|
| Phase | Effort | Notes |
|
|
|-------|--------|-------|
|
|
| Phase 1 | 2-3 days | Core parsing + eval is the most algorithmic work |
|
|
| Phase 2 | 2-3 days | Struct layout, financial formulas, unit conversion tables |
|
|
| Phase 3 | 1 day | Thin wrappers + cross-compile verification |
|
|
| Phase 4 | 1 day | Straightforward CLI, most logic in engine |
|
|
| Phase 5 | 3-4 days | TUI widgets, bit grid interaction, struct viz, convert view |
|
|
| Phase 6 | 4-5 days | Android project setup, Compose UI (5 screens), JNI, polish |
|
|
| Phase 7 | 2 days | Testing infra, CI, docs |
|
|
| **Total** | **~15-19 days** | For a single developer working focused |
|