Syntax augmentation
These are the building blocks for defining new surface syntax — see Add new surface syntax for the how-to and Tutorial: build optional chaining (?.) for a full worked example. Syntax augmentation requires Python ≥ 3.8.
AugmentationSpec
- class pyccolo.AugmentationSpec(aug_type, token, replacement, close_token, close_replacement, name_pattern, body_func_wrapper, custom)[source]
- aug_type: AugmentationType
Alias for field number 0
- custom: CustomRewrite | None
Alias for field number 7
A spec declares a source-level rewrite from an (otherwise illegal) token to a
legal one; Pyccolo records where the rewrite happened so a handler can attach to
the resulting node via get_augmentations(). For
paired-delimiter (brace-block) syntax, also set close_token /
close_replacement; is_paired and is_custom report the kind.
optional_chaining_spec = pyc.AugmentationSpec(
aug_type=pyc.AugmentationType.dot_suffix, token="?.", replacement="."
)
AugmentationType
- class pyccolo.AugmentationType(*values)[source]
- prefix = 'prefix'
- suffix = 'suffix'
- dot_prefix = 'dot_prefix'
- dot_suffix = 'dot_suffix'
- binop = 'binop'
- boolop = 'boolop'
- call = 'call'
- subscript = 'subscript'
- custom = 'custom'
The kind of token position a spec rewrites — e.g. dot_suffix (?.),
binop (|>), boolop (??), or custom.
CustomRewrite
- class pyccolo.CustomRewrite[source]
Drives a
AugmentationType.customspec. A cooperating tracer that needs a context-sensitive surface rewrite (one the static token/paired passes can’t express – e.g. a token whose meaning depends on the preceding token, or a per-occurrence choice between two lowerings) implements these three methods so the rewrite participates in pyccolo’s position-remapping anduntransformmachinery uniformly, instead of bolting on a parallel resugaring path.Subclassing is optional (the methods are duck-typed); it just documents intent.
- rewrite(code: str, register: Callable[[int, int], None]) Tuple[str, List[Tuple[int, int, int]]][source]
Forward-rewrite
code->(new_code, edits).editsare(start, end, new_len)triples incode’s input absolute offsets – sorted ascending and disjoint, the same shapereplace_tokens_and_get_augmented_positions()builds – so the caller can remap trackedpositionsthrough them withremap_through_edits(). For each rewritten occurrence whose resulting AST node should be reverse-handled byuntransform, callregister(line, col)with the 1-indexed line / 0-indexed col of the node’s anchor in ``new_code`` (the locationrange_for()will re-derive on the parsed node).
- range_for(node: AST) Range | None[source]
Anchor
Rangeof a rewrittennode(mirrors the built-in_get_<aug_type>_range_forhelpers), orNoneifnodeis not one this rewrite produced. Used both to bind the registered position forward and to locate the node duringuntransform.
- reverse(node: AST, spec: AugmentationSpec, aug_range: Range, code: str, line_starts: List[int]) Tuple[int, int, str] | None[source]
Reverse (resugar) splice
(start, end, new_text)on validcode, orNoneto leavenodeuntouched. A single whole-span edit suffices; the caller applies edits right-to-left.
The extension point for context-sensitive rewrites that a single token→token
substitution can’t express. Subclass it and reference it from a spec with
aug_type=AugmentationType.custom.
Positions
pyc.transform / pyc.untransform accept and return Position\ s so
tooling can build source maps across the rewrite.