Skip to content

Commit

Permalink
Document embedding the REPL within a Rust application (#135)
Browse files Browse the repository at this point in the history
* Document how to embed the REPL within a Rust program.

* Update rustdocs and rename to steel_repl::run_repl.
  • Loading branch information
wmedrano authored Jan 16, 2024
1 parent 4cf5e15 commit 0217b8e
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 16 deletions.
12 changes: 8 additions & 4 deletions crates/steel-core/src/primitives/strings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ fn char_upcase(c: char) -> char {

/// # steel/strings
///
/// Strings in Steel are immutable, fixed length arrays of characters. They are heap allocated,
/// and are implemented under the hood as referenced counted rust `Strings`.
/// Strings in Steel are immutable, fixed length arrays of characters. They are heap allocated, and
/// are implemented under the hood as referenced counted Rust `Strings`. Rust `Strings` are stored
/// as UTF-8 encoded bytes.
#[steel_derive::define_module(name = "steel/strings")]
pub fn string_module() -> BuiltInModule {
let mut module = BuiltInModule::new("steel/strings");
Expand Down Expand Up @@ -270,6 +271,7 @@ pub fn replace(value: &SteelString, from: &SteelString, to: &SteelString) -> Res
/// # Examples
/// ```scheme
/// > (to-string 10) ;; => "10"
/// > (to-string 10 20) ;; => "10 20"
/// > (to-string "hello" "world") ;; => "hello world"
/// ```
#[native(name = "to-string", arity = "AtLeast(0)")]
Expand Down Expand Up @@ -529,14 +531,16 @@ pub fn ends_with(value: &SteelString, suffix: &SteelString) -> bool {
value.ends_with(suffix.as_str())
}

/// Get the length of the given string
/// Get the length of the given string in UTF-8 bytes.
///
/// (string-length string?) -> int?
///
/// # Examples
///
/// ```scheme
/// > (string-length "apples") ;; => 6
/// > (string-length "✅") ;; => 3
/// > (string-length "🤖") ;; => 4
/// ```
#[function(name = "string-length")]
pub fn string_length(value: &SteelString) -> usize {
Expand All @@ -553,7 +557,7 @@ pub fn string_length(value: &SteelString) -> usize {
/// ```scheme
/// > (string-append) ;; => ""
/// > (string-append "foo" "bar") ;; => "foobar"
// ```
/// ```
#[function(name = "string-append")]
pub fn string_append(mut rest: RestArgsIter<'_, &SteelString>) -> Result<SteelVal> {
rest.0
Expand Down
9 changes: 7 additions & 2 deletions crates/steel-repl/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
#[macro_use]
pub mod repl;
pub mod highlight;
mod repl;
mod highlight;

/// Run the Steel repl with the given `Engine`. Exits on IO error or when the user requests to exit.
pub fn run_repl(vm: steel::steel_vm::engine::Engine) -> std::io::Result<()> {
repl::repl_base(vm)
}
2 changes: 1 addition & 1 deletion crates/steel-repl/src/repl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ pub fn repl_base(mut vm: Engine) -> std::io::Result<()> {
/ ___// /____ ___ / / Version 0.5.0
\__ \/ __/ _ \/ _ \/ / https://github.com/mattwparas/steel
___/ / /_/ __/ __/ / :? for help
/____/\__/\___/\___/_/
/____/\__/\___/\___/_/
"#
.bright_yellow()
.bold()
Expand Down
2 changes: 2 additions & 0 deletions docs/book.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ multilingual = false
src = "src"
title = "Steel"

# https://github.com/slowsage/mdbook-pagetoc
[preprocessor.pagetoc]

[output.html]
additional-css = ["theme/pagetoc.css"]
additional-js = ["theme/pagetoc.js"]
15 changes: 12 additions & 3 deletions docs/src/builtins/steel_strings.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# steel/strings

#### steel/strings

Strings in Steel are immutable, fixed length arrays of characters. They are heap allocated,
and are implemented under the hood as referenced counted rust `Strings`.
Strings in Steel are immutable, fixed length arrays of characters. They are heap allocated, and
are implemented under the hood as referenced counted Rust `Strings`. Rust `Strings` are stored
as UTF-8 encoded bytes.

### **char=?**
Checks if two characters are equal

Expand Down Expand Up @@ -124,15 +127,19 @@ Concatenates all of the given strings into one
```scheme
> (string-append) ;; => ""
> (string-append "foo" "bar") ;; => "foobar"
```

### **string-length**
Get the length of the given string
Get the length of the given string in UTF-8 bytes.

(string-length string?) -> int?

#### Examples

```scheme
> (string-length "apples") ;; => 6
> (string-length "✅") ;; => 3
> (string-length "🤖") ;; => 4
```
### **to-string**
Concatenatives all of the inputs to their string representation, separated by spaces.
Expand All @@ -144,8 +151,10 @@ Concatenatives all of the inputs to their string representation, separated by sp
#### Examples
```scheme
> (to-string 10) ;; => "10"
> (to-string 10 20) ;; => "10 20"
> (to-string "hello" "world") ;; => "hello world"
```

### **trim**
Returns a new string with the leading and trailing whitespace removed.

Expand Down
76 changes: 76 additions & 0 deletions docs/src/start/embedded.md
Original file line number Diff line number Diff line change
@@ -1 +1,77 @@
# Using Steel as an embedded scripting engine

Steel can be used as a scripting language within a Rust program. You can achieve
this by creating a Steel `Engine` object. The `Engine` object allows you to
execute Scheme code and interact with it from your Rust program. For more
details about `Engine`, see the [Engine API](../engine/engine.html).

## Steel Engine

The Steel Virtual Machine is provided by the `steel-core` trait.

```toml
[dependencies]
steel-core = { git="https://github.com/mattwparas/steel.git", branch = "master" }
```

The following example runs a few expressions in a Steel `Engine` and asserts
that the results are as expected.

```rust,noplaypen
use steel::steel_vm::engine::Engine;
use steel::SteelVal;
fn main() {
let mut steel_engine = Engine::new();
let answer = steel_engine.run(
(r#"
(+ 1 2 3 4)
(+ 5 6 7 8)
"#),
);
assert_eq!(answer, vec![SteelVal::IntV(10), SteelVal::IntV(26)])
}
```

### Engine::new

Creates a new engine. The `Engine` is used to run Steel Scheme code. Note that
the `Engine` is not `Send` or `Sync`. This means it is bound to the current
thread and cannot be shared or sent across other threads.

```rust,noplaypen
let mut steel_engine = Engine::new();
```

### Engine::run

Runs a Steel expression and returns the result as a `Vec<SteelVal>`. If any
error occurs, then `Err(SteelErr)` is returned.

```rust,noplaypen
let mut steel_engine = Engine::new();
assert_eq!(steel_engine.run("(+ 1 1)"), Ok(vec![SteelVal::IntV(2)]));
assert!(steel_engine.run("(+ 1 undefined-identifier)").is_err());
```

## Embedding The Steel REPL

Repl functionality is provided by the `steel-repl` crate.

```toml
[dependencies]
steel-repl = { git="https://github.com/mattwparas/steel.git", branch = "master" }
```

### run_repl

`run_repl` runs the Steel repl until an IO error is encountered or the user
exits the repl. The repl may be exited by:

- Running the `(quit)` Steel Scheme function.
- Pressing either `ctrl+c` or `ctrl+d` within the repl.

```rust,noplaypen
let steel_engine = Engine::new();
steel_repl::run_repl(steel_engine).unwrap();
```
4 changes: 2 additions & 2 deletions examples/spellcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ extern crate steel_repl;
use steel_derive::Steel;

use steel::steel_vm::engine::Engine;
use steel_repl::repl::repl_base;
use steel_repl::run_repl;

use std::cell::RefCell;
use std::cmp::{max, min};
Expand Down Expand Up @@ -45,7 +45,7 @@ fn main() {
e.emit_result("spellcheck.rkt", contents);
}

finish(repl_base(vm))
finish(run_repl(vm))
}

fn finish(result: Result<(), std::io::Error>) -> ! {
Expand Down
8 changes: 4 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ extern crate steel_repl;

use steel::steel_vm::engine::Engine;
use steel_doc::walk_dir;
use steel_repl::repl::repl_base;
use steel_repl::run_repl;

use std::path::PathBuf;
use std::process;
Expand Down Expand Up @@ -63,7 +63,7 @@ pub fn run(clap_args: Args) -> Result<(), Box<dyn Error>> {
action: None,
..
} => {
repl_base(vm)?;
run_repl(vm)?;
Ok(())
}

Expand Down Expand Up @@ -202,7 +202,7 @@ pub fn run(clap_args: Args) -> Result<(), Box<dyn Error>> {
e.emit_result(path.to_str().unwrap(), &contents);
}

repl_base(vm)?;
run_repl(vm)?;
Ok(())
}

Expand Down Expand Up @@ -307,7 +307,7 @@ lto = true
}

_ => {
repl_base(vm)?;
run_repl(vm)?;
Ok(())
}
}
Expand Down

0 comments on commit 0217b8e

Please sign in to comment.