---
epic: 1
story: 1.3
title: "Interpreter / Evaluator"
status: draft
---

## Epic 1 — Core Calculation Engine (Rust Crate)
**Goal:** Build `calcpad-engine` as a standalone Rust crate that powers all platforms. This is the foundation.

### Story 1.3: Interpreter / Evaluator

As a CalcPad engine consumer,
I want the AST evaluated into typed results with metadata,
So that each line produces a meaningful, displayable calculation result.

**Acceptance Criteria:**

**Given** an AST representing `2 + 3`
**When** the interpreter evaluates it
**Then** it returns a `CalcResult` of type `Number` with value `5`

**Given** an AST representing `5kg + 200g`
**When** the interpreter evaluates it
**Then** it returns a `CalcResult` of type `UnitValue` with value `5.2 kg`
**And** the result unit matches the left-hand operand's unit

**Given** an AST representing `$20 in EUR`
**When** the interpreter evaluates it within a context that has exchange rates loaded
**Then** it returns a `CalcResult` of type `CurrencyValue` with the converted amount and target currency `EUR`

**Given** an AST representing `today + 3 weeks`
**When** the interpreter evaluates it
**Then** it returns a `CalcResult` of type `DateTime` with the correct future date

**Given** an AST representing `March 12 to July 30`
**When** the interpreter evaluates it
**Then** it returns a `CalcResult` of type `TimeDelta` representing the duration between the two dates

**Given** an AST representing `5 > 3`
**When** the interpreter evaluates it
**Then** it returns a `CalcResult` of type `Boolean` with value `true`

**Given** an AST representing `100 - 20%`
**When** the interpreter evaluates it
**Then** it returns a `CalcResult` of type `Number` with value `80`
**And** the percentage is interpreted as "20% of 100" subtracted from 100

**Given** an AST representing `$100 + 10%`
**When** the interpreter evaluates it
**Then** it returns a `CalcResult` of type `CurrencyValue` with value `$110`

**Given** an AST with incompatible unit arithmetic such as `5kg + 3m`
**When** the interpreter evaluates it
**Then** it returns a `CalcResult` of type `Error` with a message indicating incompatible units
**And** the error includes the span of the offending expression

**Given** any evaluated result
**When** the result is produced
**Then** it includes metadata: the input span, the result type, display-formatted string, and raw numeric value where applicable
