First pass at loading modules from cli

This commit is contained in:
Richard Feldman 2020-04-11 23:18:34 -04:00
parent 62186fdda4
commit 9ca754b8fd
4 changed files with 86 additions and 54 deletions

2
Cargo.lock generated
View file

@ -871,6 +871,7 @@ dependencies = [
"roc_collections", "roc_collections",
"roc_constrain", "roc_constrain",
"roc_gen", "roc_gen",
"roc_load",
"roc_module", "roc_module",
"roc_mono", "roc_mono",
"roc_parse", "roc_parse",
@ -882,6 +883,7 @@ dependencies = [
"roc_unify", "roc_unify",
"roc_uniq", "roc_uniq",
"target-lexicon", "target-lexicon",
"tokio",
] ]
[[package]] [[package]]

View file

@ -31,12 +31,14 @@ roc_uniq = { path = "../compiler/uniq" }
roc_unify = { path = "../compiler/unify" } roc_unify = { path = "../compiler/unify" }
roc_solve = { path = "../compiler/solve" } roc_solve = { path = "../compiler/solve" }
roc_mono = { path = "../compiler/mono" } roc_mono = { path = "../compiler/mono" }
roc_load = { path = "../compiler/load", version = "0.1.0" }
roc_gen = { path = "../compiler/gen", version = "0.1.0" } roc_gen = { path = "../compiler/gen", version = "0.1.0" }
roc_reporting = { path = "../compiler/reporting", version = "0.1.0" } roc_reporting = { path = "../compiler/reporting", version = "0.1.0" }
im = "14" # im and im-rc should always have the same version! im = "14" # im and im-rc should always have the same version!
im-rc = "14" # im and im-rc should always have the same version! im-rc = "14" # im and im-rc should always have the same version!
bumpalo = { version = "3.2", features = ["collections"] } bumpalo = { version = "3.2", features = ["collections"] }
inlinable_string = "0.1.0" inlinable_string = "0.1.0"
tokio = { version = "0.2", features = ["blocking", "fs", "sync", "rt-threaded"] }
# NOTE: rtfeldman/inkwell is a fork of TheDan64/inkwell which does not change anything. # NOTE: rtfeldman/inkwell is a fork of TheDan64/inkwell which does not change anything.
# #
# The reason for this fork is that the way Inkwell is designed, you have to use # The reason for this fork is that the way Inkwell is designed, you have to use

View file

