64 lines
2.0 KiB
Python
64 lines
2.0 KiB
Python
"""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}
|