--- epic: 1 story: 1.2 title: "Parser & AST" 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.2: Parser & AST As a CalcPad engine consumer, I want tokens parsed into a typed abstract syntax tree respecting operator precedence and natural language constructs, So that the interpreter can evaluate expressions with correct semantics. **Acceptance Criteria:** **Given** a token stream for `2 + 3 * 4` **When** the parser builds the AST **Then** multiplication binds tighter than addition **And** the tree evaluates as `2 + (3 * 4)` yielding `14` **Given** a token stream for `(2 + 3) * 4` **When** the parser builds the AST **Then** the parenthesized sub-expression is grouped as a single child node **And** the tree evaluates as `(2 + 3) * 4` yielding `20` **Given** a token stream for `2^3^2` **When** the parser builds the AST **Then** exponentiation is right-associative **And** the tree evaluates as `2^(3^2)` yielding `512` **Given** a token stream for `5kg + 200g` **When** the parser builds the AST **Then** it produces a `BinaryOp(Add)` node with unit-attached number children `5 kg` and `200 g` **Given** a token stream for `$20 in euro - 5% discount` **When** the parser builds the AST **Then** it produces a `Conversion` node wrapping `$20` targeting `euro`, followed by a `PercentOp(Subtract, 5%)` node **And** the percentage operation applies to the result of the conversion **Given** a token stream for implicit multiplication such as `2(3+4)` or `3pi` **When** the parser builds the AST **Then** it inserts an implicit `Multiply` operator between the adjacent terms **Given** a token stream for a natural language phrase such as `5 plus 3 times 2` **When** the parser builds the AST **Then** it applies the same operator precedence as symbolic operators **And** the tree evaluates as `5 + (3 * 2)` yielding `11` **Given** a token stream for a proportion expression such as `3 is to 6 as what is to 10?` **When** the parser builds the AST **Then** it produces a `Proportion` node with known values `3`, `6`, `10` and an unknown placeholder **And** the unknown resolves to `5` **Given** a token stream for a conditional expression such as `if x > 5 then x * 2` **When** the parser builds the AST **Then** it produces an `IfThen` node with a condition sub-tree and a result sub-tree **And** an optional `else` branch is supported **Given** a token stream containing a syntax error such as `5 + + 3` **When** the parser attempts to build the AST **Then** it returns a `ParseError` with a descriptive message and the span of the offending token **And** it does not panic