Files
lysp/src/read.rs
T

262 lines
7.2 KiB
Rust

use std::{
borrow::Cow,
io::{BufRead, Write, stdin, stdout},
rc::Rc,
};
use crate::{
compile::{
Compile, CompileContext, CompileOptions,
syntax::{Expression, FunctionBody, ParseError},
},
error::{MachineError, MachineErrorAt, ReadError},
parse::{self, parse_value},
util::Either,
vm::{
env::Environment,
instruction::Instruction,
machine::Machine,
value::{BytecodeFunction, IdentifierValue, Value},
},
};
pub trait Reader {
type Error: Into<MachineErrorAt>;
fn read(&mut self) -> Result<Option<Value>, Self::Error>;
}
pub struct InteractiveReader {
buffer: String,
prompt_empty: Cow<'static, str>,
prompt_continuation: Cow<'static, str>,
}
pub struct FileReader<R: BufRead> {
reader: R,
buffer: String,
}
pub struct ModuleReader<R: BufRead> {
reader: FileReader<R>,
macro_machine: Machine,
}
impl InteractiveReader {
pub fn new<T: Into<Cow<'static, str>>, U: Into<Cow<'static, str>>>(
prompt_empty: T,
prompt_continuation: U,
) -> Self {
Self {
buffer: String::new(),
prompt_empty: prompt_empty.into(),
prompt_continuation: prompt_continuation.into(),
}
}
pub fn reset(&mut self) {
self.buffer.clear();
}
}
impl Reader for InteractiveReader {
type Error = MachineErrorAt;
fn read(&mut self) -> Result<Option<Value>, Self::Error> {
let stdin = stdin();
read_inner(
&mut stdin.lock(),
&mut self.buffer,
Some((
self.prompt_empty.as_ref(),
self.prompt_continuation.as_ref(),
)),
)
}
}
impl<R: BufRead> FileReader<R> {
pub fn new(reader: R) -> Self {
Self {
buffer: String::new(),
reader,
}
}
}
impl<R: BufRead> Reader for FileReader<R> {
type Error = MachineErrorAt;
fn read(&mut self) -> Result<Option<Value>, Self::Error> {
read_inner(&mut self.reader, &mut self.buffer, None)
}
}
impl<R: BufRead> ModuleReader<R> {
pub fn new(reader: R, trace_macros: bool) -> Self {
let mut macro_machine = Machine::default();
macro_machine.trace_macros = trace_macros;
Self {
reader: FileReader::new(reader),
macro_machine,
}
}
pub fn read_expression(
&mut self,
options: &CompileOptions,
env: &Rc<Environment>,
) -> Result<Option<Rc<Expression>>, Either<MachineErrorAt, Vec<ParseError>>> {
loop {
let value =
read(&mut self.reader, &mut self.macro_machine, env).map_err(Either::Left)?;
let Some(value) = value else {
return Ok(None);
};
let expression = Expression::parse(&value).map_err(Either::Right)?;
if let Expression::Defmacro(_) = expression.as_ref() {
self.macro_machine
.evaluate_value(options.clone(), Some("defmacro".into()), env, value)
.map_err(Either::Left)?;
continue;
}
return Ok(Some(expression));
}
}
pub fn compile(
mut self,
module_name: Option<IdentifierValue>,
options: &CompileOptions,
env: &Rc<Environment>,
) -> Result<Rc<BytecodeFunction>, Either<MachineErrorAt, Vec<ParseError>>> {
let mut cx = CompileContext::new(options.clone(), module_name);
let mut body = FunctionBody {
head: vec![],
tail: Rc::new(Expression::Nil),
};
let mut syntax_errors = vec![];
loop {
let expression = match self.read_expression(options, env) {
Ok(Some(expression)) => expression,
Ok(None) => break,
Err(Either::Left(error)) => return Err(Either::Left(error)),
Err(Either::Right(errors)) => {
syntax_errors.extend(errors);
continue;
}
};
body.head.push(expression);
}
if !syntax_errors.is_empty() {
return Err(Either::Right(syntax_errors));
}
let value = body
.compile(&mut cx)
.map_err(MachineError::Compile)
.map_err(MachineErrorAt::at_unknown)
.map_err(Either::Left)?;
cx.push(value)
.map_err(MachineError::Compile)
.map_err(MachineErrorAt::at_unknown)
.map_err(Either::Left)?;
cx.emit(Instruction::Return);
let function = cx
.to_bytecode()
.map_err(MachineError::Compile)
.map_err(MachineErrorAt::at_unknown)
.map_err(Either::Left)?;
Ok(function)
}
}
fn read_inner<R: BufRead>(
reader: &mut R,
buffer: &mut String,
prompt: Option<(&str, &str)>,
) -> Result<Option<Value>, MachineErrorAt> {
loop {
let mut incomplete = None;
let mut i = buffer.trim_start();
while !i.is_empty() {
i = match parse::skip_comment_and_whitespace(i) {
Ok((i, _)) => i,
Err(_error) => {
buffer.clear();
i = buffer.trim_start();
continue;
}
};
if i.is_empty() {
buffer.clear();
break;
}
let result = parse_value(i);
let (tail, value) = match result {
Ok(r) => r,
Err(nom::Err::Incomplete(error)) => {
incomplete = Some(error);
break;
}
Err(error) => {
let error = ReadError::Lexical(error.map_input(|i| i.into()));
let error = MachineError::Read(error);
buffer.clear();
return Err(error.at_unknown());
}
};
*buffer = tail.trim_start().into();
return Ok(Some(value));
}
*buffer = buffer.trim_start().into();
if let Some((prompt_empty, prompt_continuation)) = prompt {
if buffer.is_empty() {
print!("{prompt_empty}");
} else {
print!("{prompt_continuation}");
}
stdout().flush().ok();
}
let len = reader
.read_line(buffer)
.map_err(ReadError::Io)
.map_err(MachineError::Read)
.map_err(MachineErrorAt::at_unknown)?;
if len == 0 {
return if let Some(incomplete) = incomplete {
let error = ReadError::Lexical(nom::Err::Incomplete(incomplete));
let error = MachineError::Read(error);
Err(error.at_unknown())
} else {
assert!(buffer.is_empty());
Ok(None)
};
}
}
}
pub fn read<R: Reader>(
reader: &mut R,
vm: &mut Machine,
env: &Rc<Environment>,
) -> Result<Option<Value>, MachineErrorAt> {
let raw_value = reader.read().map_err(Into::into)?;
let Some(raw_value) = raw_value else {
return Ok(None);
};
let exp_value = vm.macro_expand(env, &raw_value)?;
Ok(Some(exp_value))
}