Support importing local files in the REPL

This commit is contained in:
Agus Zubiaga 2024-04-26 23:33:14 -03:00
parent e500d664fd
commit 52f84910a7
No known key found for this signature in database
5 changed files with 57 additions and 10 deletions

View File

@ -163,6 +163,8 @@ impl<'a> From<ModuleName<'a>> for roc_module::ident::ModuleName {
}
impl<'a> ModuleName<'a> {
const MODULE_SEPARATOR: char = '.';
pub const fn new(name: &'a str) -> Self {
ModuleName(name)
}
@ -170,6 +172,10 @@ impl<'a> ModuleName<'a> {
pub const fn as_str(&'a self) -> &'a str {
self.0
}
pub fn parts(&'a self) -> impl DoubleEndedIterator<Item = &'a str> {
self.0.split(Self::MODULE_SEPARATOR)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]

View File

@ -9,7 +9,7 @@ use roc_repl_eval::gen::Problems;
use roc_repl_ui::colors::{CYAN, END_COL};
use roc_repl_ui::repl_state::{ReplAction, ReplState};
use roc_repl_ui::{format_output, is_incomplete, CONT_PROMPT, PROMPT, SHORT_INSTRUCTIONS, TIPS};
use roc_reporting::report::{ANSI_STYLE_CODES, DEFAULT_PALETTE};
use roc_reporting::report::{to_file_problem_report_string, ANSI_STYLE_CODES, DEFAULT_PALETTE};
use roc_target::Target;
use rustyline::highlight::{Highlighter, PromptInfo};
use rustyline::validate::{self, ValidationContext, ValidationResult, Validator};
@ -74,6 +74,9 @@ pub fn main() -> i32 {
ReplAction::Exit => {
return 0;
}
ReplAction::FileProblem { filename, error } => {
println!("{}", to_file_problem_report_string(filename, error));
}
ReplAction::Help => {
println!("{TIPS}");
}

View File

@ -53,7 +53,7 @@ pub fn compile_to_mono<'a, 'i, I: Iterator<Item = &'i str>>(
palette: Palette,
) -> (Option<MonomorphizedModule<'a>>, Problems) {
let filename = PathBuf::from("replfile.roc");
let src_dir = PathBuf::from("fake/test/path");
let src_dir = PathBuf::from(".");
let (bytes_before_expr, module_src) = promote_expr_to_module(arena, defs, expr);
let loaded = roc_load::load_and_monomorphize_from_str(
arena,

View File

@ -1,3 +1,6 @@
use std::path::PathBuf;
use std::{fs, io};
use bumpalo::Bump;
use roc_collections::MutSet;
use roc_load::MonomorphizedModule;
@ -14,9 +17,9 @@ use roc_reporting::report::Palette;
use roc_target::Target;
#[derive(Debug, Clone, PartialEq)]
struct PastDef {
ident: String,
src: String,
enum PastDef {
Def { ident: String, src: String },
Import(String),
}
pub struct ReplState {
@ -39,6 +42,10 @@ pub enum ReplAction<'a> {
},
Exit,
Help,
FileProblem {
filename: PathBuf,
error: io::ErrorKind,
},
Nothing,
}
@ -134,9 +141,34 @@ impl ReplState {
ValueDef::ExpectFx { .. } => {
todo!("handle receiving an `expect-fx` - what should the repl do for that?")
}
ValueDef::ModuleImport(_) => {
todo!("handle importing a module from the REPL")
}
ValueDef::ModuleImport(import) => match import.name.value.package {
Some(_) => {
todo!("handle importing a module from a package")
}
None => {
let mut filename = PathBuf::new();
for part in import.name.value.name.parts() {
filename.push(part);
}
filename.set_extension("roc");
// Check we can read the file before we add it to past defs.
// If we didn't do this, the bad import would remain in past_defs
// and we'd report it on every subsequent evaluation.
if let Err(err) = fs::metadata(&filename) {
return ReplAction::FileProblem {
filename,
error: err.kind(),
};
}
self.past_defs.push(PastDef::Import(line.to_string()));
return ReplAction::Nothing;
}
},
ValueDef::IngestedFileImport(_) => {
todo!("handle ingesting a file from the REPL")
}
@ -178,7 +210,10 @@ impl ReplState {
let (opt_mono, problems) = compile_to_mono(
arena,
self.past_defs.iter().map(|def| def.src.as_str()),
self.past_defs.iter().map(|past_def| match past_def {
PastDef::Def { ident: _, src } => src.as_str(),
PastDef::Import(src) => src.as_str(),
}),
src,
target,
palette,
@ -196,7 +231,7 @@ impl ReplState {
existing_idents.insert(ident.clone());
self.past_defs.push(PastDef { ident, src });
self.past_defs.push(PastDef::Def { ident, src });
}
}

View File

@ -203,6 +203,9 @@ pub async fn entrypoint_from_js(src: String) -> String {
ReplAction::Exit => {
"To exit the web version of the REPL, just close the browser tab!".to_string()
}
ReplAction::FileProblem { .. } => {
"The web version of the REPL cannot import files... for now!".to_string()
}
ReplAction::Nothing => String::new(),
ReplAction::Eval { opt_mono, problems } => {
let opt_output = match opt_mono {