~gagbo/R7.rs

A rust hosted r7rs scheme interpreter (eternal WIP status to learn PL)

9df947a Start huge multi value refactoring

~gagbo pushed to ~gagbo/rseven git

4 days ago

e72e67e Bump dependencies

~gagbo pushed to ~gagbo/rseven git

7 days ago

#R7.rs

builds.sr.ht status

A R7RS-small implementation in Rust.

#Launch

There is a small REPL you can simply access by running the default binary:

$ cargo run
user> ((lambda (x) (/ x 4)) 28)
7
user> ((lambda (x) (/ x 4)) 28.1)
7.025

#Parser

The parser is based on Pest, and you can use another binary of the cargo workspace to visualize the AST produced:

$ cargo run --bin rseven-tree -- "(let ((x 2) (y 3)) (* x y))"
 program
 └─ command_or_definition
    └─ expression
       └─ derived_expression
          ├─ binding_let "let"
          ├─ binding_spec
          │  ├─ identifier "x"
          │  └─ expression
          │     └─ literal
          │        └─ number
          │           └─ num_10
          │              ├─ prefix_10 ""
          │              └─ complex_10
          │                 └─ real_10
          │                    └─ ureal_10
          │                       └─ decimal_10
          │                          └─ uinteger_10 "2"
          ├─ binding_spec
          │  ├─ identifier "y"
          │  └─ expression
          │     └─ literal
          │        └─ number
          │           └─ num_10
          │              ├─ prefix_10 ""
          │              └─ complex_10
          │                 └─ real_10
          │                    └─ ureal_10
          │                       └─ decimal_10
          │                          └─ uinteger_10 "3"
          └─ body
             └─ sequence
                └─ expression
                   └─ procedure_call
                      ├─ operator
                      │  └─ expression
                      │     └─ identifier "*"
                      ├─ operand
                      │  └─ expression
                      │     └─ identifier "x"
                      └─ operand
                         └─ expression
                            └─ identifier "y"

The parser lives in a standalone crate and you should be able to just use that as a Pest-based parser of r7rs syntax. The slight deviations from the specification are made to help the interpreter and compiler dispatch tasks better.

#Roadmap

  • [x] Read standard
  • [x] Implement and test the parser
  • [x] Implement basic types
  • [x] Implement REPL
  • [x] Implement eval
  • [x] Implement read
  • [ ] Implement (scheme base)

#TODOs

For each extra bit of compliance we go through, usually the parser (which started from the standard spec) gets enhanced to give better lexing information so that the core can make adjustments easily.

#Implement derived expressions

#Conditionals
#Tasks
  • [x] Write tests
  • [x] Enrich parser
  • [x] Pass tests
  • [ ] Go back and do cond-expand
#Notes
  • (when 't (define x 3)) should fail to parse (a definition is not allowed as an expression, and a sequence is only made of expressions), but currently doesn't. It parses define as the name of a procedure, and it misses the definition special treatment in core because of it, triggering a Void Variable x error instead :(
  • Fixing the above with an early return in make_unevaluated_statement means that now eval_lambda cannot support definitions at the beginning of the body in the current form.
  • cond-expand will be done once the design of features and libraries is done and integrated
#Bindings constructs
#Tasks
  • [ ] Write tests
  • [ ] Enrich parser
  • [ ] Pass tests
#Notes
#Sequencing
#Tasks
  • [ ] Write tests
  • [ ] Enrich parser
  • [ ] Pass tests
#Notes
#Iterations
#Tasks
  • [ ] Write tests
  • [ ] Enrich parser
  • [ ] Pass tests
#Notes
#Delayed evaluation
#Tasks
  • [ ] Write tests
  • [ ] Enrich parser
  • [ ] Pass tests
#Notes
#Exception handling
#Tasks
  • [ ] Write tests
  • [ ] Enrich parser
  • [ ] Pass tests
#Notes
#Quasiquotation
#Tasks
  • [ ] Write tests
  • [ ] Enrich parser
  • [ ] Pass tests
#Notes
#Case-lambda
#Tasks
  • [ ] Write tests
  • [ ] Enrich parser
  • [ ] Pass tests
#Notes

#Guarantee tail call optimization

This will probably need to be done with a trampoline or something

#Add abilities to bind Rust types to scheme

We want to have native types that are easy to manipulate. The proof of concept/motivating example will be adding a Rope-based structure to deal with long strings.

#Make a compiler

R7 will start as an interpreter only