Pyttern is a powerful Python library and toolset designed for advanced pattern matching in source code. It extends Python's syntax to allow for expressive, structural queries that can match complex code patterns across multiple files and languages (Python and Java).
- Structural Matching: Match code based on its Abstract Syntax Tree (AST), not just text.
- Rich Wildcards: Expressive wildcards for matching single elements, sequences, bodies, and containment.
- Logical Composition: Combine patterns using AND, OR, and NOT operators via directory structures, or AND and OR via sub-patterns.
- Variable Binding: Bind matched code elements to names for reuse within the same pattern.
- Interactive Debugging: Web-based visualization to step through the matching process.
- Multi-language Support: Supports both Python and Java.
Install Pyttern directly from GitHub:
pip install git+https://github.com/JulienLie/pyttern.gitOr for development:
git clone https://github.com/JulienLie/pyttern.git
cd pyttern
pip install -e .Pyttern extends standard Python syntax with special wildcard characters (?) and sub-pattern operators ($).
| Wildcard | Name | Description |
|---|---|---|
? |
Simple | Matches exactly 1 element (variable, expression, statement, etc.). |
?name |
Named | Matches 1 element and binds it to name. |
?{n, m} |
Range | Matches between n and m elements in a sequence. |
?* |
Sequence | Matches zero or more elements. |
?: |
Body | Matches a node that has a block/body (e.g., if, for). |
?:* |
Deep Body | Matches a body at any level of indentation. |
?<...> |
Contains | Matches if the inner pattern is found anywhere within the node. |
?$(...) |
Call | Calls a sub-pattern defined elsewhere. |
from pyttern import match_files, PytternMatcher
# Simple boolean match
is_match = match_files("pattern.pyt", "code.py", lang="python")
# Advanced usage with match details
matcher = PytternMatcher(match_details=True)
res, details = matcher.match("pattern.pyt", "code.py", lang="python")# Basic match
pyttern pattern.pyt code.py --lang python
# Match with detailed output and verbosity
pyttern pattern.pyt code.py --lang python --details -v
# Search using glob patterns
pyttern "patterns/*.pyt" "src/**/*.py"Pyttern includes a web-based visualization tool to help you understand and debug how your patterns match against code. It visualizes the underlying Pushdown Automaton (PDA) and its transitions.
pytternwebAccessible at http://localhost:5000.
You can also generate static PDF visualizations of PDAs or Parse Trees using the pytterngraph command.
# Visualize a pattern as a PDA
pytterngraph pattern.pyt output_pda --type tpa --font-size 16
# Visualize a Python file as a Parse Tree
pytterngraph code.py output_pt --type pt --wrap-at 10Learn more: Check out the Visualization Guide for details on highlighting nodes and formatting graphs.
Organize your pattern files into specifically named directories to create complex boolean logic:
and/: All patterns in this folder must match.or/: At least one pattern in this folder must match.not/: No patterns in this folder should match.
my_pattern/
├── and/
│ ├── check_assign.pyt
│ └── or/
│ ├── match_if.pyt
│ └── match_while.pyt
Sub-patterns allow you to define reusable blocks of logic with arguments. They support powerful logical operators:
$&: AND (all transformations must match).$|: OR (one transformation must match).
Example Definition:
$|Incr(?x)
$# aug
?x += 1
$# add
?x = ?x + 1Learn more about modular patterns in the Sub-patterns Guide.
Matches a variable being assigned and then having .append() called on it.
Pattern:
for ? in ?:
?name = ?
?name.append(?)Matches any function that contains a return statement at any level of nesting.
Pattern:
def ?():
?:*
return ?View more: Check out the examples/ directory for comprehensive guides.
Detailed tests and edge cases are located in the tests/ folder. Contributions and feedback are welcome!