Cooper. Grammar
(Cooper v0.1.0)
Copy Markdown
Orchestrates casc.aether parsing against Cooper.NativeGrammar
(Grammar.Native, compiled ahead of time by mix ichor.gen -- see
its own moduledoc). Grammar.VM -- the interpreted bytecode backend
that ichor proper still ships -- is no longer reachable from
anything under lib/ at all: ichor is an only: [:dev, :test], runtime: false dependency now (the ichor/ichor_runtime split),
so nothing a mix release build ships is allowed to call into it.
Cooper.Test.VMParity (test/support/, compiled only under
MIX_ENV=test) keeps the old Grammar.VM path alive purely for
bench/native_vs_vm.exs and test/cooper/backend_parity_test.exs.
Summary
Functions
Parses and evaluates source_text against casc.aether via
Cooper.Actions, returning whatever Cooper.Merge.assemble/1 (Phase
1-3's placeholder) or, later, the real merge engine produces.
Like run/2, but reads path itself and seeds :root/:file
(CASC.md §5.1's "resolves relative to the current file" and correct
import-cycle detection) from it automatically -- the ordinary way to
load a real CASC file with imports, rather than assembling those opts
by hand.
Parses, merges, but deliberately does not resolve source_text --
returns the assembled tree (Cooper.Merge.assemble/1's output, secret
leaves already wrapped in Cooper.Secret but otherwise still possibly
containing unresolved Cooper.Ref.*/Cooper.Merge.Layered values)
and the file's own resolved variable environment (name => value,
already public/private-filtered across any imports by
Cooper.Loader) -- exactly what Cooper.Resolver.resolve/2 needs.
Kept separate from run/2 (which only merges) rather than folding
resolution into it, since resolution needs :env/:resolvers/:tags
options run/2 doesn't take -- Cooper.load_string/2 is what finally
wires the two together end to end.
Functions
@spec run( String.t(), keyword() ) :: {:ok, term()} | {:error, Ichor.Error.t() | [Ichor.Error.t()]}
Parses and evaluates source_text against casc.aether via
Cooper.Actions, returning whatever Cooper.Merge.assemble/1 (Phase
1-3's placeholder) or, later, the real merge engine produces.
opts:
:env--%{String.t() => String.t()}, defaults toSystem.get_env/0. Threaded intoctxhere (not just atCooper.Resolver's later, separate resolve step) because CASC.md §7.2's${?NAME}-- "skip the whole statement if unset/empty" -- has to decide at parse time, inCooper.Actions, whether the statement it guards gets evaluated at all.:root-- filesystem root a bare (non-scheme://)importinsource_textresolves relative to (CASC.md §5.1). Defaults toFile.cwd!/0; pass it explicitly for anything import-related, since the default is only reasonable for a real invocation of the library, not a test fixture.:import_schemes--%{scheme => (rest :: String.t() -> {:ok, String.t()} | {:error, term()})}, one function per registeredscheme://import loader (CASC.md §9.3). The same map asCooper's own:import_schemesoption.:file-- the entry source's own absolute path, if it has one. SeedsCooper.Loader's import-cycle-detection set with it, so a cycle that loops all the way back to the entry file itself is caught on the first repeat, not one hop later (an import that never reaches the entry file again doesn't need this at all).run_file/2sets this for you.
@spec run_file( String.t(), keyword() ) :: {:ok, term()} | {:error, Ichor.Error.t() | [Ichor.Error.t()]}
Like run/2, but reads path itself and seeds :root/:file
(CASC.md §5.1's "resolves relative to the current file" and correct
import-cycle detection) from it automatically -- the ordinary way to
load a real CASC file with imports, rather than assembling those opts
by hand.
@spec run_tree( String.t(), keyword() ) :: {:ok, map(), map()} | {:error, Ichor.Error.t() | [Ichor.Error.t()]}
Parses, merges, but deliberately does not resolve source_text --
returns the assembled tree (Cooper.Merge.assemble/1's output, secret
leaves already wrapped in Cooper.Secret but otherwise still possibly
containing unresolved Cooper.Ref.*/Cooper.Merge.Layered values)
and the file's own resolved variable environment (name => value,
already public/private-filtered across any imports by
Cooper.Loader) -- exactly what Cooper.Resolver.resolve/2 needs.
Kept separate from run/2 (which only merges) rather than folding
resolution into it, since resolution needs :env/:resolvers/:tags
options run/2 doesn't take -- Cooper.load_string/2 is what finally
wires the two together end to end.