Cooper.Scope (Cooper v0.4.0)

Copy Markdown View Source

Per-file variable visibility (CASC.md §5.2).

A CASC load flattens an arbitrarily deep import tree into one list of Cooper.Op entries, and Cooper.Resolver resolves that flat result against one variable environment. Visibility, however, is a property of the file a reference was written in:

  • @name -- public. Visible to the file's importers (transitively), and to the files it imports. Public variables live in the single shared environment and need no scoping at all.
  • @*name -- private. Usable anywhere inside its declaring file, and invisible everywhere else.

Flattening destroys the file boundary that the private half depends on, so it has to be recorded before the flattening happens. This module stamps every Cooper.Ref.Var in a freshly parsed file's entries with that file's scope (its expanded path, or "(source)" for a string loaded without one), and collects that file's private declarations into a per-scope environment that Cooper.Resolver consults before the shared one.

Stamping is idempotent and outside-in safe: stamp/2 only fills in references whose scope is still nil, so entries spliced in from an already-stamped nested import keep the scope of the file that actually wrote them rather than being re-attributed to their importer.

Summary

Functions

Returns the scope identity for file, or the anonymous scope when a source string was loaded without a path.

Splits a parsed file's vars (name => {value, public?}) into the public environment that crosses file boundaries and the private one that does not.

Stamps every not-yet-stamped Cooper.Ref.Var reachable from term with scope, leaving references already attributed to a nested import untouched.

Functions

id(file)

@spec id(String.t() | nil) :: String.t()

Returns the scope identity for file, or the anonymous scope when a source string was loaded without a path.

split(vars)

@spec split(map()) :: {map(), map()}

Splits a parsed file's vars (name => {value, public?}) into the public environment that crosses file boundaries and the private one that does not.

stamp(ref, scope)

@spec stamp(term(), String.t()) :: term()

Stamps every not-yet-stamped Cooper.Ref.Var reachable from term with scope, leaving references already attributed to a nested import untouched.