Marker overview¶
Markers are valid Python syntax: calls, decorators, and identifier suffixes your snippet uses so astichi can find holes, binds, and composition sites.
The current package does not ship an astichi.markers runtime shim, so
marker-bearing examples are typically embedded directly in the source string
passed to astichi.compile(...).
Hole shape (scalar vs variadic vs block) is inferred from AST context, not from encoding a “kind” in the hole name.
Marker Vocabulary¶
astichi_hole(name)
astichi_elif(name)
with astichi_hole(name) as astichi_fallback: ...
astichi_bind_external(name)
astichi_keep(name)
astichi_import(name)
astichi_pass(name)
astichi_export(name)
astichi_for(domain)
astichi_funcargs(...)
def astichi_params(...): pass
async def astichi_params(...): pass
def astichi_elif(): ...
astichi_ref(value)
astichi_ref(external=name)
astichi_pyimport(module=module_path, names=(name,))
astichi_pyimport(module=module_path, as_=alias)
astichi_comment("comment text")
name__astichi_keep__
name__astichi_arg__
name__astichi_param_hole__
Reserved names:
astichi_bind_once(name, expr)andastichi_bind_shared(name, expr)are reserved and obsolete marker names;compile(...)rejects them with a diagnostic.
Internal emitted metadata:
astichi_insert(...)is reserved for Astichi-emitted source. Ordinaryastichi.compile(...)rejects it in the defaultsource_kind="authored"mode; only re-ingest Astichi output withsource_kind="astichi-emitted".
Call-argument note:
astichi_funcargs(...)is the authored call-argument payload surface- for non-call expression holes, author a plain expression source such as
42or(value := 2, value); build/merge normalizes it internally - expression-form
astichi_insert(target, expr)is internal normalization metadata, not an authored user surface
Parameter note:
name__astichi_param_hole__declares a function-parameter insertion target in an ordinary parameter slot.def astichi_params(...): passandasync def astichi_params(...): passare the authored parameter payload carriers; only the signature is inserted.- Astichi may emit internal
@astichi_insert(name, kind="params", ...)wrappers in pre-materialized source. They are not authored user surface.
Clause target note:
astichi_elif(name)declares an additive target in a realelifposition.def astichi_elif(): ...supplies one generatedelifbranch; its single innerifstatement provides the generated branch test and body.- Astichi may emit internal
@astichi_insert(name, kind="elif", ...)wrappers in pre-materialized source. They are not authored user surface. - Unfilled
astichi_elif(...)targets reject atmaterialize().
Reference-path note:
astichi_ref(value)is the authored value-form reference surface; it lowers a compile-time path string (e.g."self.f0"or"pkg.mod.attr") into the correspondingName/AttributeAST at materialize time- prefer
astichi_ref(...)overgetattr(...)when the attribute path is compile-time reducible; keepgetattr(...)for genuinely runtime-dynamic lookup astichi_ref(external=name)is sugar forastichi_ref(astichi_bind_external(name))and surfaces the inner bind site as a normal demand portastichi_ref(...).astichi_v(or the._shorthand) wraps the value form so it is grammatically legal as anAssign/AugAssign/Deletetarget. Prefer bareastichi_ref(...)in ordinary expression chains.
Managed import note:
astichi_pyimport(...)declares imports that are synthesized duringmaterialize()and emitted as ordinary Python imports at module head.- Imported local names participate in hygiene like other local bindings, so a
collision can turn
from foo import aintofrom foo import a as a__astichi_scoped_1. - Use
module=astichi_ref(external=name)when the module path comes from an externally bound compile-time string. - Pyimport is a top-of-Astichi-scope statement-prefix marker; it is not valid
inside
astichi_for(...)bodies or nested real user-authored function/class bodies.
Comment note:
astichi_comment("...")is a statement-only final-output comment marker.- Ordinary
emit()preserves it as a marker for round-trip. Ordinarymaterialize()strips it, insertingpassonly when a non-module suite would otherwise become empty. emit_commented()is the narrow final-output surface that materializes with comments preserved long enough to render them as real#comment lines.- The literal payload may contain
{__file__}and{__line__}placeholders; only those exact substrings are replaced. Other braces pass through unchanged.
Defaulted block-hole note:
with astichi_hole(name) as astichi_fallback:is a block-hole marker with an authored fallback suite.- The fallback suite is selected only if that block hole has no local builder
insert shells by materialize time; otherwise the inserts replace the whole
withstatement and the fallback is discarded. - Fallback contents are inactive before branch selection. If the fallback is selected, any nested markers in it become ordinary selected-state markers and unresolved demands still reject.
astichi_fallbackis a sentinel marker name required to disambiguate this form from ordinarywithstatements.
Cross-scope note:
astichi_import(name)is the declaration-form identifier-threading surface for a whole Astichi scopeastichi_pass(name)is the value-form surface and belongs in a real expression (x = astichi_pass(y),call(astichi_pass(y)),astichi_pass(obj).field = 1)- when the
astichi_pass(...)result itself must occupy the target position, append._or.astichi_v:astichi_pass(counter)._ = 1 outer_bind=Trueis the explicit convenience form for “bind this marker to the same-named identifier in the immediately enclosing Astichi scope”- explicit builder /
arg_names=/.bind_identifier(...)wiring now round-trips in source asbound=Trueon the rewritten marker call - bare statement-form
astichi_pass(name)is rejected; if you need declaration-style scope threading, useastichi_import(name)
Identifier-suffix note:
name__astichi_keep__is the identifier-position form of keep. It pins the base spellingnamethrough hygiene and strips the suffix during materialize.name__astichi_arg__creates an identifier demand namedname. Resolve it througharg_names=,.bind_identifier(...), builderarg_names=, orbuilder.assign...before materialize.name__astichi_param_hole__creates a parameter-list insertion target namedname. It is stripped by parameter materialization, not by the ordinary identifier arg/keep strip pass.- Use suffix forms when the marker must live inside an identifier slot, such as a class name, function name, parameter name, assignment target, or reference.
Identifier arguments¶
For name / target / bind keys: use a bare identifier in source (a
Name in the AST), not a string literal. The identifier names the hole
or bind; it is not a hole-kind enum like "expr" vs "block".
Per-topic reference¶
| Topic | Page |
|---|---|
Holes, *, **, block position, defaulted block holes |
marker-holes.md |
| Elif clause targets | marker-clause-targets.md |
| Binds and exports | marker-binds-and-exports.md |
| Loops and inserts | marker-for-and-insert.md |
| Parameter holes | marker-params.md |
Reference-path values (astichi_ref) |
marker-ref.md |
Managed Python imports (astichi_pyimport) |
marker-pyimport.md |
| Preserved names | marker-keep.md |
Final-source comments (astichi_comment) |
marker-comment.md |
| Identifier suffixes | classification-modes.md |
| Scoping and hygiene | scoping-hygiene.md |
Unsupported starred / double-starred contexts are hard errors.