Skip to main content

expr

Macro expr 

Source
macro_rules! expr {
    (true) => { ... };
    (false) => { ... };
    ($k:tt -> $v:tt) => { ... };
    (:: $name:ident [ $($args:tt)* ]) => { ... };
    (:: $d:tt $name:ident [ $($args:tt)* ]) => { ... };
    (:: $name:ident) => { ... };
    (:: $d:tt $name:ident) => { ... };
    ($head:ident $(:: $seg:ident)+ [ $($args:tt)* ]) => { ... };
    ($head:ident [ $($args:tt)* ]) => { ... };
    ({ $($assoc:tt)* }) => { ... };
    ($head:ident $(:: $seg:ident)+) => { ... };
    ($e:expr) => { ... };
}
Expand description

Build a Wolfram Language Expr with WL-like syntax.

§Syntax

PatternResult
expr!(System::Head[a, b])Normal with the symbol System`Head
expr!(A::B::C[a, b])Normal with A`B`C (each :: → a context backtick)
expr!(var[a, b])Normal with the variable var as head (call over var)
expr!(A::B::C)the symbol A`B`C
expr!(::Name) / expr!(::Name[…])the context-less symbol Name (works nested in arg, splice, and association-value positions too)
expr!(::$Name) / expr!(::$Name[…])the context-less $-symbol $Name (e.g. $Context, $InputFileName)
expr!(k -> v)Rule[k, v] — usable inline inside …[...]
expr!({k -> v, ...})Association — every element must be a -> Rule; bare values are a compile error
expr!(true) / expr!(false)True / False symbols
expr!("str"), expr!(42), expr!(3.14)string / integer / real
expr!(rust_var), expr!((rust_expr))Expr::from(…)
expr!(f[..iter])splice a sequence of Into<Expr> items as args

§Conventions

  • Symbols are always fully qualified: a bare ident is always a Rust variable (in head and arg position) — there is no implicit System`` prefix. Write System::Times[…], Global::x`, etc. for symbols.
  • Arg position: string literals become WL strings; k -> v becomes Rule[k, v] inline; {k -> v} an Association; (rust_expr) an arbitrary Rust expression; ..iter splices a sequence.
  • Nesting: Head[a, b] in arg position recurses to all depths.

§Examples

let msg = "something went wrong";

// Failure["RustPanic", <|"MessageTemplate" -> "something went wrong"|>]
// {…} always produces an Association; non-Rule elements are a compile error.
let e = expr!(System::Failure["RustPanic", {"MessageTemplate" -> msg}]);

// {1, 2, 3}
let list = expr!(System::List[1, 2, 3]);

// Tabular`Arrow`ToTabular[{1, 2, 3}]
// Each `::` becomes a context backtick; `list` is a Rust variable spliced as-is.
let table = expr!(Tabular::Arrow::ToTabular[list]);

let head = Symbol::new("Global`f");
// f[1, 2]  — bare ident in head position is a Rust variable, not a symbol.
// To call a symbol by name write expr!(Global::f[1, 2]) instead.
let call = expr!(head[1, 2]);

§Symbols

// Fully qualified: each `::` becomes a context backtick.
assert_eq!(expr!(System::Plus), Expr::symbol(Symbol::new("System`Plus")));
assert_eq!(expr!(My::Custom::Symbol), Expr::symbol(Symbol::new("My`Custom`Symbol")));

// Context-less `::Name` produces the bare symbol `Name` (no context prefix)
// — useful for symbols WL resolves relative to the current context, like
// `$Context` or a name meant to land in `Global\``.
assert_eq!(expr!(::Name), Expr::symbol(Symbol::new("Name")));

// `::$Name` covers `$`-prefixed system symbols (the `$` is pasted back on).
assert_eq!(expr!(::$Context), Expr::symbol(Symbol::new("$Context")));

// A Rust `Symbol`/`Expr` value used bare (no `::`) is spliced in as-is —
// not reinterpreted as WL syntax.
let sym = Symbol::new("Global`counter");
assert_eq!(expr!(sym.clone()), Expr::symbol(sym));

§Function application

// Literal qualified head. `List` gets WL surface syntax (`{…}`); most
// other heads render as `head[…]`, keeping their full qualified name.
assert_eq!(expr!(System::List[1, 2, 3]).to_string(), "{1, 2, 3}");
assert_eq!(expr!(System::Point[1, 2]).to_string(), "System`Point[1, 2]");

// Nested heads recurse to any depth.
assert_eq!(
    expr!(System::Point[System::List[1, 2]]).to_string(),
    "System`Point[{1, 2}]"
);

// A runtime `Symbol` as the head calls that symbol, same as writing it
// out literally — handy when the head name is only known at runtime
// (e.g. built with `format!` or looked up from user input).
let h = Symbol::new("Global`f");
assert_eq!(expr!(h[1, 2]), expr!(Global::f[1, 2]));

// Curried application `f[1, 2][3, 4]`: the head is itself a `Normal`, built
// as an ordinary Rust variable and spliced in as the head.
let inner = expr!(Global::f[1, 2]);
let curried = expr!(inner[3, 4]);
assert_eq!(curried.to_string(), "Global`f[1, 2][3, 4]");

§Associations

// `{k -> v, ...}` always builds an Association; every element must be a
// `->` Rule — a bare value in `{...}` is a compile error (write
// `System::List[..]` for a WL list instead).
assert_eq!(expr!({"a" -> 1, "b" -> 2}).to_string(), r#"<|"a" -> 1, "b" -> 2|>"#);

// Keys and values can be any `expr!` form, including nested function
// calls and symbols — this is the shape `#[derive(ToWXF)]` emits for a
// per-variant `Failure["OutOfRange", <|"Min" -> 0, "Max" -> 255|>]`.
let e = expr!(System::Failure["OutOfRange", {"Min" -> 0, "Max" -> 255}]);
assert_eq!(e.to_string(), r#"System`Failure["OutOfRange", <|"Min" -> 0, "Max" -> 255|>]"#);

§Injecting Rust values: variables, vectors, iterators

// A bare Rust variable in arg position converts via `Expr::from`.
let count = 3i64;
assert_eq!(expr!(System::List[count]), expr!(System::List[3]));

// Parenthesize any other Rust expression — method calls, arithmetic, …
let n = 5i64;
assert_eq!(expr!(System::F[(n * 2)]), expr!(System::F[10]));

// `..iter` splices a sequence of `Into<Expr>` items as args: a `Vec<Expr>`,
// a `Vec<T>` for `T: Into<Expr>`, or any iterator — no intermediate `Vec`
// needed, and it can mix with literal args and other splices.
let values: Vec<i64> = vec![1, 2, 3];
assert_eq!(expr!(System::List[..values]), expr!(System::List[1, 2, 3]));

let middle = vec![1i64, 2];
assert_eq!(
    expr!(System::f[0, ..middle, 9]),
    expr!(System::f[0, 1, 2, 9])
);

// Splice an iterator adaptor directly, with no collect().
let items = vec![1i64, 2, 3];
assert_eq!(
    expr!(System::List[..items.into_iter().rev()]),
    expr!(System::List[3, 2, 1])
);