scheme.rs icon indicating copy to clipboard operation
scheme.rs copied to clipboard

a simple yet comprehensive scheme interpreter in rust

  • scheme.rs /scheme.rs/ is a simple Scheme interpreter that implements considerably large subset of R5RS with some extensions from R7RS. No dependencies to any other Rust packages.

** Motivation I was studying about compilers and interpreters. On the other hand I was trying to learn Rust. So I combined those two and this project has emerged. There are thousands of fast, mature and feature-rich Scheme interpreters that you can use. This project is not intended to be usable in production although I use it for my personal scripts and one can embed /scheme.rs/ into ones project to provide scripting facilities.

** Examples #+BEGIN_SRC scheme ;; FizzBuzz (define (fizzbuzz x y) (println (cond ((= (modulo x 15) 0 ) "FizzBuzz") ((= (modulo x 3) 0 ) "Fizz") ((= (modulo x 5) 0 ) "Buzz") (else x)))

(if (< x y) (fizzbuzz (+ x 1) y)))

(fizzbuzz 1 100)

;; Read a line from file and print it (call-with-input-file "file.txt" (λ (file) (println (read-line file))))

;; Tail recursive fibanocci (define (fib n) (define (fib-helper a b n) (if (= n 0) a (fib-helper b (+ a b) (- n 1))))

(fib-helper 0 1 n))

(display (fib 60)) ; prints 1548008755920 #+END_SRC

** Usage Run it using cargo: #+BEGIN_SRC bash cd scheme.rs cargo run #+END_SRC

This will fire up REPL. You can also run files directly: #+BEGIN_SRC bash cargo run filename.scm #+END_SRC

** Notes about implementation *** Extras

  • Brackets can be used instead of parenthesis.

*** What is not included?

  • Mutable lists
  • Vectors (Lists are implemented in terms of vectors)
  • Hygienic macros
  • ~call-with-current-continuation~ and it's derivatives

*** Proper tail recursion Tail calls are optimized but this implementation does not reflect the standard fully. Because there are no macros, functions like ~and~, ~or~, ~cond~, ~let~ etc. are implemented as separate procedures. So a procedure with ~and~ in it's tail call may blow up the stack. Regardless of macro implementation, I may fix this in the future simply by expanding required functions before evaluation.

** TODO Goals

  • [ ] Mutable lists
  • [ ] Hygienic macros
  • [ ] Add useful SFRI's like:
    • [ ] SRFI-9 (Record types)
    • [ ] SRFI-6 (String ports)
    • [ ] SRFI-1 (List library, some of the functions are already available)
    • [ ] SRFI-13 (String library)
    • [ ] SRFI-88 (Keyword objects)
  • Adding a basic VM with garbage collector may be a long term goal (which will allow implementation of cal/cc).

** List of functions Fair amount of these functions are implemented in Rust.

| define | < | procedure? | char<=? | | set! | > | boolean? | char>=? | | λ | <= | char? | char-ci=? | | lambda | >= | string? | char-ci<? | | apply | = | integer? | char-ci>? | | let | cond | exact? | char-ci<=? | | let* | case | inexact? | char-ci>=? | | letrec | and | number? | string=? | | quote | or | pair? | string<? | | quasiquote | cons | list? | string>? | | unquote | car | output-port? | string<=? | | eqv? | cdr | input-port? | string>=? | | eq? | append | textual-port? | string-ci=? | | equal? | list-copy | binary-port? | string-ci<? | | + | string-append | not | string-ci>? | | - | string-upcase | zero? | string-ci<=? | | * | string-downcase | positive? | string-ci>=? | | / | string-length | negative? | substring | | remainder | char-upcase | odd? | string-ref | | modulo | char-downcase | even? | string | | numerator | char-upper-case? | abs | symbol->string | | denominator | char-lower-case? | gcd | string->symbol | | sqrt | char-alphabetic? | lcm | string->list | | expt | char-numeric? | 1+ | list->string | | ceiling | char-alphanumeric? | 1- | char->integer | | floor | char-whitespace? | list | integer->char | | truncate | string-copy | list-ref | caar | | round | string-append | null? | cadr | | exp | load | sum | cdar | | log | file-exists? | product | cddr | | sin | delete-file | map | caaar | | cos | system* | filter | caadr | | tan | get-environment-variable | reverse | cadar | | asin | get-environment-variables | length | caddr | | acos | open-binary-input-file | max | cdaar | | atan | open-binary-output-file | min | cdadr | | number->string | open-input-file | list-tail | cddar | | string->number | open-output-file | list-head | cdddr | | id | read | list-ref | caaaar | | curry | read-u8 | memq | caaadr | | foldr | read-line | memv | caadar | | foldl | read-char | member | caaddr | | unfold | read-all | assq | cadaar | | reduce | write | assv | cadadr | | call-with-input-file | display | assoc | caddar | | call-with-output-file | newline | char=? | cadddr | | println | write-string | char<? | cdaaar | | compose | close-port | char>? | cdaadr |

List may not be complete.