mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 08:11:12 +00:00
Load main
in the CLI and use it for gen
This commit is contained in:
parent
9ca754b8fd
commit
1517581ced
6 changed files with 84 additions and 424 deletions
|
@ -1,7 +1,6 @@
|
|||
extern crate roc_gen;
|
||||
extern crate roc_reporting;
|
||||
|
||||
use crate::helpers::{infer_expr, uniq_expr_with};
|
||||
use bumpalo::Bump;
|
||||
use inkwell::context::Context;
|
||||
use inkwell::module::Linkage;
|
||||
|
@ -15,6 +14,7 @@ use roc_gen::llvm::build::{
|
|||
};
|
||||
use roc_gen::llvm::convert::basic_type_from_layout;
|
||||
use roc_load::file::{load, LoadedModule, LoadingProblem};
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::expr::{Expr, Procs};
|
||||
use roc_mono::layout::Layout;
|
||||
use std::time::SystemTime;
|
||||
|
@ -29,8 +29,6 @@ use std::process::Command;
|
|||
use target_lexicon::{Architecture, OperatingSystem, Triple, Vendor};
|
||||
use tokio::runtime::Builder;
|
||||
|
||||
pub mod helpers;
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
let argv = std::env::args().collect::<Vec<String>>();
|
||||
|
||||
|
@ -67,6 +65,7 @@ fn main() -> io::Result<()> {
|
|||
|
||||
async fn load_file(src_dir: PathBuf, filename: PathBuf) -> Result<(), LoadingProblem> {
|
||||
let compilation_start = SystemTime::now();
|
||||
let arena = Bump::new();
|
||||
|
||||
// Step 1: compile the app and generate the .o file
|
||||
let subs_by_module = MutMap::default();
|
||||
|
@ -80,7 +79,7 @@ async fn load_file(src_dir: PathBuf, filename: PathBuf) -> Result<(), LoadingPro
|
|||
|
||||
let dest_filename = filename.with_extension("o");
|
||||
|
||||
gen(loaded, filename, Triple::host(), &dest_filename);
|
||||
gen(&arena, loaded, filename, Triple::host(), &dest_filename);
|
||||
|
||||
let compilation_end = compilation_start.elapsed().unwrap();
|
||||
|
||||
|
@ -103,14 +102,16 @@ async fn load_file(src_dir: PathBuf, filename: PathBuf) -> Result<(), LoadingPro
|
|||
.expect("`ar` failed to run");
|
||||
|
||||
// Step 3: have rustc compile the host and link in the .a file
|
||||
let binary_path = cwd.join("app");
|
||||
|
||||
Command::new("rustc")
|
||||
.args(&["-L", ".", "host.rs", "-o", "app"])
|
||||
.args(&["-L", ".", "--crate-type", "bin", "host.rs", "-o", binary_path.as_path().to_str().unwrap()])
|
||||
.current_dir(cwd)
|
||||
.spawn()
|
||||
.expect("rustc failed to run");
|
||||
|
||||
// Step 4: Run the compiled app
|
||||
Command::new(cwd.join("app")).spawn().unwrap_or_else(|err| {
|
||||
Command::new(binary_path).spawn().unwrap_or_else(|err| {
|
||||
panic!(
|
||||
"{} failed to run: {:?}",
|
||||
cwd.join("app").to_str().unwrap(),
|
||||
|
@ -121,27 +122,19 @@ async fn load_file(src_dir: PathBuf, filename: PathBuf) -> Result<(), LoadingPro
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn gen(loaded: LoadedModule, filename: PathBuf, target: Triple, dest_filename: &Path) {
|
||||
fn gen(arena: &Bump, loaded: LoadedModule, filename: PathBuf, target: Triple, dest_filename: &Path) {
|
||||
use roc_reporting::report::{can_problem, RocDocAllocator, DEFAULT_PALETTE};
|
||||
use roc_reporting::type_error::type_problem;
|
||||
|
||||
// Build the expr
|
||||
let arena = Bump::new();
|
||||
|
||||
let src = loaded.src;
|
||||
let (loc_expr, _output, can_problems, subs, var, constraint, home, interns) =
|
||||
uniq_expr_with(&arena, &src, &ImMap::default());
|
||||
|
||||
let mut type_problems = Vec::new();
|
||||
let (content, mut subs) = infer_expr(subs, &mut type_problems, &constraint, var);
|
||||
|
||||
let home = loaded.module_id;
|
||||
let src_lines: Vec<&str> = src.split('\n').collect();
|
||||
let palette = DEFAULT_PALETTE;
|
||||
|
||||
// Report parsing and canonicalization problems
|
||||
let alloc = RocDocAllocator::new(&src_lines, home, &interns);
|
||||
let alloc = RocDocAllocator::new(&src_lines, home, &loaded.interns);
|
||||
|
||||
for problem in can_problems.into_iter() {
|
||||
for problem in loaded.can_problems.into_iter() {
|
||||
let report = can_problem(&alloc, filename.clone(), problem);
|
||||
let mut buf = String::new();
|
||||
|
||||
|
@ -150,7 +143,7 @@ fn gen(loaded: LoadedModule, filename: PathBuf, target: Triple, dest_filename: &
|
|||
println!("\n{}\n", buf);
|
||||
}
|
||||
|
||||
for problem in type_problems.into_iter() {
|
||||
for problem in loaded.type_problems.into_iter() {
|
||||
let report = type_problem(&alloc, filename.clone(), problem);
|
||||
let mut buf = String::new();
|
||||
|
||||
|
@ -159,6 +152,63 @@ fn gen(loaded: LoadedModule, filename: PathBuf, target: Triple, dest_filename: &
|
|||
println!("\n{}\n", buf);
|
||||
}
|
||||
|
||||
// Look up the types and expressions of the `provided` values
|
||||
|
||||
// TODO instead of hardcoding this to `main`, use the `provided` list and gen all of them.
|
||||
let ident_ids = loaded.interns.all_ident_ids.get(&home).unwrap();
|
||||
let main_ident_id = *ident_ids.get_id(&"main".into()).unwrap_or_else(|| {
|
||||
todo!("TODO gracefully handle the case where `main` wasn't declared in the app")
|
||||
});
|
||||
let main_symbol = Symbol::new(home, main_ident_id);
|
||||
let mut main_var = None;
|
||||
let mut main_expr = None;
|
||||
|
||||
for (symbol, var) in loaded.exposed_vars_by_symbol {
|
||||
if symbol == main_symbol {
|
||||
main_var = Some(var);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We use a loop label here so we can break all the way out of a nested
|
||||
// loop inside DeclareRec if we find the expr there.
|
||||
//
|
||||
// https://doc.rust-lang.org/1.30.0/book/first-edition/loops.html#loop-labels
|
||||
'find_expr: for decl in loaded.declarations {
|
||||
use roc_can::def::Declaration::*;
|
||||
|
||||
match decl {
|
||||
Declare(def) => {
|
||||
if def.pattern_vars.contains_key(&main_symbol) {
|
||||
main_expr = Some(def.loc_expr);
|
||||
|
||||
break 'find_expr;
|
||||
}
|
||||
}
|
||||
|
||||
DeclareRec(defs) => {
|
||||
for def in defs {
|
||||
if def.pattern_vars.contains_key(&main_symbol) {
|
||||
main_expr = Some(def.loc_expr);
|
||||
|
||||
break 'find_expr;
|
||||
}
|
||||
}
|
||||
}
|
||||
InvalidCycle( _, _) => {}
|
||||
}
|
||||
}
|
||||
|
||||
let loc_expr = main_expr.unwrap_or_else(|| panic!
|
||||
("TODO gracefully handle the case where `main` was declared but not exposed")
|
||||
);
|
||||
let mut subs = loaded.solved.into_inner();
|
||||
let content = match main_var {
|
||||
Some(var) => subs.get_without_compacting(var).content,
|
||||
None => todo!("TODO gracefully handle the case where `main` was declared but not exposed"),
|
||||
};
|
||||
|
||||
// Generate the binary
|
||||
|
||||
let context = Context::create();
|
||||
|
@ -181,14 +231,14 @@ fn gen(loaded: LoadedModule, filename: PathBuf, target: Triple, dest_filename: &
|
|||
|
||||
let main_fn_type =
|
||||
basic_type_from_layout(&arena, &context, &layout, ptr_bytes).fn_type(&[], false);
|
||||
let main_fn_name = "$Test.main";
|
||||
let main_fn_name = "$main";
|
||||
|
||||
// Compile and add all the Procs before adding main
|
||||
let mut env = roc_gen::llvm::build::Env {
|
||||
arena: &arena,
|
||||
builder: &builder,
|
||||
context: &context,
|
||||
interns,
|
||||
interns: loaded.interns,
|
||||
module: arena.alloc(module),
|
||||
ptr_bytes,
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue