GithubHelp home page GithubHelp logo

cedric-h / rust_lisp Goto Github PK

View Code? Open in Web Editor NEW

This project forked from brundonsmith/rust_lisp

1.0 1.0 0.0 94 KB

A Rust-embeddable Lisp, with support for interop with native Rust functions

Rust 100.00%

rust_lisp's Introduction

Rust

What is this?

This is a Lisp interpreter, written in Rust, intended to be embeddable as a library in a larger application for scripting purposes. Goals:

  • Small footprint (both code size and memory usage)
  • No dependencies
  • Easy, ergonomic interop with native Rust functions
  • Small but practical set of Lisp functionality

Basic Usage

[dependencies]
rust_lisp = "0.1.0"
use std::{cell::RefCell, rc::Rc};

use rust_lisp::{parse,eval,default_env};

fn main() {

  // create a base environment
  let env = Rc::new(RefCell::new(default_env()));

  // parse into an iterator of syntax trees (one for each root)
  let mut ast_iter = parse("(+ \"Hello \" \"world!\")");
  let first_expression = ast_iter.next().unwrap().unwrap();

  // evaluate
  let evaluation_result = eval(env.clone(), &first_expression).unwrap();

  // use result
  println!("{}", &evaluation_result);
}

As you can see, the base environment is managed by the user of the library, as is the parsing stage. This is to give the user maximum control, including error-handling by way of Results.

The data model

The heart of the model is Value, an enum encompassing every type of valid Lisp value. Most of these are trivial, but Value::List is not. It holds a recursive List data structure which functions internally like a linked-list. into_iter() and from_iter() have been implemented for List, and there is also a lisp! macro (see below) which makes working with Lists, in particular, much more conventient.

Value does not implement Copy because of cases like Value::List, so if you read the source you'll see lots of value.clone(). This almost always amounts to copying a primitive, except in the Value::List case where it means cloning an internal Rc pointer. In all cases, it's considered cheap enough to do liberally.

The environment and exposing Rust functions

The base environment is managed by the user of the library mainly so that it can be customized. default_env() prepopulates the environment with a number of common functions, but these can be omitted (or pared down) if you wish. Adding an entry to the environment is also how you would expose your Rust functions to your scripts, which can take the form of either regular functions or closures:

fn my_func(env: Rc<RefCell<Env>>, args: &Vec<Value>) -> Result<Value,RuntimeError> {
  println!("Hello world!");
  return Ok(Value::NIL);
}

...

  env.borrow_mut().entries.insert(
    String::from("sayhello"),
    Value::NativeFunc(my_func));
entries.insert(
  String::from("sayhello"),
  Value::NativeFunc(
    |env, args| {
      println!("Hello world!");
      return Ok(Value::NIL);
    }));

In either case, a native function must have the following function signature:

type NativeFunc = fn(env: Rc<RefCell<Env>>, args: &Vec<Value>) -> Result<Value, RuntimeError>;

The first argument is the environment at the time and place of calling (closures are implemented as environment extensions). The second argument is the Vec of evaluated argument values. For convenience, utility functions (require_parameter(), require_int_parameter(), etc) have been provided for doing basic argument retrieval with error messaging. See default_environment.rs for examples.

The lisp! macro

A Rust macro, named lisp!, is provided which allows the user to embed sanitized Lisp syntax inside their Rust code, which will be converted to an AST at compile-time:

fn parse_basic_expression() {
  let ast = parse("
    (list 
      (* 1 2)  ;; a comment
      (/ 6 3 \"foo\"))").next().unwrap().unwrap();

  assert_eq!(ast, lisp! {
    (list 
      (* 1 2)
      (/ 6 3 "foo"))
  });
}

Note that this just gives you a syntax tree (in the form of a Value). If you want to actually evaluate the expression, you would need to then pass it to eval().

The macro also allows Rust expressions (of type Value) to be embedded within the lisp code using { }:

fn parse_basic_expression() {
  let ast = parse("
    (+ 3 1)").next().unwrap().unwrap();

  let n = 2;

  assert_eq!(ast, lisp! {
    (+ { Value::Int(n + 1) } 1)
  });
}

NOTE: There is currently a problem with the macro where predicates ending in ? cannot be used. This is because ? cannot be a valid part of an identifier in Rust, and so null? for example cannot be processed by Rust as a single token. The solution will likely involve renaming those predicates to not include ?. This is why the project is still in version 0.X.X :)

Included functionality

Special forms: define, set, defun, lambda, quote, let, begin, cond, if, and, or

Functions (in default_env()): print, null?, number?, symbol?, boolean?, procedure?, pair?, car, cdr, cons, list, nth, sort, reverse, map, filter, length, range, +, -, *, /, truncate, not, ==, !=, <, <=, >, >=, apply, eval

Other features:

  • Single-tick quoting
  • Tail-call optimization

rust_lisp's People

Stargazers

Ryan Chou avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.