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
sourceimpl Context
impl Context
sourcepub fn base() -> Self
pub fn base() -> Self
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>"
sourceimpl Context
impl Context
sourcepub fn math(self) -> Self
pub fn math(self) -> Self
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");
sourceimpl Context
impl Context
sourcepub fn push(&mut self)
pub fn push(&mut self)
Add a new, nested scope.
See Context::pop
for a usage example.
sourcepub fn pop(&mut self)
pub fn pop(&mut self)
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);
sourcepub fn get(&self, key: &str) -> Option<SExp>
pub fn get(&self, key: &str) -> Option<SExp>
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:
- The core language
- User definitions, starting from the most recent scope and working backward to the top-level
- 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)));
sourcepub fn set(&mut self, key: &str, value: SExp) -> Result
pub fn set(&mut self, key: &str, value: SExp) -> Result
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"
sourcepub fn eval(&mut self, expr: SExp) -> Result
pub fn eval(&mut self, expr: SExp) -> Result
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
Auto Trait Implementations
impl !RefUnwindSafe for Context
impl !Send for Context
impl !Sync for Context
impl Unpin for Context
impl !UnwindSafe for Context
Blanket Implementations
sourceimpl<T> BorrowMut<T> for T where
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
const: unstable · sourcefn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more