Class FunctionCatalog
The catalogue is built once — from the installed libraries — and then only read. Building it once matters: two catalogues assembled separately can disagree about what a name means, and the disagreement shows up as analysis accepting a call that evaluation cannot make. Discover once, and pass the result along with the rest of the analysis.
FunctionCatalog catalog = FunctionCatalog.discover();
Optional<ScalarFunction> upper = catalog.scalar("UCase");
Lookup is case-insensitive throughout: UCase, ucase and
UCASE are one function. When two libraries offer the same name the higher
priority wins, and the loss is logged rather
than passed over — a replaced built-in should be a decision, not a surprise.
Holding a function here does not put it in a symbol table. The engine registers a function on first reference, so a script's symbol table — and the IR dump printed from it — lists the functions that script actually calls rather than the whole library. This catalogue is the thing that answers "is there such a function, and what is its form"; registration stays a consequence of a script mentioning the name.
-
Method Summary
Modifier and TypeMethodDescriptionLooks up an aggregate by name, case-insensitively.static FunctionCatalogdiscover()Builds a catalogue from everyFunctionLibraryinstalled on the module path or the class path.static FunctionCatalogdiscoverWith(Collection<FunctionLibrary> extra) Builds a catalogue over the discovered libraries plus the given ones.documentation(String docKey) The documentation page a library holds underdocKey, as Markdown.static FunctionCatalogempty()The catalogue holding nothing — useful where a caller must supply one and the functions are irrelevant.booleanisEmpty()The libraries this catalogue was built over, in claiming order.names()The canonical spelling of every name in the catalogue — scalar functions first, then aggregates.static FunctionCatalogof(FunctionLibrary... libraries) Builds a catalogue over exactly these libraries, bypassing discovery.static FunctionCatalogof(Collection<FunctionLibrary> libraries) Builds a catalogue over exactly these libraries, bypassing discovery.resolve(String name, List<ScalarType> argumentTypes) Resolves a scalar call against this catalogue.Looks up a scalar function by name, case-insensitively.scalars()
-
Method Details
-
discover
Builds a catalogue from everyFunctionLibraryinstalled on the module path or the class path.Discovery is declared here rather than by each consumer, because
ServiceLoaderresolves services against the module that calls it: doing it in one place means no consumer needs a service declaration of its own, and there is one catalogue rather than several.- Returns:
- a catalogue over the discovered libraries; empty when none is installed
-
discoverWith
Builds a catalogue over the discovered libraries plus the given ones.For a program that installs a library of its own without publishing it as a service. The SPI's claim is that anything the shipped library can do a third party can do; requiring a
META-INF/servicesentry to exercise that inside one's own program would be a gap in the claim rather than a feature of it.Discovery stays here, for the reason
discover()gives — a caller enumerating services itself would need ausesdeclaration of its own, and two independently-populated catalogues can disagree about what a name means.Clashes are resolved by
FunctionLibrary.priority()exactly as they are among discovered libraries, so an extra library must declare a higher priority than the bundled0to replace a built-in rather than merely to add to it.- Parameters:
extra- libraries to index alongside the discovered ones; must not be null- Returns:
- a catalogue over both
-
of
Builds a catalogue over exactly these libraries, bypassing discovery.- Parameters:
libraries- the libraries to index- Returns:
- a catalogue over
libraries
-
of
Builds a catalogue over exactly these libraries, bypassing discovery.- Parameters:
libraries- the libraries to index- Returns:
- a catalogue over
libraries
-
empty
The catalogue holding nothing — useful where a caller must supply one and the functions are irrelevant.- Returns:
- an empty catalogue
-
scalar
Looks up a scalar function by name, case-insensitively.- Parameters:
name- the function name as written at the call site- Returns:
- the function, or empty when no library offers that name
-
aggregate
Looks up an aggregate by name, case-insensitively.- Parameters:
name- the aggregate name as written at the call site- Returns:
- the aggregate, or empty when no library offers that name
-
resolve
Resolves a scalar call against this catalogue.A name identifies one function, so the argument types are accepted and not consulted; the parameter is here because resolution by argument type is a property of the lookup rather than of a caller, and a caller written against this form keeps working if the rule ever sharpens. To ask what a call returns, take the resolved function's
ScalarFunction.returnTypeFor(List).- Parameters:
name- the function name as written at the call siteargumentTypes- the argument types at that call site, in order- Returns:
- the function, or empty when no library offers that name
-
libraries
The libraries this catalogue was built over, in claiming order.Which implementations are actually installed is otherwise unanswerable from inside a running program — discovery is a
ServiceLoaderscan, and a missing provider fails nothing a compiler can see. This is what lets a process report its own inventory.- Returns:
- the libraries, highest priority first; never null
-
scalars
-
aggregates
- Returns:
- every aggregate in the catalogue, in the order the libraries offered them
-
names
The canonical spelling of every name in the catalogue — scalar functions first, then aggregates. These are display forms; lookup is case-insensitive.- Returns:
- the declared names
-
documentation
The documentation page a library holds underdocKey, as Markdown.Asked of the libraries in the order they get to claim a name, so the library whose function a caller resolved is the one that answers for it. The engine never reads a library's resources itself — see
FunctionLibrary.documentation(String)for why that is the seam.- Parameters:
docKey- the key aFunctionSignature.docKey()declared- Returns:
- the Markdown page, or empty when no installed library has one
-
isEmpty
public boolean isEmpty()- Returns:
truewhen no library offered a single function — which, outside a deliberatelyempty()catalogue, means no library was found
-