Skip to content

Commit 837cfa5

Browse files
author
Jason P. Barmparesos
committed
Basic REPL.
1 parent 22d6067 commit 837cfa5

File tree

6 files changed

+110
-45
lines changed

6 files changed

+110
-45
lines changed

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
2-
name = "rlisp"
3-
version = "0.1.0"
2+
name = "rscheme"
3+
version = "0.0.1"
44
authors = ["Jason P. Barmparesos <[email protected]>"]
55

66
[dependencies]

README.md

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
1-
# rlisp
2-
A simple Lisp interpreter written in Rust.
3-
4-
## What dialect of Lisp does it recognize?
5-
This interpreter does not adhere to any specific Lisp-like specification. Nevertheless, its syntax closely resembles a
6-
simplified version of the Scheme variant.
1+
# rscheme
2+
A simple Scheme interpreter written in Rust.
73

84
## Why?
95
Why not? In all seriousness, this project is not destined to be a commercial intepreter. Instead it aims to be a
@@ -12,3 +8,15 @@ simple and modifiable piece of software to assist the teaching of compiler/inter
128
## How can I try it?
139
Just clone the sources and type `cargo run` inside the repository folder. By default, the interpreter reads and executes
1410
`test-code.scm` but changing that should be trivial (simply edit `src/main.rs`).
11+
12+
## Features
13+
- [x] Basic arithmetic operations.
14+
- [x] Variables.
15+
- [x] Lambda expressions.
16+
- [x] Recursion.
17+
- [ ] Scheme function declaration syntax.
18+
- [ ] REPL prompt.
19+
- [ ] `display` procedure.
20+
- [ ] Lists.
21+
- [ ] String manipulation procedures.
22+
- [ ] Foreign function calls.

src/expression.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,18 @@ impl fmt::Display for Procedure {
4343
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
4444
match *self {
4545
Procedure::UserDefined { arguments: _, body: _ } => {
46-
write!(f, "#procedure:user-defined")
46+
write!(f, "#<procedure>:user-defined")
4747
}
48-
Procedure::Sum => write!(f, "#procedure:+"),
49-
Procedure::Difference => write!(f, "#procedure:-"),
50-
Procedure::Product => write!(f, "#procedure:*"),
51-
Procedure::Division => write!(f, "#procedure:/"),
52-
Procedure::Equal => write!(f, "#procedure:="),
53-
Procedure::Less => write!(f, "#procedure:<"),
54-
Procedure::Greater => write!(f, "#procedure:>"),
55-
Procedure::And => write!(f, "#procedure:and"),
56-
Procedure::Or => write!(f, "#procedure:or"),
57-
Procedure::Not => write!(f, "#procedure:not"),
48+
Procedure::Sum => write!(f, "#<procedure>:+"),
49+
Procedure::Difference => write!(f, "#<procedure>:-"),
50+
Procedure::Product => write!(f, "#<procedure>:*"),
51+
Procedure::Division => write!(f, "#<procedure>:/"),
52+
Procedure::Equal => write!(f, "#<procedure>:="),
53+
Procedure::Less => write!(f, "#<procedure>:<"),
54+
Procedure::Greater => write!(f, "#<procedure>:>"),
55+
Procedure::And => write!(f, "#<procedure>:and"),
56+
Procedure::Or => write!(f, "#<procedure>:or"),
57+
Procedure::Not => write!(f, "#<procedure>:not"),
5858
}
5959
}
6060
}
@@ -71,7 +71,7 @@ impl fmt::Display for LResult {
7171
match *self {
7272
LResult::Value(ref v) => write!(f, "{}", v),
7373
LResult::Procedure(ref p) => write!(f, "{}", p),
74-
LResult::Undefined => write!(f, "#undefined"),
74+
LResult::Undefined => write!(f, "#<undefined>"),
7575
}
7676
}
7777
}

src/main.rs

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,52 @@ mod program;
66

77
use std::fs::File;
88
use std::io::prelude::*;
9-
use list::*;
9+
use std::io;
10+
use std::env;
1011
use program::Program;
1112

13+
fn get_file_list() -> Vec<String> {
14+
let mut args = env::args();
15+
args.next(); // Skip the program name.
16+
let mut files:Vec<String> = Vec::new();
17+
for arg in args {
18+
files.push(arg.clone());
19+
}
20+
files
21+
}
22+
1223
fn main() {
13-
let mut source_file = File::open("test-code.scm").unwrap();
14-
let mut code = String::new();
15-
source_file.read_to_string(&mut code).unwrap();
16-
let tokens = parser::parse_primitives(&code);
17-
let mut token_iter = tokens.into_iter();
18-
let list_tree = ListNode::from_primitive_tokens(&mut token_iter);
24+
println!("rScheme - A minimal Scheme intepreter written in Rust (v0.0.1 Alpha)");
25+
println!("Copyright (C) 2016 School of Engineering - Aristotle University of Thessaloniki");
26+
println!("---------------");
27+
println!("Type `exit` to quit the REPL environment. Statements can't span multiple lines.");
28+
println!("Loading the standard library...");
29+
1930
let mut program = Program::new();
20-
program.run(&list_tree);
31+
let mut files = vec!["stdlib.scm".to_string()];
32+
files.append(&mut get_file_list());
33+
for path in files {
34+
match File::open(path.clone()) {
35+
Ok(mut file) => {
36+
let mut code = String::new();
37+
file.read_to_string(&mut code).unwrap();
38+
program.run_code(code, true);
39+
}
40+
Err(_) => println!("Failed to open file {}.", path)
41+
}
42+
}
43+
44+
println!("---------------");
45+
loop {
46+
print!("]=> ");
47+
io::stdout().flush().unwrap();
48+
let mut accum = String::new();
49+
io::stdin().read_line(&mut accum).unwrap();
50+
if accum.trim() == "exit" {
51+
println!("Goodbye!");
52+
break;
53+
}
54+
program.run_code(accum, false);
55+
println!("");
56+
}
2157
}

