tulisp/
lib.rs

1/*!
2Tulisp is a Lisp interpreter that can be embedded into Rust programs.  The
3syntax tries to closely match that of Emacs Lisp.  It was primarily designed to
4be a configuration language, but it also works well as a general purpose
5embedded scripting language.
6
7One of the many benefits of using the Emacs Lisp syntax is that we can reuse its
8documentation for the builtin functions and macros.  And for people who are
9already familiar with Emacs Lisp, there's no need to learn an extra language.
10
11## Getting started
12
13Tulisp requires `rustc` version 1.70 or higher.
14
15It is very easy to get started.  Here's an example:
16*/
17
18/*!
19  ```rust
20  use tulisp::{TulispContext, tulisp_fn, Error};
21
22  fn main() -> Result<(), Error> {
23      // Create a new Tulisp execution context.
24      let mut ctx = TulispContext::new();
25
26      // Add a function called `add_nums` to `ctx`.
27      #[tulisp_fn(add_func = "ctx")]
28      fn add_nums(num1: i64, num2: i64) -> i64 {
29          num1 + num2
30      }
31
32      // Write a lisp program that calls `add_nums`
33      let program = "(add_nums 10 20)";
34
35      // Evaluate the program, and save the result.
36      let sum: i64 = ctx.eval_string(program)?.try_into()?;
37
38      assert_eq!(sum, 30);
39      Ok(())
40  }
41  ```
42
43## Features
44
45- `defun`s, `defmacro`s and `lambda`s
46- `intern` to find/create symbols dynamically
47- Backquote/Unquote forms (for example `` `(answer . ,(+ 2 3)) ``)
48- Threading macros (`thread-first` and `thread-last`)
49- Methods for reading from alists and plists
50- Lexical scopes and lexical binding
51- Tailcall Optimization
52- Proc macros for exposing rust functions to tulisp
53- Decl macros for
54  [creating lists](https://docs.rs/tulisp/latest/tulisp/macro.list.html)
55  and
56  [destructuring lists](https://docs.rs/tulisp/latest/tulisp/macro.destruct_bind.html)
57  quickly.
58- Easy to use [interpreter](https://docs.rs/tulisp/latest/tulisp/struct.TulispContext.html) and [object](https://docs.rs/tulisp/latest/tulisp/struct.TulispObject.html)s
59- Backtraces for errors
60
61## Performance
62
63Tulisp has a light-weight tree-walking interpreter with very low startup times and sufficient speed for many config/simulation needs.
64
65## Builtin functions
66
67A list of currently available builtin functions can be found [here](builtin).
68*/
69
70/*!
71## Next steps
72
731. Values in _Tulisp_ are represented in rust as [`TulispObject`]s.  That struct
74   implements methods for performing operations on Tulisp values.
75
761. [`TulispContext`] tracks the state of the interpreter and provides methods
77   for executing _Tulisp_ programs.
78
791. [`#[tulisp_fn]`](tulisp_fn) and [`#[tulisp_fn_no_eval]`](tulisp_fn_no_eval)
80   are flexible attribute macros for adding many different kinds of functions to
81   a `TulispContext` object, so that they can be called from lisp code.
82*/
83
84mod eval;
85mod macros;
86mod parse;
87
88pub use tulisp_proc_macros::{tulisp_add_func, tulisp_add_macro, tulisp_fn, tulisp_fn_no_eval};
89
90pub mod builtin;
91
92mod cons;
93pub use cons::{BaseIter, Iter};
94
95mod context;
96pub use context::TulispContext;
97
98mod error;
99pub use error::{Error, ErrorKind};
100
101pub mod lists;
102
103mod value;
104#[doc(hidden)]
105pub use value::TulispValue;
106
107mod object;
108pub use object::TulispObject;
109
110#[cfg(test)]
111mod test_utils {
112    #[track_caller]
113    pub(crate) fn eval_assert_equal(ctx: &mut crate::TulispContext, a: &str, b: &str) {
114        let av = ctx.eval_string(a).unwrap();
115        let bv = ctx.eval_string(b).unwrap();
116        assert!(
117            crate::TulispObject::equal(&av, &bv),
118            "{}(=> {}) != {}(=> {})",
119            a,
120            av,
121            b,
122            bv
123        );
124    }
125
126    #[track_caller]
127    pub(crate) fn eval_assert(ctx: &mut crate::TulispContext, a: &str) {
128        let av = ctx.eval_string(a).unwrap();
129        assert!(av.is_truthy(), "{}(=> {}) is not true", a, av);
130    }
131
132    #[track_caller]
133    pub(crate) fn eval_assert_not(ctx: &mut crate::TulispContext, a: &str) {
134        let av = ctx.eval_string(a).unwrap();
135        assert!(av.null(), "{}(=> {}) is not nil", a, av);
136    }
137}