# `Schooner.Session`
[🔗](https://github.com/ausimian/schooner/blob/1.2.0/lib/schooner/session.ex#L1)

A sequence of evaluations against one `Schooner.Environment`, each
seeing what the ones before it defined: the evaluation state behind
`mix schooner.repl`, for building a console of your own.

    iex> session = Schooner.Session.new(Schooner.Environment.new(pre_imports: [["scheme", "base"]]))
    iex> {:ok, _, session} = Schooner.Session.eval(session, "(define x 41)")
    iex> {:ok, 42, _session} = Schooner.Session.eval(session, "(+ x 1)")

`Schooner.eval/3` keeps a script's top-level `define`s and imported
variables in the environment, but its `define-syntax` macros, and the
macros its `(import ...)` forms bring in from a library such as one
loaded with `Schooner.Library.Loader`, last only for that call. A
session keeps them too, so a later evaluation can use a macro an
earlier one defined or imported:

    iex> session = Schooner.Session.new(Schooner.Environment.new(pre_imports: [["scheme", "base"]]))
    iex> {:ok, _, session} =
    ...>   Schooner.Session.eval(session, "(define-syntax twice (syntax-rules () ((_ e) (begin e e))))")
    iex> {:ok, 3, _session} = Schooner.Session.eval(session, "(twice 1) 3")

`eval/3` returns the next session whether the evaluation succeeded
or not, and an error doesn't end the session. What the failing
source did before the error stays done, as with `Schooner.eval/3`:
the definitions it evaluated, and its imports and macros once they
were read and resolved.

As with `Schooner.Environment`, the session's definitions live in
the dictionary of the process that built the environment, so use a
session only from that process.

The session's imports are resolved against the environment's
registry, so a session can import only what a script evaluated with
`Schooner.eval/3` against the same environment could.

# `binding`

```elixir
@type binding() :: %{
  name: binary(),
  kind: :macro | :procedure | :value,
  library: Schooner.Library.name() | nil,
  value: Schooner.Value.t() | nil
}
```

A name in scope in a session, as listed by `bindings/1`.

  * `:name` — the name.
  * `:kind` — `:macro`, `:procedure`, or `:value`.
  * `:library` — the name of a library in the environment's
    registry that exports this binding under this name, such as
    `["scheme", "base"]`, or `nil` when none does: a definition made
    in the session, a binding from an anonymous library, or an
    import renamed with `prefix` or `rename`.
  * `:value` — the bound value, or `nil` for a macro.

# `t`

```elixir
@opaque t()
```

# `bindings`

```elixir
@spec bindings(t()) :: [binding()]
```

Every name in scope in `session`, sorted by name: the variables the
environment, imports and definitions bind, and the macros.

A name that is both is listed as the macro, which is what a use of
the name expands to: a variable keeps its value after a
`define-syntax` of its name, and a macro keeps expanding after a
definition of its name, as in a script evaluated with
`Schooner.eval/3`.

# `environment`

```elixir
@spec environment(t()) :: Schooner.Environment.t()
```

The session's state as a `Schooner.Environment`, with the macros it
has imported and defined: pass it to `Schooner.expand/3` or
`Schooner.check/3` to see code as this session would.

# `eval`

```elixir
@spec eval(t(), binary(), keyword()) ::
  {:ok, Schooner.Value.t(), t()} | {:error, Exception.t(), t()}
```

Read and evaluate `source` in `session`.

Returns `{:ok, value, session}`, or `{:error, exception, session}`
for any script-level failure, with the exceptions of
`Schooner.eval/3`. Either way, pass the returned session to the
next call.

Options:

  * `:file` — the name of the source, recorded in the location of
    any error and prefixed to its message, as for `Schooner.eval/3`.
    Defaults to `nil`; the error's location then holds the line and
    column in `source`.

# `new`

```elixir
@spec new(
  Schooner.Environment.t(),
  keyword()
) :: t()
```

Start a session against `environment`.

Options apply to every evaluation in the session:

  * `:debug` — as for `Schooner.eval/3`: locate errors raised while
    applying a procedure and attach a Scheme backtrace. Defaults to
    `false`.
  * `:backtrace_depth` — as for `Schooner.eval/3`.

Errors are located in the source given to `eval/3` either way.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