src/program.rs

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

22
use std::collections::HashMap;
3+
use parser;
34
use list::ListNode;
45
use expression::*;
56
use std::cmp::Ordering;
@@ -10,30 +11,22 @@ pub struct Program {
1011

1112
impl Program {
1213
pub fn new() -> Program {
13-
Program { stack: Vec::new() }
14+
let mut p = Program { stack: Vec::new() };
15+
p.initialize();
16+
p
1417
}
1518

16-
pub fn run(&mut self, root: &ListNode) {
17-
// Add the basic functions.
18-
let mut basic_map: HashMap<String, LResult> = HashMap::new();
19-
basic_map.insert("+".to_string(), LResult::Procedure(Procedure::Sum));
20-
basic_map.insert("-".to_string(), LResult::Procedure(Procedure::Difference));
21-
basic_map.insert("*".to_string(), LResult::Procedure(Procedure::Product));
22-
basic_map.insert("/".to_string(), LResult::Procedure(Procedure::Division));
23-
basic_map.insert("=".to_string(), LResult::Procedure(Procedure::Equal));
24-
basic_map.insert("<".to_string(), LResult::Procedure(Procedure::Less));
25-
basic_map.insert(">".to_string(), LResult::Procedure(Procedure::Greater));
26-
basic_map.insert("and".to_string(), LResult::Procedure(Procedure::And));
27-
basic_map.insert("or".to_string(), LResult::Procedure(Procedure::Or));
28-
basic_map.insert("not".to_string(), LResult::Procedure(Procedure::Not));
29-
self.stack.push(basic_map);
30-
match *root {
19+
pub fn run_code(&mut self, code: String, silent:bool) {
20+
let tokens = parser::parse_primitives(&code);
21+
let mut token_iter = tokens.into_iter();
22+
let list_tree = ListNode::from_primitive_tokens(&mut token_iter);
23+
match list_tree {
3124
ListNode::Node(ref v) => {
3225
for e in v {
3326
match Expression::from_list(e) {
3427
Ok(res) => {
3528
match self.evaluate_expression(&res) {
36-
Ok(result) => println!("{}", result),
29+
Ok(result) => if !silent { println!("{}", result) },
3730
Err(s) => println!("Runtime error: {}", s),
3831
}
3932
}
@@ -48,6 +41,22 @@ impl Program {
4841
}
4942
}
5043

44+
pub fn initialize(&mut self) {
45+
// Add the basic functions.
46+
let mut basic_map: HashMap<String, LResult> = HashMap::new();
47+
basic_map.insert("+".to_string(), LResult::Procedure(Procedure::Sum));
48+
basic_map.insert("-".to_string(), LResult::Procedure(Procedure::Difference));
49+
basic_map.insert("*".to_string(), LResult::Procedure(Procedure::Product));
50+
basic_map.insert("/".to_string(), LResult::Procedure(Procedure::Division));
51+
basic_map.insert("=".to_string(), LResult::Procedure(Procedure::Equal));
52+
basic_map.insert("<".to_string(), LResult::Procedure(Procedure::Less));
53+
basic_map.insert(">".to_string(), LResult::Procedure(Procedure::Greater));
54+
basic_map.insert("and".to_string(), LResult::Procedure(Procedure::And));
55+
basic_map.insert("or".to_string(), LResult::Procedure(Procedure::Or));
56+
basic_map.insert("not".to_string(), LResult::Procedure(Procedure::Not));
57+
self.stack.push(basic_map);
58+
}
59+
5160
fn find_identifier(&self, name: &str) -> Option<&LResult> {
5261
let stack_ref = &self.stack;
5362
for name_stack in stack_ref.into_iter().rev() {

stdlib.scm

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
; rScheme standard library.
2+
3+
(define pi 3.14159)
4+
5+
(define <= (lambda (a b)
6+
(or (< a b) (= a b))))
7+
8+
(define >= (lambda (a b)
9+
(or (> a b) (= a b))))
10+
11+
(define abs (lambda (x)
12+
(if (< x 0) (- x) x)))

0 commit comments

Comments
 (0)