Skip to content

Commit

Permalink
Parse all expressions per line nicely!
Browse files Browse the repository at this point in the history
  • Loading branch information
WilliamRagstad committed Oct 31, 2024
1 parent c0f1926 commit 122529b
Showing 1 changed file with 52 additions and 17 deletions.
69 changes: 52 additions & 17 deletions src/commands/repl.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use std::io::Write;
use std::io::{Read, Write};

use clap::{ArgMatches, Command};
use colorful::Colorful;
use lento_core::{
interpreter::{environment::global_env, interpreter::interpret_ast, value::Value},
lexer::readers::stdin::StdinReader,
parser::parser,
type_checker::types::GetType,
};
Expand All @@ -22,29 +21,65 @@ Interactive mode, exit using Ctrl+C",
LANG_TITLE = "language".bold(),
LANG_VERSION = lento_core::LANG_VERSION.yellow()
);
let mut parser = parser::from_stdin();
parser.lexer().set_buffer_size(1);
let mut parser = parser::from_stream(StdinLinesReader::default(), "stdin");
// Force the parsing to stop after the first EOF token
// and not try to read more tokens from the reader,
// this prevents the parser to infinitely wait for more input.
parser.lexer().set_try_read_after_eof(false);
// Force the lexer to read only once from the reader,
// this prevents another prompt appearing after the
// user has entered an expression.
parser.lexer().set_read_only_once(true);
let mut env = global_env();
loop {
print!("> ");
std::io::stdout().flush().unwrap();
match parser.parse_one() {
Ok(ast) => match interpret_ast(&ast, &mut env) {
Ok(value) => {
if value != Value::Unit {
println!("{}", value.print_color());
println!(
"{} {}",
"type:".dark_gray(),
value.get_type().to_string().dark_gray()
);
match parser.parse_all() {
Ok(asts) => {
'exprs: for (i, ast) in asts.iter().enumerate() {
match interpret_ast(ast, &mut env) {
Ok(value) => {
if i == asts.len() - 1 && value != Value::Unit {
println!("{}", value.print_color());
println!(
"{} {}",
"type:".dark_gray(),
value.get_type().to_string().dark_gray()
);
}
}
Err(err) => {
print_error(err.message);
break 'exprs; // Stop on error
}
}
}
Err(err) => print_error(err.message),
},
}
Err(err) => print_error(err.message),
}
// Instead of creating a new parser, lexer, and reader, we simply reset them to save memory
parser.lexer().reset(StdinReader::default());
parser.lexer().reset();
}
}

/// A reader that reads lines from stdin.
/// A whole line is read at a time and then returned in chunks for the parser to consume
/// all expressions together until no more is left.
#[derive(Default)]
struct StdinLinesReader {
buffer: String,
}

impl Read for StdinLinesReader {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
if self.buffer.is_empty() {
std::io::stdin().read_line(&mut self.buffer)?;
self.buffer = self.buffer.trim().to_string();
}
let bytes = self.buffer.as_bytes();
let len = buf.len().min(bytes.len());
buf[..len].copy_from_slice(&bytes[..len]);
self.buffer = self.buffer[len..].to_string();
Ok(len)
}
}

0 comments on commit 122529b

Please sign in to comment.