Module lifecycle
koskari.module
Module lifecycle for Koskari source files.
Provides new_module, init_module, load_module_async, and load_module_demand. new_module is synchronous and copies parent bindings from koskari.builtins. Module body loading may use the async or demand execution path.
Each top-level expression is read, compiled to a Code object, executed as a koskari expression coroutine (async path) or via demand_call (demand path), and run in sequence. This allows each expression to mutate the module namespace for subsequent expressions, e.g. by adding new bindings or special forms.
This is the koskari analogue of sibilant.module from python-sibilant.
- koskari.module.attach_module_load_facets(module, pragma, compiler, reader)
Bind
__pragma__,__compiler__, and__reader__onmodulefor load time.- Parameters:
pragma – ModulePragma instance for this load
module – koskari Module (or object whose
vars()is the ns)compiler – Compiler instance for this load
reader – LayoutReader instance for this load
- koskari.module.build_module_load_facets(module, filename=None)
Produce the load-time pragma, compiler, and reader for
module.When all three facets are already bound on the module (a prior load ran with
detach=False), they are reused as-is rather than rebuilt, so consecutive loads share one pragma lineage, one compiler (and its open code allocator), and one reader. The compiler’s filename is refreshed so code minted by this load attributes backtrace positions to the current source file.Otherwise the module’s bound
__pragma__is kept when present (a detached load leaves it as the module’s record), or aModulePragmais built and bound as__pragma__; the compiler and reader are then chained off it viafrom_pragma(each subscribing for later pragma changes) and bound as load facets. A fresh pragma comes frombuild_module_pragma(), which seeds it from the nearest ancestor package’s__package_pragma__.- Parameters:
module – koskari Module (or object whose
vars()is the ns)filename – optional source filename
- Returns:
the (compiler, reader) pair
- koskari.module.build_module_pragma(module)
The module’s
__pragma__record, bound if it was not already.A bound
__pragma__is returned as-is. Otherwise this is the single chokepoint where the pragma source is resolved: the nearest ancestor package’s__package_pragma__seeds the settings when one exists (a copy with a fresh watcher set – watchers never cross modules), falling back to the built-in default. A package additionally pulls the inherited default down as its own__package_pragma__so its descendants inherit it; a(package-pragma ...)declaration in the package body overwrites that stamp.- Parameters:
module – koskari Module (or object whose
vars()is the ns)- Returns:
the ModulePragma bound as
__pragma__
- koskari.module.compile_top_level(compiler, reader, source_stream)
Read and compile each top-level form of a module’s source in order, yielding one expression Code per form. The caller runs each before the next is read, so compile-time artifacts a form defines (syntax, reader macros) are live when the following form compiles.
A leading string is the module docstring: it is rewritten to a var of
__doc__and yielded like any other form, which is also the body a .kio carries for it- Parameters:
compiler – Compiler facet for this load
reader – LayoutReader facet for this load
source_stream – SourceStream from source_open or source_str
- koskari.module.detach_module_load_facets(module)
Remove load-time
__compiler__and__reader__bindings.__pragma__stays bound as the module’s record; the get-compiler runtime function rebuilds a compiler from it on demand. Ignores names listed inMODULE_DETACH_FACET_NAMESthat are not bound.- Parameters:
module – koskari Module (or object whose
vars()is the ns)
- koskari.module.exports_materialized(module)
Materialize
__all__when the block ends, whether or not it raised
- koskari.module.find_module_pragma(ns)
The pragma record for the module owning ns. Returns the bound __pragma__, or seeds one from the nearest package pragma, as a load would, and binds it
- Parameters:
ns – a module, function, or let namespace, or a plain mapping
- Returns:
the ModulePragma
- koskari.module.find_module_reader(ns)
The layout reader for the module owning ns. Returns the bound __reader__, or rebuilds one from the module’s pragma and binds it when the load-time facet was detached
- Parameters:
ns – a module, function, or let namespace, or a plain mapping
- Returns:
the LayoutReader
- koskari.module.init_module(module, filename, spec=None)
Initialise a koskari Module with source file metadata.
Sets __file__, and if the filename is an __init__.ki also sets __path__ to the containing directory. Stores __spec__ and __loader__ when provided via spec.
- Parameters:
module – koskari Module instance
filename – absolute path to the .ki source file
spec – importlib ModuleSpec, or None
- koskari.module.kio_codes(module)
The stored bodies of a module’s precompiled .kio file, with the module’s
__pragma__record bound first so(pragma ...)bodies and package-pragma stamping run as they do under a source load. No compiler or reader is built: the bodies were compiled already. Every function the file holds is decoded before any body runs, so the function code its build placed in arena chunks is placed and sealed here, before the first body- Parameters:
module – koskari Module with
__file__set to a .kio path- Returns:
the Code objects in stored order
- koskari.module.load_facets(module, filename, *, seal, detach)
The facets of one load. Builds (or reuses) the compiler and reader, opens the compiler’s code allocator so the load’s function code is placed into arena chunks – unless the load can never seal, with
sealFalse anddetachset, where no allocator is opened: a fresh compiler then builds function code on the heap, while a compiler reused from an earlierdetachFalse load keeps its open allocator and still places into it – and yields them; when the block ends, whether or not the load raised, seals the chunks whensealis set, and whendetachis set materializes__all__and detaches the facets, with__pragma__staying bound. Callers passingdetachFalse own the completion steps: an interactive session seals but retains facets; the bootstrap builtins loop defers both across its source files and performs them once at the end- Parameters:
module – koskari Module (or object whose
vars()is the ns)filename – source filename for the compiler
seal – on success, seal the arena chunks the load placed its function code into
detach – materialize exports and drop the load facets
- Returns:
the (compiler, reader) pair
- async koskari.module.load_module_async(module, *, seal=True, detach=True)
Execute a koskari module by reading, compiling, and running each top-level expression in order.
Each expression is compiled relative to the module, then executed as an expression coroutine and awaited. Bindings created by one expression are visible to all subsequent expressions, supporting define, defsyntax, and reader macro registration at module load time.
While loading,
__pragma__,__compiler__, and__reader__are bound on the module; facets already present (a prior load withdetach=False) are reused, so consecutive loads share one pragma, compiler, and reader. Sealing and detaching followload_facets().- Parameters:
module – koskari Module instance with
__file__setseal – when True, seal the module on successful completion
detach – when True, detach the compiler and reader facets afterward
- koskari.module.load_module_demand(module, *, seal=True, detach=True)
Execute a koskari module by reading, compiling, and running each top-level expression in order via demand_call.
Same structure as
load_module_async()but each expression is run with demand_call instead of awaiting a coroutine. No async suspension is allowed. Used by the loader’s exec_module_demand path.- Parameters:
module – koskari Module instance with __file__ set
seal – when True, seal the module on successful completion
detach – when True, detach the compiler and reader facets afterward
- async koskari.module.load_module_kio_async(module)
Execute a module from a precompiled .kio file.
Each stored body is re-hardened and run as a top-level expression in order, matching the incremental structure of load_module_async;
__all__is materialized fromdeclare-exportsat the end.- Parameters:
module – koskari Module with __file__ pointing at a .kio path
- koskari.module.load_module_kio_demand(module)
Execute a module from a precompiled .kio file via demand_call.
Same steps as load_module_kio_async but synchronous.
- Parameters:
module – koskari Module with __file__ set to a .kio path
- async koskari.module.load_module_source_async(module, source, *, seal=True, detach=True, layout=True)
Execute koskari source passed as a string.
Same top-level expression loop as
load_module_async(), but reads fromsourceinstead of openingmodule’s__file__.- Parameters:
module – koskari Module instance with
__file__setsource – koskari source text to execute
seal – when True, seal the module on successful completion
detach – when True, detach the compiler and reader facets afterward
layout – when False, read plain s-expressions instead of layout, by turning reader/layout off on the module pragma for this load, so a pragma form in the source keeps it off; the prior value is restored afterward. A layout line is a single form, so several expressions on one line become one implicit call; that suits a file but not a one-liner, where consecutive top-level forms are wanted
- koskari.module.new_module(name, package=None, system=False)
Create a new koskari Module with an initialised ModuleNamespace
Parent bindings are copied from the loaded koskari.builtins Python module (bootstrap registry plus basics.ki). No event loop or await is required.
- Parameters:
name – fully-qualified module name string
package – parent package name string, or None
system – when True, register the module in sys.modules
- Returns:
koskari Module instance
- async koskari.module.run_codes_async(module, codes)
Run each Code as an expression of
module, awaiting each in turn.Each expression is dropped before the next form is read, so the function code only it holds dies while its chunk is open and the next function takes its bytes; a helper so no caller local holds the last one past the loop either, before the compiler seals
- koskari.module.run_codes_demand(module, codes)
Run each Code as an expression of
modulevia demand_call. No async suspension is allowed. Seerun_codes_async()for why the loop lives in a helper