mirror of
https://github.com/roc-lang/roc.git
synced 2024-07-14 22:00:24 +03:00
Support importing local files in the REPL
This commit is contained in:
parent
e500d664fd
commit
52f84910a7
@ -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)]
|
||||
|
@ -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}");
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user