mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
Reorganize repl modules
This commit is contained in:
parent
9f498add60
commit
a6c1667d37
9 changed files with 400 additions and 359 deletions
|
@ -1,28 +1,12 @@
|
|||
mod cli_gen;
|
||||
mod colors;
|
||||
mod repl_state;
|
||||
|
||||
use bumpalo::Bump;
|
||||
use const_format::concatcp;
|
||||
use inkwell::context::Context;
|
||||
use libloading::Library;
|
||||
use repl_state::ReplState;
|
||||
use roc_gen_llvm::llvm::build::LlvmBackendMode;
|
||||
use roc_intern::SingleThreadedInterner;
|
||||
use roc_mono::layout::Layout;
|
||||
use roc_types::subs::Subs;
|
||||
use target_lexicon::Triple;
|
||||
pub mod repl_state;
|
||||
|
||||
use colors::{BLUE, END_COL, PINK};
|
||||
use roc_build::link::llvm_module_to_dylib;
|
||||
use roc_collections::all::MutSet;
|
||||
use roc_gen_llvm::llvm::externs::add_default_roc_externs;
|
||||
use roc_gen_llvm::{run_jit_function, run_jit_function_dynamic_type};
|
||||
use roc_load::{EntryPoint, MonomorphizedModule};
|
||||
use roc_mono::ir::OptLevel;
|
||||
use roc_parse::ast::Expr;
|
||||
use roc_repl_eval::{ReplApp, ReplAppMemory};
|
||||
use roc_std::RocStr;
|
||||
use roc_target::TargetInfo;
|
||||
use const_format::concatcp;
|
||||
use repl_state::ReplState;
|
||||
|
||||
use crate::repl_state::PROMPT;
|
||||
|
||||
pub const WELCOME_MESSAGE: &str = concatcp!(
|
||||
"\n The rockin’ ",
|
||||
|
@ -38,194 +22,7 @@ pub const WELCOME_MESSAGE: &str = concatcp!(
|
|||
|
||||
// For when nothing is entered in the repl
|
||||
// TODO add link to repl tutorial(does not yet exist).
|
||||
pub const SHORT_INSTRUCTIONS: &str = "Enter an expression, or :help, or :q to quit.\n";
|
||||
|
||||
pub const PROMPT: &str = concatcp!("\n", BLUE, "»", END_COL, " ");
|
||||
pub const CONT_PROMPT: &str = concatcp!(BLUE, "…", END_COL, " ");
|
||||
|
||||
struct CliApp {
|
||||
lib: Library,
|
||||
}
|
||||
|
||||
struct CliMemory;
|
||||
|
||||
impl<'a> ReplApp<'a> for CliApp {
|
||||
type Memory = CliMemory;
|
||||
|
||||
/// Run user code that returns a type with a `Builtin` layout
|
||||
/// Size of the return value is statically determined from its Rust type
|
||||
fn call_function<Return, F>(&mut self, main_fn_name: &str, mut transform: F) -> Expr<'a>
|
||||
where
|
||||
F: FnMut(&'a Self::Memory, Return) -> Expr<'a>,
|
||||
Self::Memory: 'a,
|
||||
{
|
||||
run_jit_function!(self.lib, main_fn_name, Return, |v| transform(&CliMemory, v))
|
||||
}
|
||||
|
||||
/// Run user code that returns a struct or union, whose size is provided as an argument
|
||||
fn call_function_dynamic_size<T, F>(
|
||||
&mut self,
|
||||
main_fn_name: &str,
|
||||
ret_bytes: usize,
|
||||
mut transform: F,
|
||||
) -> T
|
||||
where
|
||||
F: FnMut(&'a Self::Memory, usize) -> T,
|
||||
Self::Memory: 'a,
|
||||
{
|
||||
run_jit_function_dynamic_type!(self.lib, main_fn_name, ret_bytes, |v| transform(
|
||||
&CliMemory, v
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! deref_number {
|
||||
($name: ident, $t: ty) => {
|
||||
fn $name(&self, addr: usize) -> $t {
|
||||
let ptr = addr as *const _;
|
||||
unsafe { *ptr }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl ReplAppMemory for CliMemory {
|
||||
deref_number!(deref_bool, bool);
|
||||
|
||||
deref_number!(deref_u8, u8);
|
||||
deref_number!(deref_u16, u16);
|
||||
deref_number!(deref_u32, u32);
|
||||
deref_number!(deref_u64, u64);
|
||||
deref_number!(deref_u128, u128);
|
||||
deref_number!(deref_usize, usize);
|
||||
|
||||
deref_number!(deref_i8, i8);
|
||||
deref_number!(deref_i16, i16);
|
||||
deref_number!(deref_i32, i32);
|
||||
deref_number!(deref_i64, i64);
|
||||
deref_number!(deref_i128, i128);
|
||||
deref_number!(deref_isize, isize);
|
||||
|
||||
deref_number!(deref_f32, f32);
|
||||
deref_number!(deref_f64, f64);
|
||||
|
||||
fn deref_str(&self, addr: usize) -> &str {
|
||||
let reference: &RocStr = unsafe { std::mem::transmute(addr) };
|
||||
reference.as_str()
|
||||
}
|
||||
|
||||
fn deref_pointer_with_tag_id(&self, addr: usize) -> (u16, u64) {
|
||||
let addr_with_id = self.deref_usize(addr);
|
||||
let tag_id_mask = 0b111;
|
||||
|
||||
let tag_id = addr_with_id & tag_id_mask;
|
||||
let data_addr = addr_with_id & !tag_id_mask;
|
||||
(tag_id as _, data_addr as _)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mono_module_to_dylib<'a>(
|
||||
arena: &'a Bump,
|
||||
target: Triple,
|
||||
loaded: MonomorphizedModule<'a>,
|
||||
opt_level: OptLevel,
|
||||
) -> Result<
|
||||
(
|
||||
libloading::Library,
|
||||
&'a str,
|
||||
Subs,
|
||||
SingleThreadedInterner<'a, Layout<'a>>,
|
||||
),
|
||||
libloading::Error,
|
||||
> {
|
||||
let target_info = TargetInfo::from(&target);
|
||||
|
||||
let MonomorphizedModule {
|
||||
procedures,
|
||||
entry_point,
|
||||
interns,
|
||||
subs,
|
||||
layout_interner,
|
||||
..
|
||||
} = loaded;
|
||||
|
||||
let context = Context::create();
|
||||
let builder = context.create_builder();
|
||||
let module = arena.alloc(roc_gen_llvm::llvm::build::module_from_builtins(
|
||||
&target, &context, "",
|
||||
));
|
||||
|
||||
let module = arena.alloc(module);
|
||||
let (module_pass, function_pass) =
|
||||
roc_gen_llvm::llvm::build::construct_optimization_passes(module, opt_level);
|
||||
|
||||
let (dibuilder, compile_unit) = roc_gen_llvm::llvm::build::Env::new_debug_info(module);
|
||||
|
||||
// Compile and add all the Procs before adding main
|
||||
let env = roc_gen_llvm::llvm::build::Env {
|
||||
arena,
|
||||
layout_interner: &layout_interner,
|
||||
builder: &builder,
|
||||
dibuilder: &dibuilder,
|
||||
compile_unit: &compile_unit,
|
||||
context: &context,
|
||||
interns,
|
||||
module,
|
||||
target_info,
|
||||
mode: LlvmBackendMode::GenTest, // so roc_panic is generated
|
||||
// important! we don't want any procedures to get the C calling convention
|
||||
exposed_to_host: MutSet::default(),
|
||||
};
|
||||
|
||||
// Add roc_alloc, roc_realloc, and roc_dealloc, since the repl has no
|
||||
// platform to provide them.
|
||||
add_default_roc_externs(&env);
|
||||
|
||||
let entry_point = match entry_point {
|
||||
EntryPoint::Executable { symbol, layout, .. } => {
|
||||
roc_mono::ir::EntryPoint { symbol, layout }
|
||||
}
|
||||
EntryPoint::Test => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
let (main_fn_name, main_fn) = roc_gen_llvm::llvm::build::build_procedures_return_main(
|
||||
&env,
|
||||
opt_level,
|
||||
procedures,
|
||||
entry_point,
|
||||
);
|
||||
|
||||
env.dibuilder.finalize();
|
||||
|
||||
// we don't use the debug info, and it causes weird errors.
|
||||
module.strip_debug_info();
|
||||
|
||||
// Uncomment this to see the module's un-optimized LLVM instruction output:
|
||||
// env.module.print_to_stderr();
|
||||
|
||||
if main_fn.verify(true) {
|
||||
function_pass.run_on(&main_fn);
|
||||
} else {
|
||||
panic!("Main function {} failed LLVM verification in build. Uncomment things nearby to see more details.", main_fn_name);
|
||||
}
|
||||
|
||||
module_pass.run_on(env.module);
|
||||
|
||||
// Uncomment this to see the module's optimized LLVM instruction output:
|
||||
// env.module.print_to_stderr();
|
||||
|
||||
// Verify the module
|
||||
if let Err(errors) = env.module.verify() {
|
||||
panic!(
|
||||
"Errors defining module:\n{}\n\nUncomment things nearby to see more details.",
|
||||
errors.to_string()
|
||||
);
|
||||
}
|
||||
|
||||
llvm_module_to_dylib(env.module, &target, opt_level)
|
||||
.map(|lib| (lib, main_fn_name, subs, layout_interner))
|
||||
}
|
||||
const SHORT_INSTRUCTIONS: &str = "Enter an expression, or :help, or :q to quit.\n";
|
||||
|
||||
pub fn main() -> i32 {
|
||||
use rustyline::error::ReadlineError;
|
||||
|
@ -250,11 +47,13 @@ pub fn main() -> i32 {
|
|||
|
||||
let repl_helper = editor.helper_mut().expect("Editor helper was not set");
|
||||
|
||||
dbg!(&editor);
|
||||
|
||||
match step_repl_state(repl_helper, trim_line) {
|
||||
match repl_helper.step(trim_line) {
|
||||
Ok(output) => {
|
||||
print!("{}", output);
|
||||
// If there was no output, don't print a blank line!
|
||||
// (This happens for something like a type annotation.)
|
||||
if !output.is_empty() {
|
||||
println!("{}", output);
|
||||
}
|
||||
}
|
||||
Err(exit_code) => return exit_code,
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue