use std::fs;
use std::path::{Path, PathBuf};
use argh::FromArgs;
use parser::{visiting::VisitorsMut, ASTNode};
use parser::{Expression, Module, Statement};
use crate::reporting::report_diagnostics_to_cli;
use crate::utilities::print_to_cli;
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "repl")]
pub(crate) struct ReplArguments {
#[argh(switch)]
const_as_let: bool,
#[argh(option, short = 'd')]
type_definition_module: Option<PathBuf>,
}
#[allow(unused)]
fn file_system_resolver(path: &Path) -> Option<Vec<u8>> {
if path.to_str() == Some("BLANK") {
Some(Vec::new())
} else {
match fs::read_to_string(path) {
Ok(source) => Some(source.into()),
Err(_) => None,
}
}
}
pub(crate) fn run_repl<U: crate::CLIInputResolver>(
cli_input_resolver: U,
ReplArguments { const_as_let, type_definition_module }: ReplArguments,
) {
print_to_cli(format_args!("Entering REPL. Exit with `close()`"));
let definitions = if let Some(tdm) = type_definition_module {
std::iter::once(tdm).collect()
} else {
std::iter::once(checker::INTERNAL_DEFINITION_FILE_PATH.into()).collect()
};
let state = checker::synthesis::interactive::State::new(&file_system_resolver, definitions);
let mut state = match state {
Ok(state) => state,
Err((diagnostics, fs)) => {
report_diagnostics_to_cli(
diagnostics,
&fs,
false,
crate::utilities::MaxDiagnostics::All,
)
.unwrap();
return;
}
};
let source = state.get_source_id();
loop {
let input = cli_input_resolver("");
let input = if let Some(input) = input {
if input.is_empty() {
continue;
} else if input.trim() == "close()" {
break;
}
input
} else {
continue;
};
let (from_index, _) = state.get_fs_mut().append_to_file(source, &input);
let options = Default::default();
let offset = Some(from_index as u32);
let result = if input.trim_start().starts_with('{') {
Expression::from_string_with_options(input, options, offset).map(|(expression, _)| {
Module {
hashbang_comment: None,
span: expression.get_position(),
items: vec![Statement::Expression(expression.into()).into()],
}
})
} else {
Module::from_string(input, options)
};
let mut item = match result {
Ok(item) => item,
Err(err) => {
report_diagnostics_to_cli(
std::iter::once((err, source).into()),
state.get_fs_ref(),
false,
crate::utilities::MaxDiagnostics::All,
)
.unwrap();
continue;
}
};
if const_as_let {
item.visit_mut(
&mut VisitorsMut {
statement_visitors_mut: vec![Box::new(crate::transformers::ConstToLet)],
..Default::default()
},
&mut (),
&Default::default(),
source,
);
}
let result = state.check_item(&item);
match result {
Ok((last_ty, diagnostics)) => {
report_diagnostics_to_cli(
diagnostics,
state.get_fs_ref(),
false,
crate::utilities::MaxDiagnostics::All,
)
.unwrap();
if let Some(last_ty) = last_ty {
println!("{last_ty}");
}
}
Err(diagnostics) => {
report_diagnostics_to_cli(
diagnostics,
state.get_fs_ref(),
false,
crate::utilities::MaxDiagnostics::All,
)
.unwrap();
}
}
}
}