Skip to main content

pASTadd

A Python attribute grammar framework inspired by JastAdd. Uses Python's dynamic mechanisms (descriptors, decorators, __getattr__) instead of code generation — making attribute grammar semantics visible and interactive.

Quick Example

Define a grammar (lang.ast):

Program ::= Func*;
Func ::= <Name:String> Body:Expr;
abstract Expr;
IdUse : Expr ::= <Name:String>;
BinOp : Expr ::= Left:Expr <Op:String> Right:Expr;
Numeral : Expr ::= <Value:int>;

Load it and define attributes:

from pastadd import load_grammar, inh, syn

# Load grammar — creates ASTNode classes dynamically
load_grammar("lang.ast")

# Synthesized attribute (lambda):
Func.qualified_name = lambda self: f"program.{self.name}"

# Inherited attribute (decorator):
@inh(Program)
def env(self, child_index):
    return {f.name: f for f in self.children}

# Or as a lambda:
# inh(Program).env = lambda self, ci: {f.name: f for f in self.children}

# Use it
prog = Program()
f = Func(name="main")
prog.children.append(f)

print(f.env)              # {'main': <Func object>}
print(f.qualified_name)   # 'program.main'

Inherited attributes resolve by walking up the tree — no pass-through equations needed on intermediate nodes.

Or generate a Python file from the grammar:

python -m pastadd.grammar lang.ast -o lang_ast.py

Design Principles

  1. Grammar from .ast files — load_grammar() creates node classes dynamically; generate_grammar() writes Python source.
  2. Equations live in modules — all syn, inh, circular, collection definitions are external to the grammar.
  3. One mechanism per concern — synthesized, inherited, circular, collection, NTA, forwarding — each has a clear API.
  4. Educational transparency — every evaluation step is traceable via observe().

Features

Feature API Description
Grammar loading load_grammar() / generate_grammar() Parse .ast files into ASTNode classes
Synthesized attributes @syn(Cls) / Cls.attr = lambda Demand-driven, cached
Inherited attributes @inh(Cls) / @inh(Cls.child) Parent provides equation for children
Collection attributes collection() + contribute() Gather values from tree via survey
Circular attributes circular(bottom=...)(fn) / circular(bottom=...) Fixed-point iteration (syn and inh)
Non-Terminal Attributes @nta(Cls) Computed subtrees with parent links
Rewrites @rewrite / @rewrite(Cls) Conditional tree transformations on access
Parameterized attributes extra args on equation fn Cached per argument tuple
Child targeting @inh(Cls.child) Target equations to specific children
Incremental evaluation automatic Dependency tracking + auto-invalidation
Forwarding forwards_to attribute Silver-style delegation
Tokens token(default) Mutable input data (triggers invalidation)
Tracing / Profiling observe() Observe evaluation, timing, cache hits
Abstract nodes abstract Foo : Bar; in .ast Cannot instantiate directly

Key Patterns

# One-liner synthesized:
Cls.attr = lambda self: expr

# Multi-line synthesized:
@syn(Cls)
def attr(self):
    return complex_computation

# Inherited (all children, lambda):
inh(Parent).attr = lambda self, ci: value

# Inherited (all children, multi-line):
@inh(Parent)
def attr(self, child_index):
    return complex_lookup

# Inherited (targeted child):
inh(Parent.child_name).attr = lambda self, ci: value

# Circular synthesized:
Cls.attr = circular(bottom=True)(lambda self, t: t.supertype(self))

# Circular inherited:
Expr.target_type = circular(bottom=None)

# Collection:
Cls.errors = collection(bottom=set, combine=set.add)
contribute(SubCls.check, to=Cls.errors)

# NTA (computed subtree):
@nta(Cls)
def computed_child(self):
    return SomeNode(...)

Requirements

Python 3.13+ required. Depends on pytracked for dependency tracking.

pip install pastadd

Testing

python -m pytest tests/ -v

See Also

  • JastAdd — the Java attribute grammar system that inspired pASTadd
  • ExtendJ-pASTadd — a Java 5 compiler frontend ported to pASTadd (504 tests passing)

License

BSD-3-Clause

Metadata

Release files for pastadd 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pastadd 0.1.3
File Size Uploaded
pastadd-0.1.3.tar.gz 63.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pastadd 0.1.3
File Interpreter ABI Platform
pastadd-0.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 101.8 kB

Release files / pastadd-0.1.3.tar.gz

Download URL pastadd-0.1.3.tar.gz
Size 63.2 kB
Tags Source
SHA-256 checksum
How to use checksums
e25495aece4da8a82dc109ac9fbf28b3f64460155e9f70a4036d95a731805018
BLAKE2b-256 checksum
How to use checksums
35d0f1c73acbb3352cea782413fae304a96888877eeba1cae2c4a5058d2ea2e8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.7

Release files / pastadd-0.1.3-py3-none-any.whl

Download URL pastadd-0.1.3-py3-none-any.whl
Size 38.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
35827338ae08f0d6cc65c8f246b429c72f427a752a01b245952734c46aeb4d74
BLAKE2b-256 checksum
How to use checksums
2d3d06069742d7d8b9adab022a07aad02b8dcc118ac46411e62379bff13a7af9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.7

Release history Release notifications | RSS feed

This release

0.1.3 This release

2 release files

0.1.2

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page