Expand description
The SURFACE environment — user-declared notation, fixity and macros.
A mathematician coins notation constantly, and the vernacular had exactly ONE infix table, hard-coded, with no extension point. This module is that extension point, and the shape of it is the whole design:
- A parser-extension command declares into the SURFACE, never into the namespace. The
kernel context holds declarations; this holds ways of spelling them.
Notation "a ⊕ b" := …adds no global — not the token, not the command word — because a flat namespace with one phantom per notation is a collision waiting to happen. - Two stages, because they are two different things. A macro is a PATTERN REWRITE and can be recursive, so it runs as a source-to-source pre-pass to a fixpoint. A notation is a fixed shape with a PRECEDENCE, so it is a layer in the term parser. Lean stages them the same way and for the same reason.
- Scope is the section stack. A declaration lives in the innermost open section and dies
with it, so one token can mean two things in two sections without either shadowing the other.
Localis the explicit spelling of what already happens. - A namespace is the purest case of “a spelling, not a declaration”.
Namespace/End/Openchange which constant a short name DENOTES and add nothing to the context. Lean agrees: its kernelEnvironmentmaps absolute names to constants and the namespace scope lives in the elaborator, withresolveGlobalNamerunning to completion before anything reaches the kernel. So it lives here and the resolution runs in theRepl, which is why the kernel can stay a flat map of absolute keys and know nothing about any of it. - Hygiene is not optional. A template’s own binders are renamed to names that do not occur
anywhere in the expansion before its arguments are spliced in, so a template binder can never
capture a call-site name. Without it
Macro "twiceIt $e" := (fun x : Int => … $e …)applied at a call site that also bindsxcomputes a silently wrong answer — not a type error.
Structs§
- Env
- The environment a written name is resolved against — the two questions resolution asks of it, as closures, which is what keeps the kernel out of the surface.
- Name
- A hierarchical name — Lean’s
Name, which is a LIST of components and not a string with dots. - Namespaces
- The namespace scope: what is CURRENT, and what is OPEN.
- Open
Clause - One
openclause: a namespace, and WHICH of its names it brings in, under WHICH spelling. - Scope
Mark - Where a scope stood, so a scoped
Open … in …(or a declaration’s own implicit namespace) can be wound back EXACTLY, without knowing what it pushed. - Surface
- The surface environment: a stack of scopes, innermost last.
Enums§
- Assoc
- Which way a chain of one operator nests.
- Operator
Form - The shape a fixity command implies for its operator.
- Resolution
- What a written name denotes, once the scope has had its say.
- Surface
Decl - A declaration that extends the SURFACE rather than the context. Emitted by the command parser, applied by the REPL — so the one place a parser extension can land is the surface environment.
Constants§
- ANONYMOUS_
SECTION - How an ANONYMOUS section is named in a report. Lean’s
sectionmay be written with no name at all, and a scope with no name still has to be reportable — as an unclosed scope at the end of a document, and as the scope a mismatchedEndfailed to close. - ROOT_
ESCAPE - The one name that is never relative:
_root_.xis the absolutex, whatever is open.
Functions§
- fill_
defaults - Fill every OMITTED DEFAULT ARGUMENT in
term, at every application spine in it. - resolve_
names resolve_names_inagainst an environment that is only its declared keys —known— and shadows nothing.- resolve_
names_ in - Resolve every global name written in
termagainst the scope, BEFORE any elaboration sees it — Lean’s staging, and the whole content of “name resolution completes before translation begins”. - respell_
names - The inverse of
resolve_names_in, for a term already in KEY space: every global is re-spelled so that resolving the result in this same scope reaches exactly the key it holds now.