pub struct Context {
    pub lang: HashMap<String, SExp>,
    /* private fields */
}
Expand description

Evaluation context for LISP expressions.

Note

Context::default() only provides very basic utilities. To obtain an evaluation context with useful functions available, use Context::base().

Some implementation details

Context maintains separate environments for “core” (special forms, etc.), “lang” (basic functions, vectors, and more), and “user” definitions. Most of the provided methods operate on the “user” environment, as the intended use case keeps the other environments immutable once they have been initialized.

Fields

lang: HashMap<String, SExp>

You can insert additional definitions here to make them available throughout the runtime. These definitions will not go out of scope automatically, but can be overridden (see get for semantic details).

Implementations

Base context - defines a number of useful functions and constants for use in the runtime.

Example
use parsley::prelude::*;
let mut ctx = Context::base();

assert_eq!(
    ctx.eval(
        sexp![SExp::sym("null?"), SExp::sym("null")]
    ).unwrap(),
    SExp::from(true),
);

println!("{}", ctx.get("eq?").unwrap());   // "#<procedure>"
println!("{}", ctx.get("+").unwrap());     // "#<procedure>"

Math functions that are less commonly used. Intended to be layered on top of the base context.

Example
use parsley::prelude::*;
let mut ctx = &mut Context::base().math();
let mut asrt = |lhs, rhs| {
    assert_eq!(ctx.run(lhs).unwrap(), ctx.run(rhs).unwrap())
};

asrt("(is-nan NaN)", "#t");
asrt("(floor -4.07326)", "-5");
asrt("(ceil 7.1)", "8");
asrt("(hypot 3 4)", "5");
asrt("(recip 100)", "0.01");
asrt("(log (exp 7))", "7");

Start capturing printed content in a buffer.

Capture display and write statement output in a buffer.

Get the captured side-effect output.

Add a new, nested scope.

See Context::pop for a usage example.

Remove the most recently added scope.

If the stack height is 1, all definitions will be cleared, and the global scope will be replaced with an empty one.

Example
use parsley::prelude::*;
let mut ctx = Context::default();

assert_eq!(ctx.get("x"), None);
ctx.push();
ctx.define("x", SExp::Null);
assert_eq!(ctx.get("x"), Some(SExp::Null));
ctx.pop();
assert_eq!(ctx.get("x"), None);

Create a new definition in the current scope.

Get the definition for a symbol in the execution environment.

Returns None if no definition is found.

Override semantics

This method searches for a definition in the following order:

  1. The core language
  2. User definitions, starting from the most recent scope and working backward to the top-level
  3. Language-level definitions

What this means is that definitions populated in the lang field can be overridden inside the runtime (e.g. in a REPL), but special form keywords cannot. For example, we can (define null "foo"), but we cannot (set! and or).

Examples
let ctx = parsley::Context::default(); // only core definitions included
assert!(ctx.get("potato").is_none());
use parsley::prelude::*;
let mut ctx = Context::default();

ctx.define("x", SExp::from(3));
assert_eq!(ctx.get("x"), Some(SExp::from(3)));

Re-bind an existing definition to a new value.

Errors

Returns Ok if an existing definition was found and updated. Returns Err if no definition exists.

Example
use parsley::prelude::*;
let mut ctx = Context::default();

assert!(ctx.set("x", SExp::from(false)).is_err());    // Err, because x is not yet defined
ctx.define("x", SExp::from(3));                       // define x
assert_eq!(ctx.get("x"), Some(SExp::from(3)));        // check that its value is 3
assert!(ctx.set("x", SExp::from("potato")).is_ok());  // Ok because x is now defined
assert_eq!(ctx.get("x"), Some(SExp::from("potato"))); // check that its value is now "potato"

Run a code snippet in an existing Context.

Errors

Returns Err if a parsing or runtime error occurs.

Example
use parsley::prelude::*;
let mut ctx = Context::base();

assert!(ctx.run("x").is_err());
assert!(ctx.run("(define x 6)").is_ok());
assert_eq!(ctx.run("x").unwrap(), SExp::from(6));

Evaluate an S-Expression in a context.

The context will retain any definitions bound during evaluation (e.g. define, set!).

Errors

An Err will be returned if an undefined symbol is referenced, the empty list is evaluated, a non-procedure value is called, or a procedure returns an error.

Examples
use parsley::prelude::*;
let result = Context::base().eval(
    sexp![SExp::sym("eq?"), 0, 1]
);
assert_eq!(result.unwrap(), SExp::from(false));
use parsley::prelude::*;
let mut ctx = Context::base();

let exp1 = sexp![SExp::sym("define"), SExp::sym("x"), 10];
let exp2 = SExp::sym("x");

ctx.eval(exp1);
assert_eq!(ctx.eval(exp2).unwrap(), SExp::from(10));

Trait Implementations

Returns the “default value” for a type. Read more

Writes a string slice into this writer, returning whether the write succeeded. Read more

Writes a char into this writer, returning whether the write succeeded. Read more

Glue for usage of the write! macro with implementors of this trait. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

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

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.