mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 11:52:19 +00:00
Support importing local files in the REPL
This commit is contained in:
parent
e500d664fd
commit
52f84910a7
5 changed files with 57 additions and 10 deletions
|
@ -163,6 +163,8 @@ impl<'a> From<ModuleName<'a>> for roc_module::ident::ModuleName {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ModuleName<'a> {
|
impl<'a> ModuleName<'a> {
|
||||||
|
const MODULE_SEPARATOR: char = '.';
|
||||||
|
|
||||||
pub const fn new(name: &'a str) -> Self {
|
pub const fn new(name: &'a str) -> Self {
|
||||||
ModuleName(name)
|
ModuleName(name)
|
||||||
}
|
}
|
||||||
|
@ -170,6 +172,10 @@ impl<'a> ModuleName<'a> {
|
||||||
pub const fn as_str(&'a self) -> &'a str {
|
pub const fn as_str(&'a self) -> &'a str {
|
||||||
self.0
|
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)]
|
#[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::colors::{CYAN, END_COL};
|
||||||
use roc_repl_ui::repl_state::{ReplAction, ReplState};
|
use roc_repl_ui::repl_state::{ReplAction, ReplState};
|
||||||
use roc_repl_ui::{format_output, is_incomplete, CONT_PROMPT, PROMPT, SHORT_INSTRUCTIONS, TIPS};
|
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 roc_target::Target;
|
||||||
use rustyline::highlight::{Highlighter, PromptInfo};
|
use rustyline::highlight::{Highlighter, PromptInfo};
|
||||||
use rustyline::validate::{self, ValidationContext, ValidationResult, Validator};
|
use rustyline::validate::{self, ValidationContext, ValidationResult, Validator};
|
||||||
|
@ -74,6 +74,9 @@ pub fn main() -> i32 {
|
||||||
ReplAction::Exit => {
|
ReplAction::Exit => {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
ReplAction::FileProblem { filename, error } => {
|
||||||
|
println!("{}", to_file_problem_report_string(filename, error));
|
||||||
|
}
|
||||||
ReplAction::Help => {
|
ReplAction::Help => {
|
||||||
println!("{TIPS}");
|
println!("{TIPS}");
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ pub fn compile_to_mono<'a, 'i, I: Iterator<Item = &'i str>>(
|
||||||
palette: Palette,
|
palette: Palette,
|
||||||
) -> (Option<MonomorphizedModule<'a>>, Problems) {
|
) -> (Option<MonomorphizedModule<'a>>, Problems) {
|
||||||
let filename = PathBuf::from("replfile.roc");
|
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 (bytes_before_expr, module_src) = promote_expr_to_module(arena, defs, expr);
|
||||||
let loaded = roc_load::load_and_monomorphize_from_str(
|
let loaded = roc_load::load_and_monomorphize_from_str(
|
||||||
arena,
|
arena,
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::{fs, io};
|
||||||
|
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_collections::MutSet;
|
use roc_collections::MutSet;
|
||||||
use roc_load::MonomorphizedModule;
|
use roc_load::MonomorphizedModule;
|
||||||
|
@ -14,9 +17,9 @@ use roc_reporting::report::Palette;
|
||||||
use roc_target::Target;
|
use roc_target::Target;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
struct PastDef {
|
enum PastDef {
|
||||||
ident: String,
|
Def { ident: String, src: String },
|
||||||
src: String,
|
Import(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ReplState {
|
pub struct ReplState {
|
||||||
|
@ -39,6 +42,10 @@ pub enum ReplAction<'a> {
|
||||||
},
|
},
|
||||||
Exit,
|
Exit,
|
||||||
Help,
|
Help,
|
||||||
|
FileProblem {
|
||||||
|
filename: PathBuf,
|
||||||
|
error: io::ErrorKind,
|
||||||
|
},
|
||||||
Nothing,
|
Nothing,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,9 +141,34 @@ impl ReplState {
|
||||||
ValueDef::ExpectFx { .. } => {
|
ValueDef::ExpectFx { .. } => {
|
||||||
todo!("handle receiving an `expect-fx` - what should the repl do for that?")
|
todo!("handle receiving an `expect-fx` - what should the repl do for that?")
|
||||||
}
|
}
|
||||||
ValueDef::ModuleImport(_) => {
|
ValueDef::ModuleImport(import) => match import.name.value.package {
|
||||||
todo!("handle importing a module from the REPL")
|
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(_) => {
|
ValueDef::IngestedFileImport(_) => {
|
||||||
todo!("handle ingesting a file from the REPL")
|
todo!("handle ingesting a file from the REPL")
|
||||||
}
|
}
|
||||||
|
@ -178,7 +210,10 @@ impl ReplState {
|
||||||
|
|
||||||
let (opt_mono, problems) = compile_to_mono(
|
let (opt_mono, problems) = compile_to_mono(
|
||||||
arena,
|
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,
|
src,
|
||||||
target,
|
target,
|
||||||
palette,
|
palette,
|
||||||
|
@ -196,7 +231,7 @@ impl ReplState {
|
||||||
|
|
||||||
existing_idents.insert(ident.clone());
|
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 => {
|
ReplAction::Exit => {
|
||||||
"To exit the web version of the REPL, just close the browser tab!".to_string()
|
"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::Nothing => String::new(),
|
||||||
ReplAction::Eval { opt_mono, problems } => {
|
ReplAction::Eval { opt_mono, problems } => {
|
||||||
let opt_output = match opt_mono {
|
let opt_output = match opt_mono {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue