"""Tiny DSL parser for Phase-0. Supports simple line-oriented declarations like: TaxLot id=lot1 acquisition_date=2020-01-01 basis=100 quantity=10 market_value=80 Account id=acct1 jurisdiction=US tax_profile=taxable This is intentionally minimal and deterministic for testing and the early prototype. It returns IR dataclasses. """ from .ir import TaxLot, Account from datetime import datetime from typing import List def _parse_kv_tokens(tokens): data = {} for t in tokens: if "=" not in t: continue k, v = t.split("=", 1) data[k.strip()] = v.strip() return data def parse_declarations(text: str): """Parse multiple lines of simple declarations into IR objects. Returns dict with lists: {"taxlots": [...], "accounts": [...]}. """ taxlots = [] accounts = [] for raw in text.splitlines(): line = raw.strip() if not line or line.startswith("#"): continue parts = line.split() kind = parts[0] kv = _parse_kv_tokens(parts[1:]) if kind == "TaxLot": acq = kv.get("acquisition_date") acq_date = datetime.strptime(acq, "%Y-%m-%d").date() if acq else None lot = TaxLot( id=kv.get("id"), acquisition_date=acq_date, basis=float(kv.get("basis", 0)), quantity=float(kv.get("quantity", 0)), market_value=float(kv.get("market_value")) if kv.get("market_value") else None, lot_status=kv.get("lot_status", "open"), ) taxlots.append(lot) elif kind == "Account": acct = Account( id=kv.get("id"), jurisdiction=kv.get("jurisdiction", "unknown"), tax_profile=kv.get("tax_profile", "unknown"), ) accounts.append(acct) else: # unknown declarations ignored for now continue return {"taxlots": taxlots, "accounts": accounts}