Interp - an Interpreted Programming Language Pt.10 - REPL and Comments
Hey there! It’s Pt. 10 and in this one we create a command line interface. Also, comments and multilines.
RustyLine
Add rustyline (found here) to your dependencies.
Cargo.toml:
[dependencies]
...
rustyline = "10.0.0"
VM
Make the functions expr_to_value and value_repr public since we are going to use them from main.
src/vm/mod.rs:
pub fn expr_to_value(vm: &mut VM, expr: &Expr) -> value::Value {
...
pub fn value_repr(val: value::Value) -> String {
...
Main
Multilines and comments
Add support for multilines and comments.
src/main.rs:
...
use std::fs;
use structopt::StructOpt;
fn main() {
let opt = opt::Opt::from_args();
let mut vm = vm::init_vm();
match opt.source_file {
Some(source_file) => {
// We read the whole file before parsing
match fs::read_to_string(&source_file) {
Ok(text) => {
let mut line_buffer = String::new();
for (line_nr, mut line_str) in text.lines().enumerate() {
if let Some(i) = line_str.find("#") {
line_str = &line_str[0..i];
}
// Multi-line "lines"
if line_str.trim_end().ends_with("\\") {
line_buffer.push_str(&line_str[0..line_str.rfind("\\").unwrap()]);
} else {
line_buffer.push_str(&line_str);
let parsed_line = parser::parse_line(
&line_buffer,
&source_file,
line_nr
);
if let Ok(parsed_line) = parsed_line {
vm::exec_line(&mut vm, &parsed_line);
}
line_buffer.clear();
}
}
}
Err(err) => {
err::throw(err::Err::FileError { file: source_file, message: err.to_string() });
}
}
REPL
Implement REPL with rustyline.
None => {
let mut rl = rustyline::Editor::<()>::new().unwrap();
for line_nr in 0.. {
let line_str = rl.readline("> ");
match &line_str {
Ok(line_str) => {
rl.add_history_entry(line_str);
let parsed_line = parser::parse_line(
line_str,
"<stdin>",
line_nr
);
if let Ok(parsed_line) = parsed_line {
// If a line contains only an Expr and we are not inside a scope
// We will simply print the repr
if vm.scope == 0 {
if let parser::line::LineType::Expr(expr) = &parsed_line.type_ {
let value = vm::expr_to_value(&mut vm, expr);
println!("{}", vm::value_repr(value));
} else {
vm::exec_line(&mut vm, &parsed_line);
}
} else {
vm::exec_line(&mut vm, &parsed_line);
}
}
}
Err(_) => break,
}
}
}
...
Source Code
Source code for this part can be found here.