@ -9,10 +9,12 @@ use inkwell::passes::PassManager;
use inkwell::types::BasicType; use inkwell::types::BasicType;
use inkwell::OptimizationLevel; use inkwell::OptimizationLevel;
use roc_collections::all::ImMap; use roc_collections::all::ImMap;
use roc_collections::all::MutMap;
use roc_gen::llvm::build::{ use roc_gen::llvm::build::{
build_proc, build_proc_header, get_call_conventions, module_from_builtins, build_proc, build_proc_header, get_call_conventions, module_from_builtins,
}; };
use roc_gen::llvm::convert::basic_type_from_layout; use roc_gen::llvm::convert::basic_type_from_layout;
use roc_load::file::{load, LoadedModule, LoadingProblem};
use roc_mono::expr::{Expr, Procs}; use roc_mono::expr::{Expr, Procs};
use roc_mono::layout::Layout; use roc_mono::layout::Layout;
use std::time::SystemTime; use std::time::SystemTime;
@ -20,47 +22,71 @@ use std::time::SystemTime;
use inkwell::targets::{ use inkwell::targets::{
CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetTriple, CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetTriple,
}; };
use std::fs::File; use std::env::current_dir;
use std::io; use std::io;
use std::io::prelude::*;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::Command; use std::process::Command;
use target_lexicon::{Architecture, OperatingSystem, Triple, Vendor}; use target_lexicon::{Architecture, OperatingSystem, Triple, Vendor};
use tokio::runtime::Builder;
pub mod helpers; pub mod helpers;
fn main() -> io::Result<()> { fn main() -> io::Result<()> {
let now = SystemTime::now();
let argv = std::env::args().collect::<Vec<String>>(); let argv = std::env::args().collect::<Vec<String>>();
match argv.get(1) { match argv.get(1) {
Some(filename) => { Some(filename) => {
let mut path = Path::new(filename).canonicalize().unwrap(); let mut path = Path::new(filename).canonicalize().unwrap();
let src_dir = current_dir()?;
if !path.is_absolute() { if !path.is_absolute() {
path = std::env::current_dir()?.join(path).canonicalize().unwrap(); path = src_dir.join(path).canonicalize().unwrap();
} }
// Step 1: build the .o file for the app // Create the runtime
let mut file = File::open(path.clone())?; let mut rt = Builder::new()
let mut contents = String::new(); .thread_name("roc")
.threaded_scheduler()
.build()
.expect("Error spawning initial compiler thread."); // TODO make this error nicer.
file.read_to_string(&mut contents)?; // Spawn the root task
let loaded = rt.block_on(load_file(src_dir, path));
let dest_filename = path.with_extension("o"); loaded.expect("TODO gracefully handle LoadingProblem");
gen( Ok(())
Path::new(filename).to_path_buf(), }
contents.as_str(), None => {
Triple::host(), println!("Usage: roc FILENAME.roc");
&dest_filename,
);
let end_time = now.elapsed().unwrap(); Ok(())
}
}
}
async fn load_file(src_dir: PathBuf, filename: PathBuf) -> Result<(), LoadingProblem> {
let compilation_start = SystemTime::now();
// Step 1: compile the app and generate the .o file
let subs_by_module = MutMap::default();
let loaded = load(
&roc_builtins::std::standard_stdlib(),
src_dir,
filename.clone(),
subs_by_module,
)
.await?;
let dest_filename = filename.with_extension("o");
gen(loaded, filename, Triple::host(), &dest_filename);
let compilation_end = compilation_start.elapsed().unwrap();
println!( println!(
"Finished compilation and code gen in {} ms\n", "Finished compilation and code gen in {} ms\n",
end_time.as_millis() compilation_end.as_millis()
); );
let cwd = dest_filename.parent().unwrap(); let cwd = dest_filename.parent().unwrap();
@ -91,25 +117,20 @@ fn main() -> io::Result<()> {
err err
) )
}); });
Ok(())
}
None => {
println!("Usage: roc FILENAME.roc");
Ok(()) Ok(())
}
}
} }
fn gen(filename: PathBuf, src: &str, target: Triple, dest_filename: &Path) { fn gen(loaded: LoadedModule, filename: PathBuf, target: Triple, dest_filename: &Path) {
use roc_reporting::report::{can_problem, RocDocAllocator, DEFAULT_PALETTE}; use roc_reporting::report::{can_problem, RocDocAllocator, DEFAULT_PALETTE};
use roc_reporting::type_error::type_problem; use roc_reporting::type_error::type_problem;
// Build the expr // Build the expr
let arena = Bump::new(); let arena = Bump::new();
let src = loaded.src;
let (loc_expr, _output, can_problems, subs, var, constraint, home, interns) = let (loc_expr, _output, can_problems, subs, var, constraint, home, interns) =
uniq_expr_with(&arena, src, &ImMap::default()); uniq_expr_with(&arena, &src, &ImMap::default());
let mut type_problems = Vec::new(); let mut type_problems = Vec::new();
let (content, mut subs) = infer_expr(subs, &mut type_problems, &constraint, var); let (content, mut subs) = infer_expr(subs, &mut type_problems, &constraint, var);

View file

@ -44,6 +44,7 @@ pub struct Module {
pub aliases: MutMap<Symbol, Alias>, pub aliases: MutMap<Symbol, Alias>,
pub rigid_variables: MutMap<Variable, Lowercase>, pub rigid_variables: MutMap<Variable, Lowercase>,
pub imported_modules: MutSet<ModuleId>, pub imported_modules: MutSet<ModuleId>,
pub src: Box<str>,
} }
#[derive(Debug)] #[derive(Debug)]
@ -54,6 +55,7 @@ pub struct LoadedModule {
pub can_problems: Vec<roc_problem::can::Problem>, pub can_problems: Vec<roc_problem::can::Problem>,
pub type_problems: Vec<solve::TypeError>, pub type_problems: Vec<solve::TypeError>,
pub declarations: Vec<Declaration>, pub declarations: Vec<Declaration>,
pub src: Box<str>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -89,6 +91,7 @@ enum Msg {
var_store: VarStore, var_store: VarStore,
}, },
Solved { Solved {
src: Box<str>,
module_id: ModuleId, module_id: ModuleId,
solved_types: MutMap<Symbol, SolvedType>, solved_types: MutMap<Symbol, SolvedType>,
aliases: MutMap<Symbol, Alias>, aliases: MutMap<Symbol, Alias>,
@ -393,7 +396,7 @@ pub async fn load<'a>(
subs, subs,
problems, problems,
aliases, aliases,
.. src,
} => { } => {
type_problems.extend(problems); type_problems.extend(problems);
@ -428,6 +431,7 @@ pub async fn load<'a>(
can_problems, can_problems,
type_problems, type_problems,
declarations, declarations,
src,
}); });
} else { } else {
// This was a dependency. Write it down and keep processing messages. // This was a dependency. Write it down and keep processing messages.
@ -885,6 +889,7 @@ fn solve_module(
aliases: module.aliases, aliases: module.aliases,
}; };
let src = module.src;
let mut subs = Subs::new(var_store.into()); let mut subs = Subs::new(var_store.into());
for (var, name) in module.rigid_variables { for (var, name) in module.rigid_variables {
@ -934,6 +939,7 @@ fn solve_module(
// Send the subs to the main thread for processing, // Send the subs to the main thread for processing,
tx.send(Msg::Solved { tx.send(Msg::Solved {
src,
module_id: home, module_id: home,
subs: Arc::new(solved_subs), subs: Arc::new(solved_subs),
solved_types, solved_types,
@ -1069,6 +1075,7 @@ fn parse_and_constrain(
aliases, aliases,
rigid_variables, rigid_variables,
imported_modules: header.imported_modules, imported_modules: header.imported_modules,
src: header.src,
}; };
(module, ident_ids, constraint, problems) (module, ident_ids, constraint, problems)