Source code for amalgam.primordials.meta

from __future__ import annotations

from typing import TYPE_CHECKING

import amalgam.amalgams as am
from amalgam.primordials.utils import make_function


if TYPE_CHECKING:  # pragma: no cover
    from amalgam.environment import Environment
    from amalgam.primordials.utils import Store


META: Store = {}


[docs]@make_function(META, "setn", defer=True) def _setn(env: Environment, name: am.Symbol, amalgam: am.Amalgam) -> am.Amalgam: """ Binds :data:`name` to the evaluated :data:`amalgam` value in the immediate :data:`env` and returns that value. """ value = amalgam.evaluate(env) env[name.value] = value return value
[docs]@make_function(META, "setr", defer=True) def _setr( env: Environment, rname: am.Amalgam, amalgam: am.Amalgam, ) -> am.Amalgam: """ Attemps to resolve :data:`rname` to a :class:`.amalgams.Symbol` and binds it to the evaluated :data:`amalgam` in the immediate :data:`env`. """ name = rname.evaluate(env) if not isinstance(name, am.Symbol): raise am.Failure(rname, env, "could not resolve to a symbol") amalgam = amalgam.evaluate(env) env[name.value] = amalgam return amalgam
[docs]@make_function(META, "unquote") def _unquote(env: Environment, qamalgam: am.Quoted[am.Amalgam]) -> am.Amalgam: """Unquotes a given :data:`qamalgam`.""" if not isinstance(qamalgam, am.Quoted): raise am.Failure(qamalgam, env, "unquotable value") return qamalgam.value
[docs]@make_function(META, "eval") def _eval(env: Environment, amalgam: am.Amalgam) -> am.Amalgam: """Evaluates a given :data:`amalgam`.""" if isinstance(amalgam, am.Quoted): amalgam = amalgam.value return amalgam.evaluate(env)
[docs]@make_function(META, "fn", defer=True) def _fn( env: Environment, args: am.Vector[am.Symbol], body: am.Amalgam, ) -> am.Function: """ Creates an anonymous function using the provided arguments. Binds :data:`env` to the created :class:`.amalgams.Function` if a closure is formed. """ fn = am.create_fn("~lambda~", [arg.value for arg in args], body) if env.parent is not None: fn.bind(env) return fn
[docs]@make_function(META, "mkfn", defer=True) def _mkfn( env: Environment, name: am.Symbol, args: am.Vector[am.Symbol], body: am.Amalgam, ) -> am.Amalgam: """ Creates a named function using the provided arguments. Composes :func:`._fn` and :func:`._setn`. """ return _setn(env, name, _fn(env, args, body).with_name(name.value))
[docs]@make_function(META, "macro", defer=True) def _macro( env: Environment, name: am.Symbol, args: am.Vector[am.Symbol], body: am.Amalgam, ) -> am.Amalgam: """Creates a named macro using the provided arguments.""" fn = am.create_fn( name.value, [arg.value for arg in args], body, defer=True, ) if env.parent is not None: fn.bind(env) return _setn(env, name, fn)
[docs]@make_function(META, "let", defer=True) def _let( env: Environment, pairs: am.Vector[am.Vector], body: am.Amalgam, ) -> am.Amalgam: """ Creates temporary bindings of names to values specified in :data:`pairs` before evaluating :data:`body`. """ names = [] values = [] for pair in pairs: if not isinstance(pair, am.Vector) or len(pair) != 2: raise am.Failure(pair, env, "not a pair") name, value = pair if not isinstance(name, am.Symbol): raise am.Failure(name, env, "not a symbol") names.append(name) values.append(value) return _fn(env, am.Vector(*names), body).call(env, *values)