Metadata-Version: 2.4
Name: sexp
Version: 1.0.2
Summary: A minimal-allocation S-expression library for Python, backed by a C extension.
Author-Email: Andre Koraleski <andrekorale@gmail.com>
License-Expression: MIT
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Operating System :: OS Independent
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Text Processing
Project-URL: Repository, https://github.com/AndreKoraleski/sexp
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# sexp

[![Build](https://github.com/AndreKoraleski/sexp/actions/workflows/build.yml/badge.svg)](https://github.com/AndreKoraleski/sexp/actions/workflows/build.yml)
[![Test](https://github.com/AndreKoraleski/sexp/actions/workflows/test.yml/badge.svg)](https://github.com/AndreKoraleski/sexp/actions/workflows/test.yml)
[![PyPI](https://img.shields.io/pypi/v/sexp)](https://pypi.org/project/sexp/)
[![Python](https://img.shields.io/pypi/pyversions/sexp)](https://pypi.org/project/sexp/)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)

A minimal-allocation S-expression library for Python, backed by a C extension.

Parsing and tree manipulation are handled entirely in C with a bump-pointer
arena allocator and an interned string pool. Python gets lightweight node
views — no copying, no per-node heap allocation.

## Installation

```bash
pip install sexp
```

Requires **Python 3.10+**. Wheels are provided for **Linux** (`x86_64` + `aarch64`),
**macOS** (`x86_64` + `arm64`), and **Windows** (`AMD64`).

## Quick start

```python
from sexp import parse

tree = parse("(define (square x) (* x x))")

tree[0].value         # 'define'
tree[1][0].value      # 'square'
tree.head.value       # 'define'

for node in tree:
    print(node)

src = "(a (b (c d)) e)"
assert repr(parse(src)) == src
```

## Further reading

| Path | Contents |
|------|----------|
| [CHANGELOG.md](CHANGELOG.md) | Release history |
| [docs/api.md](docs/api.md) | Full API reference, including recipes for common patterns |
| [docs/how-it-works.md](docs/how-it-works.md) | Architecture overview: node array, arena, intern pool, parser |
| [docs/internals/](docs/internals/README.md) | Internals wiki: node array, arena, intern pool, parser, mutation |

## Development

### Prerequisites

| Audience | Requirements |
|----------|--------------|
| **Installing from PyPI** | Python 3.10+ — wheels are provided for Linux (x86\_64, aarch64), macOS (x86\_64, arm64), and Windows (AMD64). No compiler needed. |
| **Building from source** | Python 3.10+, CMake 3.15+, and a C11 compiler (gcc or clang on Linux/macOS; MSVC 2019+ or clang-cl on Windows). |

### Setup

```bash
python -m venv .venv && source .venv/bin/activate  # Windows: .venv\Scripts\activate
pip install -e '.[dev]'
```

### Running tests

```bash
# Python tests
pytest tests/python

# C tests
cmake -B build && cmake --build build
ctest --test-dir build --output-on-failure

# Benchmarks (local only)
pytest benchmarks/ --benchmark-only
```

## License

[MIT](LICENSE)
