Skip to main content

Expr

Enum Expr 

Source
pub enum Expr {
Show 13 variants Int(BigInt), List(Vec<Expr>), Name(Text), Local { name: Box<Text>, index: u32, }, Builtin(Builtin), ModItem { name: Box<Text>, index: u32, depth: u32, }, Recur(Rc<ModuleData>), Symbol(Text), Str(Text), App(Box<[Expr]>), Abs(Rc<Lambda>), Map(Vec<(Expr, Expr)>), Home { leaf: HomeLeaf, depth: u32, },
}
Expand description

An Elly expression in the first subset. Strings and records are deferred (see the spec), so there is no variant for them yet.

Variants§

§

Int(BigInt)

An arbitrary-precision integer literal, parsed from the token (0, -123, 0xCAFE); see the integers section of the spec.

§

List(Vec<Expr>)

A runtime list literal from a Muon <list> ([…]), of any arity: [] (the empty list, which is unit), [e] (a genuine 1-list, distinct from e), or [e0, e1, …]. Parens (…) never produce this — they are grouping / argument spread at parse time (see parse.rs).

§

Name(Text)

A bare name: a reference to an enclosing &-binding, else a free name. Produced by the parser as the unresolved form; the resolution pass (resolve.rs) rewrites every in-scope Name into a Expr::Local and rejects the rest. Tooling that wants the raw, pre-resolution tree (parse_open) keeps seeing Name; the evaluator only ever sees Local.

§

Local

A resolved reference: a flat de Bruijn index produced by the resolver from a Expr::Name. The environment is a nameless cons list of bindings (one cell per bound name, innermost first), and index counts cells to walk from the top (0 = the most recent binding) — so the evaluator’s lookup is a pointer chase with no string compare and no per-link clone. The original name is kept only for rendering, boxed so it does not widen Expr past four words (it is read solely by to_sexp / to_json): a Local then prints exactly like the Name it replaced ((name foo) / {"name":"foo"}), so the goldens are unchanged.

Fields

§name: Box<Text>
§index: u32
§

Builtin(Builtin)

A __-builtin resolved at parse (see Builtin::from_name). __ names are un-bindable, so a reference like __Int.add never depends on the environment; resolving it here turns each call into a direct dispatch rather than a failing env walk plus a name match at eval. Rendered exactly like the Name it replaces ((name __Int.add) / {"name":"__Int.add"}) so the goldens are unchanged.

§

ModItem

A module sibling reference: a name that resolved not to a lexical binding but to another item of the enclosing module (see docs/done/2026-08-07_elly-modules-v0.md). Produced only by the module resolver (resolve::resolve_module_bodies), never by parse; it is a sink — it carries no module reference and is resolved at eval through the home module carried in the environment (EnvNode::Module).

index is the item’s position in the home module’s (name-sorted) item table, assigned at resolve so eval indexes straight into it with no name compare — the module-tier analogue of a Local’s de Bruijn index. name is kept for rendering only (boxed to keep Expr at four words). Renders (moditem factorial) / {"moditem":"factorial"}. depth is how many Module terminals the walk skips before the one that owns this item. A program with one module has no nesting and every ModItem carries 0; a recur inside a module body puts a second terminal on the chain, and a reference to the module’s own item from inside the recur has to step over the recur’s. It is the barrier-stack distance the resolver measured, not rendered (like a Local’s index, it is derived addressing).

Fields

§name: Box<Text>
§index: u32
§depth: u32
§

Recur(Rc<ModuleData>)

A recursive binding group as an expression: recur (a = va, b = vb) e. The bindings are simultaneous — each sees all of them, itself included — which is what separates it from let, whose group is sequential and desugars to nested App/Abs with no node of its own.

The group is a module — the whole of one, body included: the bindings are its (name-sorted) item table, and they reach each other as ModItems through the terminal rather than by capturing references to each other, the edge that would cycle. The expression the group scopes over is the ModuleData’s own body, the slot a module source fills with __main. Evaluating this builds the terminal over the current environment (the cons-shaped frame) and runs that body under it; see docs/done/2026-08-13_elly-recur.md and docs/done/2026-08-14_elly-run.md.

§

Symbol(Text)

A .-prefixed literal (.foo, .0), stored without the dot — the dot is the Muon sigil and is re-added when displayed / dumped.

§

Str(Text)

A string literal, decoded at parse from a Muon <str> (JSON/Muon escapes resolved, \uXXXX surrogate pairs combined) into owned UTF-8. It is self-evaluating: eval clones the handle into Value::Str. Rendered as the bare quoted, re-escaped literal ("foo") — the quotes already mark it apart from .foo / foo, so no (str …) wrapper.

§

App(Box<[Expr]>)

Application: a flattened call spine whose element 0 is the callee and [1..] the arguments. A source spine f a b c and a spread call f(a, b) both parse into one node with a known call-site arity, so the evaluator binds a whole call’s arguments in one pass (see apply_n in eval.rs). Always holds at least a callee and one argument (two elements); currying is recovered by apply_n’s over-application loop, so a flat spine is semantically identical to the left-nested binary applications it replaced — which is exactly how it is re-rendered in to_sexp / to_json.

§

Abs(Rc<Lambda>)

Abstraction &<pattern> body: the one universal binding form, its code (Lambda: the parameter patterns and the body) shared behind Rc. A run of &p0 &p1 … is collected at parse into one multi-parameter Lambda (arity head.len()), so applying it matches a whole call’s arguments in one pass. The evaluator builds a closure by cloning the Rc<Lambda> and capturing the environment, rather than deep-cloning the subtree. Rendered as nested (abs p0 (abs p1 …)) — the curried reading the collected head stands for — to keep the goldens stable.

§

Map(Vec<(Expr, Expr)>)

A map literal from a Muon <block> ({ … }): its entries as (key-expr, value-expr) pairs, in source order. Keys stay expressions until eval, so computed keys ((expr)) just evaluate like any other expression; see the maps section of the spec.

§

Home

A home-module leaf: __module, __new or __value, each reading the module the body it sits in was written in (see HomeLeaf). Like a ModItem it is a sink — it carries no module reference and finds its module through the environment’s terminal at eval — and like one it costs a leaf and no capture slot.

depth is how many Module terminals to step over before the module: a leaf names the nearest terminal written as a module, so a recur between the leaf and its module is stepped over and a method that loops internally still constructs objects of its own type. The resolver measures it (the same barrier-stack distance a ModItem carries) and rejects a leaf with no module on the stack; it is derived addressing, so it is not rendered. See docs/done/2026-08-15_elly-objects-v0.md.

Fields

§depth: u32

Implementations§

Source§

impl Expr

Source

pub fn to_sexp(&self) -> String

Serialize to a compact s-expression, e.g. (app (name f) (name x)).

Source

pub fn to_json(&self) -> String

Serialize to compact, tagged JSON, e.g. {"app":[{"name":"f"},{"name":"x"}]}. Parallels muon::Seq::to_json; used by the elly-wasm playground to render the AST as a tree.

Trait Implementations§

Source§

impl Clone for Expr

Source§

fn clone(&self) -> Expr

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Expr

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl PartialEq for Expr

Source§

fn eq(&self, other: &Expr) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Eq for Expr

Source§

impl StructuralPartialEq for Expr

Auto Trait Implementations§

§

impl Freeze for Expr

§

impl !RefUnwindSafe for Expr

§

impl !Send for Expr

§

impl !Sync for Expr

§

impl Unpin for Expr

§

impl UnsafeUnpin for Expr

§

impl !UnwindSafe for Expr

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.