# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Overview

xvcl is a VCL transpiler that extends Fastly VCL with metaprogramming features like loops, conditionals, constants, functions, and macros. It's implemented as a single-file Python compiler (`src/xvcl/compiler.py`) that processes `.xvcl` source files and generates standard `.vcl` output. Zero runtime dependencies (Python stdlib only).

## Build and Test Commands

```bash
# Install dependencies
make install          # runs uv sync

# Run tests
make test             # uv run python -m pytest tests/ -v

# Lint and format
make lint             # uv run ruff check src/ tests/
make format           # uv run ruff format src/ tests/
make check            # lint + format check

# Run the compiler
uv run xvcl input.xvcl -o output.vcl
uv run xvcl input.xvcl -o output.vcl --debug        # detailed trace
uv run xvcl input.xvcl -o output.vcl --source-maps   # source origin comments
uv run xvcl input.xvcl -o output.vcl --error-format json  # JSON diagnostics

# Validate generated VCL with Falco (external tool, installed separately)
falco lint output.vcl
```

## Architecture

### Compiler Passes

The `XVCLCompiler` class processes files in sequential passes:

0. **Pass 0**: Join multi-line directives (arrays/expressions spanning multiple lines)
1. **Pass 1**: Extract `#const` declarations and evaluate constant expressions
2. **Pass 2**: Process `#include` directives with cycle detection and include-once semantics
3. **Pass 3**: Extract `#inline...#endinline` macro definitions
4. **Pass 4**: Extract `#def...#enddef` function definitions
5. **Pass 4.5**: Join multi-line function calls (parenthesis balancing)
6. **Pass 5**: Process control flow (`#for`, `#if`) and expand macros/functions
7. **Pass 6**: Generate VCL subroutines for all functions

### Key Design Patterns

**AST-Based Safe Evaluation**: Template expressions `{{...}}` are evaluated using Python's AST module with restricted operations. Only whitelisted operators and functions (`range`, `len`, `str`, `int`, `hex`, `format`, `enumerate`, `min`, `max`, `abs`) are allowed.

**Macro vs Function Distinction**:
- **Macros** (`#inline`): Zero-overhead compile-time text substitution with automatic parenthesization when arguments contain operators
- **Functions** (`#def`): Generate VCL subroutines using global headers (`req.http.X-Func-*`) for parameter passing

**Function Call Translation**: `set var.x = add(5, 10);` becomes:
```vcl
set req.http.X-Func-add-a = std.itoa(5);
set req.http.X-Func-add-b = std.itoa(10);
call add;
set var.x = std.atoi(req.http.X-Func-add-Return);
```

### Type System

Types: `INTEGER`, `STRING`, `FLOAT`, `BOOL`. Conversions are automatic:
- `INTEGER` ↔ STRING via `std.atoi()` / `std.itoa()`
- `FLOAT` ↔ STRING via `std.atof()` / string concatenation
- `BOOL` ↔ STRING via `"true"` / `"false"` literals

## Test Structure

Tests use a fixture-based pattern comparing compiled output against expected files:

- `tests/xvcl/*.xvcl` — input source files
- `tests/expected/*.vcl` — expected compiled output (matched by filename)
- `tests/xvcl/error_*.xvcl` — error cases; first line `// ERROR: <message>` defines expected error substring
- `tests/xvcl/falco/*.xvcl` — files that should produce valid VCL (validated with `falco lint` if installed)
- `tests/xvcl/includes/` — shared include files used by test inputs

### Adding a New Test

1. Create `tests/xvcl/my_feature.xvcl` with xvcl source
2. Create `tests/expected/my_feature.vcl` with expected output
3. For error tests: name file `error_*.xvcl`, add `// ERROR: expected message` as first line

Tests are auto-discovered by `get_feature_tests()` and `get_error_tests()` in `test_compiler.py`.

## Common Development Patterns

### Adding New Directives

1. Add extraction logic in the appropriate pass (`_extract_*` method)
2. Store parsed data in compiler state
3. Process during `_process_lines()` or generate output in the final pass

### Adding New Template Functions

Add to `allowed_functions` dict in `_evaluate_expression()` method.

### Debugging Compiler Issues

Use `--debug` flag to trace passes, constant/macro/function definitions, loop iterations, conditional evaluations, and macro expansions. Use `--source-maps` to add comments tracking source origins.
