mirror of
https://github.com/roc-lang/roc.git
synced 2024-11-09 22:54:44 +03:00
Merge branch 'trunk' into parse-pkg-imports
This commit is contained in:
commit
b592e8b25d
@ -16,6 +16,8 @@ To run the test suite (via `cargo test`), you additionally need to install:
|
||||
* [`valgrind`](https://www.valgrind.org/) (needs special treatment to [install on macOS](https://stackoverflow.com/a/61359781)
|
||||
Alternatively, you can use `cargo test --no-fail-fast` or `cargo test -p specific_tests` to skip over the valgrind failures & tests.
|
||||
|
||||
For debugging LLVM IR, we use [DebugIR](https://github.com/vaivaswatha/debugir). This dependency is only required to build with the `--debug` flag, and for normal developtment you should be fine without it.
|
||||
|
||||
### libunwind & libc++-dev
|
||||
|
||||
MacOS systems should already have `libunwind`, but other systems will need to install it (On Ubuntu, this can be donw with `sudo apt-get install libunwind-dev`).
|
||||
|
@ -24,6 +24,7 @@ pub fn build_file(
|
||||
src_dir: PathBuf,
|
||||
roc_file_path: PathBuf,
|
||||
opt_level: OptLevel,
|
||||
emit_debug_info: bool,
|
||||
link_type: LinkType,
|
||||
) -> Result<PathBuf, LoadingProblem> {
|
||||
let compilation_start = SystemTime::now();
|
||||
@ -95,6 +96,7 @@ pub fn build_file(
|
||||
Triple::host(),
|
||||
&app_o_file,
|
||||
opt_level,
|
||||
emit_debug_info,
|
||||
);
|
||||
|
||||
println!("\nSuccess! 🎉\n\n\t➡ {}\n", app_o_file.display());
|
||||
|
@ -14,6 +14,7 @@ use target_lexicon::Triple;
|
||||
pub mod build;
|
||||
pub mod repl;
|
||||
|
||||
pub static FLAG_DEBUG: &str = "debug";
|
||||
pub static FLAG_OPTIMIZE: &str = "optimize";
|
||||
pub static FLAG_ROC_FILE: &str = "ROC_FILE";
|
||||
pub static DIRECTORY_OR_FILES: &str = "DIRECTORY_OR_FILES";
|
||||
@ -34,6 +35,12 @@ pub fn build_app<'a>() -> App<'a> {
|
||||
.help("Optimize the compiled program to run faster. (Optimization takes time to complete.)")
|
||||
.required(false),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(FLAG_DEBUG)
|
||||
.long(FLAG_DEBUG)
|
||||
.help("Store LLVM debug information in the generated program")
|
||||
.required(false),
|
||||
)
|
||||
)
|
||||
.subcommand(App::new("run")
|
||||
.about("Build and run a program")
|
||||
@ -48,6 +55,12 @@ pub fn build_app<'a>() -> App<'a> {
|
||||
.help("Optimize the compiled program to run faster. (Optimization takes time to complete.)")
|
||||
.required(false),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(FLAG_DEBUG)
|
||||
.long(FLAG_DEBUG)
|
||||
.help("Store LLVM debug information in the generated program")
|
||||
.required(false),
|
||||
)
|
||||
)
|
||||
.subcommand(App::new("repl")
|
||||
.about("Launch the interactive Read Eval Print Loop (REPL)")
|
||||
@ -70,6 +83,8 @@ pub fn build(target: &Triple, matches: &ArgMatches, run_after_build: bool) -> io
|
||||
} else {
|
||||
OptLevel::Normal
|
||||
};
|
||||
let emit_debug_info = matches.is_present(FLAG_DEBUG);
|
||||
|
||||
let path = Path::new(filename).canonicalize().unwrap();
|
||||
let src_dir = path.parent().unwrap().canonicalize().unwrap();
|
||||
|
||||
@ -92,8 +107,15 @@ pub fn build(target: &Triple, matches: &ArgMatches, run_after_build: bool) -> io
|
||||
}
|
||||
});
|
||||
|
||||
let binary_path = build::build_file(target, src_dir, path, opt_level, LinkType::Executable)
|
||||
.expect("TODO gracefully handle build_file failing");
|
||||
let binary_path = build::build_file(
|
||||
target,
|
||||
src_dir,
|
||||
path,
|
||||
opt_level,
|
||||
emit_debug_info,
|
||||
LinkType::Executable,
|
||||
)
|
||||
.expect("TODO gracefully handle build_file failing");
|
||||
|
||||
if run_after_build {
|
||||
// Run the compiled app
|
||||
|
@ -4,6 +4,8 @@ use inkwell::module::Module;
|
||||
use inkwell::targets::{CodeModel, FileType, RelocMode};
|
||||
use libloading::{Error, Library};
|
||||
use roc_gen::llvm::build::OptLevel;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Child, Command, Output};
|
||||
@ -25,7 +27,6 @@ pub fn link(
|
||||
) -> io::Result<(Child, PathBuf)> {
|
||||
match target {
|
||||
Triple {
|
||||
architecture: Architecture::X86_64,
|
||||
operating_system: OperatingSystem::Linux,
|
||||
..
|
||||
} => link_linux(target, output_path, input_paths, link_type),
|
||||
@ -46,9 +47,11 @@ pub fn rebuild_host(host_input_path: &Path) {
|
||||
let cargo_host_src = host_input_path.with_file_name("Cargo.toml");
|
||||
let host_dest = host_input_path.with_file_name("host.o");
|
||||
|
||||
let env_path = env::var("PATH").unwrap_or_else(|_| "".to_string());
|
||||
// Compile host.c
|
||||
let output = Command::new("clang")
|
||||
.env_clear()
|
||||
.env("PATH", &env_path)
|
||||
.args(&[
|
||||
"-c",
|
||||
c_host_src.to_str().unwrap(),
|
||||
@ -75,6 +78,7 @@ pub fn rebuild_host(host_input_path: &Path) {
|
||||
|
||||
let output = Command::new("ld")
|
||||
.env_clear()
|
||||
.env("PATH", &env_path)
|
||||
.args(&[
|
||||
"-r",
|
||||
"-L",
|
||||
@ -103,6 +107,7 @@ pub fn rebuild_host(host_input_path: &Path) {
|
||||
|
||||
let output = Command::new("ld")
|
||||
.env_clear()
|
||||
.env("PATH", &env_path)
|
||||
.args(&[
|
||||
"-r",
|
||||
c_host_dest.to_str().unwrap(),
|
||||
@ -145,18 +150,31 @@ fn link_linux(
|
||||
input_paths: &[&str],
|
||||
link_type: LinkType,
|
||||
) -> io::Result<(Child, PathBuf)> {
|
||||
let libcrt_path = if Path::new("/usr/lib/x86_64-linux-gnu").exists() {
|
||||
Path::new("/usr/lib/x86_64-linux-gnu")
|
||||
let usr_lib_path = Path::new("/usr/lib").to_path_buf();
|
||||
let usr_lib_gnu_path = usr_lib_path.join(format!("{}-linux-gnu", target.architecture));
|
||||
let lib_gnu_path = Path::new("/lib/").join(format!("{}-linux-gnu", target.architecture));
|
||||
|
||||
let libcrt_path = if usr_lib_gnu_path.exists() {
|
||||
&usr_lib_gnu_path
|
||||
} else {
|
||||
Path::new("/usr/lib")
|
||||
&usr_lib_path
|
||||
};
|
||||
|
||||
let libgcc_path = if Path::new("/lib/x86_64-linux-gnu/libgcc_s.so.1").exists() {
|
||||
Path::new("/lib/x86_64-linux-gnu/libgcc_s.so.1")
|
||||
} else if Path::new("/usr/lib/x86_64-linux-gnu/libgcc_s.so.1").exists() {
|
||||
Path::new("/usr/lib/x86_64-linux-gnu/libgcc_s.so.1")
|
||||
let libgcc_name = "libgcc_s.so.1";
|
||||
let libgcc_path = if lib_gnu_path.join(libgcc_name).exists() {
|
||||
lib_gnu_path.join(libgcc_name)
|
||||
} else if usr_lib_gnu_path.join(libgcc_name).exists() {
|
||||
usr_lib_gnu_path.join(libgcc_name)
|
||||
} else {
|
||||
Path::new("/usr/lib/libgcc_s.so.1")
|
||||
usr_lib_path.join(libgcc_name)
|
||||
};
|
||||
let ld_linux = match target.architecture {
|
||||
Architecture::X86_64 => "/lib64/ld-linux-x86-64.so.2",
|
||||
Architecture::Aarch64(_) => "/lib/ld-linux-aarch64.so.1",
|
||||
_ => panic!(
|
||||
"TODO gracefully handle unsupported linux architecture: {:?}",
|
||||
target.architecture
|
||||
),
|
||||
};
|
||||
|
||||
let mut soname;
|
||||
@ -194,12 +212,20 @@ fn link_linux(
|
||||
}
|
||||
};
|
||||
|
||||
let env_path = env::var("PATH").unwrap_or_else(|_| "".to_string());
|
||||
// NOTE: order of arguments to `ld` matters here!
|
||||
// The `-l` flags should go after the `.o` arguments
|
||||
Ok((
|
||||
Command::new("ld")
|
||||
// Don't allow LD_ env vars to affect this
|
||||
.env_clear()
|
||||
.env("PATH", &env_path)
|
||||
// Keep NIX_ env vars
|
||||
.envs(
|
||||
env::vars()
|
||||
.filter(|&(ref k, _)| k.starts_with("NIX_"))
|
||||
.collect::<HashMap<String, String>>(),
|
||||
)
|
||||
.args(&[
|
||||
"-arch",
|
||||
arch_str(target),
|
||||
@ -207,7 +233,7 @@ fn link_linux(
|
||||
libcrt_path.join("crtn.o").to_str().unwrap(),
|
||||
])
|
||||
.args(&base_args)
|
||||
.args(&["-dynamic-linker", "/lib64/ld-linux-x86-64.so.2"])
|
||||
.args(&["-dynamic-linker", ld_linux])
|
||||
.args(input_paths)
|
||||
.args(&[
|
||||
// Libraries - see https://github.com/rtfeldman/roc/pull/554#discussion_r496365925
|
||||
@ -220,6 +246,7 @@ fn link_linux(
|
||||
"-lutil",
|
||||
"-lc_nonshared",
|
||||
"-lc++",
|
||||
"-lc++abi",
|
||||
"-lunwind",
|
||||
libgcc_path.to_str().unwrap(),
|
||||
// Output
|
||||
|
@ -20,6 +20,7 @@ pub fn gen_from_mono_module(
|
||||
target: Triple,
|
||||
app_o_file: &Path,
|
||||
opt_level: OptLevel,
|
||||
emit_debug_info: bool,
|
||||
) {
|
||||
use roc_reporting::report::{
|
||||
can_problem, mono_problem, type_problem, RocDocAllocator, DEFAULT_PALETTE,
|
||||
@ -159,15 +160,78 @@ pub fn gen_from_mono_module(
|
||||
// Uncomment this to see the module's optimized LLVM instruction output:
|
||||
// env.module.print_to_stderr();
|
||||
|
||||
// Emit the .o file
|
||||
// annotate the LLVM IR output with debug info
|
||||
// so errors are reported with the line number of the LLVM source
|
||||
if emit_debug_info {
|
||||
module.strip_debug_info();
|
||||
|
||||
let reloc = RelocMode::Default;
|
||||
let model = CodeModel::Default;
|
||||
let target_machine = target::target_machine(&target, opt_level.into(), reloc, model).unwrap();
|
||||
let mut app_ll_file = std::path::PathBuf::from(app_o_file);
|
||||
app_ll_file.set_extension("ll");
|
||||
|
||||
target_machine
|
||||
.write_to_file(&env.module, FileType::Object, &app_o_file)
|
||||
.expect("Writing .o file failed");
|
||||
let mut app_ll_dbg_file = std::path::PathBuf::from(app_o_file);
|
||||
app_ll_dbg_file.set_extension("dbg.ll");
|
||||
|
||||
let mut app_bc_file = std::path::PathBuf::from(app_o_file);
|
||||
app_bc_file.set_extension("bc");
|
||||
|
||||
use std::process::Command;
|
||||
|
||||
// write the ll code to a file, so we can modify it
|
||||
module.print_to_file(&app_ll_file).unwrap();
|
||||
|
||||
// run the debugir https://github.com/vaivaswatha/debugir tool
|
||||
match Command::new("debugir")
|
||||
.env_clear()
|
||||
.args(&[app_ll_file.to_str().unwrap()])
|
||||
.output()
|
||||
{
|
||||
Ok(_) => {}
|
||||
Err(error) => {
|
||||
use std::io::ErrorKind;
|
||||
match error.kind() {
|
||||
ErrorKind::NotFound => panic!(
|
||||
r"I could not find the `debugir` tool on the PATH, install it from https://github.com/vaivaswatha/debugir"
|
||||
),
|
||||
_ => panic!("{:?}", error),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// assemble the .ll into a .bc
|
||||
let _ = Command::new("llvm-as-10")
|
||||
.env_clear()
|
||||
.args(&[
|
||||
app_ll_dbg_file.to_str().unwrap(),
|
||||
"-o",
|
||||
app_bc_file.to_str().unwrap(),
|
||||
])
|
||||
.output()
|
||||
.unwrap();
|
||||
|
||||
// write the .o file. Note that this builds the .o for the local machine,
|
||||
// and ignores the `target_machine` entirely.
|
||||
let _ = Command::new("llc-10")
|
||||
.env_clear()
|
||||
.args(&[
|
||||
"-filetype=obj",
|
||||
app_bc_file.to_str().unwrap(),
|
||||
"-o",
|
||||
app_o_file.to_str().unwrap(),
|
||||
])
|
||||
.output()
|
||||
.unwrap();
|
||||
} else {
|
||||
// Emit the .o file
|
||||
|
||||
let reloc = RelocMode::Default;
|
||||
let model = CodeModel::Default;
|
||||
let target_machine =
|
||||
target::target_machine(&target, opt_level.into(), reloc, model).unwrap();
|
||||
|
||||
target_machine
|
||||
.write_to_file(&env.module, FileType::Object, &app_o_file)
|
||||
.expect("Writing .o file failed");
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FunctionIterator<'ctx> {
|
||||
|
@ -14,6 +14,11 @@ pub fn target_triple_str(target: &Triple) -> &'static str {
|
||||
operating_system: OperatingSystem::Linux,
|
||||
..
|
||||
} => "x86_64-unknown-linux-gnu",
|
||||
Triple {
|
||||
architecture: Architecture::Aarch64(_),
|
||||
operating_system: OperatingSystem::Linux,
|
||||
..
|
||||
} => "aarch64-unknown-linux-gnu",
|
||||
Triple {
|
||||
architecture: Architecture::X86_64,
|
||||
operating_system: OperatingSystem::Darwin,
|
||||
@ -36,6 +41,10 @@ pub fn arch_str(target: &Triple) -> &'static str {
|
||||
|
||||
"x86-64"
|
||||
}
|
||||
Architecture::Aarch64(_) => {
|
||||
Target::initialize_aarch64(&InitializationConfig::default());
|
||||
"aarch64"
|
||||
}
|
||||
Architecture::Arm(_) if cfg!(feature = "target-arm") => {
|
||||
// NOTE: why not enable arm and wasm by default?
|
||||
//
|
||||
@ -67,7 +76,7 @@ pub fn target_machine(
|
||||
|
||||
Target::from_name(arch).unwrap().create_target_machine(
|
||||
&TargetTriple::create(target_triple_str(target)),
|
||||
arch,
|
||||
"generic",
|
||||
"", // TODO: this probably should be TargetMachine::get_host_cpu_features() to enable all features.
|
||||
opt,
|
||||
reloc,
|
||||
|
@ -1725,10 +1725,7 @@ fn expose_function_to_host<'a, 'ctx, 'env>(
|
||||
let c_function_name: String =
|
||||
format!("roc_{}_exposed", roc_function.get_name().to_str().unwrap());
|
||||
|
||||
let result = expose_function_to_host_help(env, roc_function, &c_function_name);
|
||||
|
||||
let subprogram = env.new_subprogram(&c_function_name);
|
||||
result.set_subprogram(subprogram);
|
||||
expose_function_to_host_help(env, roc_function, &c_function_name);
|
||||
}
|
||||
|
||||
fn expose_function_to_host_help<'a, 'ctx, 'env>(
|
||||
@ -1806,7 +1803,8 @@ fn expose_function_to_host_help<'a, 'ctx, 'env>(
|
||||
|
||||
// STEP 3: build a {} -> u64 function that gives the size of the return type
|
||||
let size_function_type = env.context.i64_type().fn_type(&[], false);
|
||||
let size_function_name: String = format!("{}_size", roc_function.get_name().to_str().unwrap());
|
||||
let size_function_name: String =
|
||||
format!("roc_{}_size", roc_function.get_name().to_str().unwrap());
|
||||
|
||||
let size_function = env.module.add_function(
|
||||
size_function_name.as_str(),
|
||||
@ -1814,10 +1812,30 @@ fn expose_function_to_host_help<'a, 'ctx, 'env>(
|
||||
Some(Linkage::External),
|
||||
);
|
||||
|
||||
let subprogram = env.new_subprogram(&size_function_name);
|
||||
size_function.set_subprogram(subprogram);
|
||||
|
||||
let entry = context.append_basic_block(size_function, "entry");
|
||||
|
||||
builder.position_at_end(entry);
|
||||
|
||||
let func_scope = size_function.get_subprogram().unwrap();
|
||||
let lexical_block = env.dibuilder.create_lexical_block(
|
||||
/* scope */ func_scope.as_debug_info_scope(),
|
||||
/* file */ env.compile_unit.get_file(),
|
||||
/* line_no */ 0,
|
||||
/* column_no */ 0,
|
||||
);
|
||||
|
||||
let loc = env.dibuilder.create_debug_location(
|
||||
env.context,
|
||||
/* line */ 0,
|
||||
/* column */ 0,
|
||||
/* current_scope */ lexical_block.as_debug_info_scope(),
|
||||
/* inlined_at */ None,
|
||||
);
|
||||
builder.set_current_debug_location(env.context, loc);
|
||||
|
||||
let size: BasicValueEnum = return_type.size_of().unwrap().into();
|
||||
builder.build_return(Some(&size));
|
||||
|
||||
@ -2012,6 +2030,9 @@ fn make_exception_catching_wrapper<'a, 'ctx, 'env>(
|
||||
env.module
|
||||
.add_function(&wrapper_function_name, wrapper_function_type, None);
|
||||
|
||||
let subprogram = env.new_subprogram(wrapper_function_name);
|
||||
wrapper_function.set_subprogram(subprogram);
|
||||
|
||||
// our exposed main function adheres to the C calling convention
|
||||
wrapper_function.set_call_conventions(FAST_CALL_CONV);
|
||||
|
||||
@ -2021,6 +2042,23 @@ fn make_exception_catching_wrapper<'a, 'ctx, 'env>(
|
||||
let basic_block = context.append_basic_block(wrapper_function, "entry");
|
||||
builder.position_at_end(basic_block);
|
||||
|
||||
let func_scope = wrapper_function.get_subprogram().unwrap();
|
||||
let lexical_block = env.dibuilder.create_lexical_block(
|
||||
/* scope */ func_scope.as_debug_info_scope(),
|
||||
/* file */ env.compile_unit.get_file(),
|
||||
/* line_no */ 0,
|
||||
/* column_no */ 0,
|
||||
);
|
||||
|
||||
let loc = env.dibuilder.create_debug_location(
|
||||
env.context,
|
||||
/* line */ 0,
|
||||
/* column */ 0,
|
||||
/* current_scope */ lexical_block.as_debug_info_scope(),
|
||||
/* inlined_at */ None,
|
||||
);
|
||||
builder.set_current_debug_location(env.context, loc);
|
||||
|
||||
let result = invoke_and_catch(
|
||||
env,
|
||||
wrapper_function,
|
||||
@ -2119,8 +2157,9 @@ pub fn build_closure_caller<'a, 'ctx, 'env>(
|
||||
|
||||
// STEP 1: build function header
|
||||
|
||||
// e.g. `roc__main_1_Fx_caller`
|
||||
let function_name = format!(
|
||||
"{}_{}_caller",
|
||||
"roc_{}_{}_caller",
|
||||
def_name,
|
||||
alias_symbol.ident_string(&env.interns)
|
||||
);
|
||||
@ -2200,7 +2239,7 @@ pub fn build_closure_caller<'a, 'ctx, 'env>(
|
||||
// STEP 3: build a {} -> u64 function that gives the size of the return type
|
||||
let size_function_type = env.context.i64_type().fn_type(&[], false);
|
||||
let size_function_name: String = format!(
|
||||
"{}_{}_size",
|
||||
"roc_{}_{}_size",
|
||||
def_name,
|
||||
alias_symbol.ident_string(&env.interns)
|
||||
);
|
||||
|
@ -70,6 +70,8 @@ Thoughts and ideas possibly taken from above inspirations or separate.
|
||||
* Makes sense for unit tests, keeps the test close to the source
|
||||
* Doesn't necessarily make sense for integration or e2e testing
|
||||
* Maybe easier to manually trigger a test related to exactly what code you're writing
|
||||
* Ability to generate unit tests for a selected function in context menu
|
||||
* A table should appear to enter input and expected output pairs quickly
|
||||
* "Error mode" where the editor jumps you to the next error
|
||||
* Similar in theory to diff tools that jump you to the next merge conflict
|
||||
* dependency recommendation
|
||||
|
7
examples/balance/Main.roc
Normal file
7
examples/balance/Main.roc
Normal file
@ -0,0 +1,7 @@
|
||||
app Main provides [ rocMain ] imports [ Effect ]
|
||||
|
||||
rocMain : Effect.Effect {} as Fx
|
||||
rocMain =
|
||||
when List.len (Str.split "hello" "JJJJ there") is
|
||||
_ -> Effect.putLine "Yay"
|
||||
|
23
examples/balance/platform/Cargo.lock
generated
Normal file
23
examples/balance/platform/Cargo.lock
generated
Normal file
@ -0,0 +1,23 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "host"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"roc_std 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "roc_std"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[metadata]
|
||||
"checksum libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)" = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743"
|
13
examples/balance/platform/Cargo.toml
Normal file
13
examples/balance/platform/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "host"
|
||||
version = "0.1.0"
|
||||
authors = ["Richard Feldman <oss@rtfeldman.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[dependencies]
|
||||
roc_std = { path = "../../../roc_std" }
|
||||
|
||||
[workspace]
|
13
examples/balance/platform/Pkg-Config.roc
Normal file
13
examples/balance/platform/Pkg-Config.roc
Normal file
@ -0,0 +1,13 @@
|
||||
platform folkertdev/foo
|
||||
provides [ mainForHost ]
|
||||
requires { main : Effect {} }
|
||||
imports []
|
||||
effects Effect
|
||||
{
|
||||
putChar : Int -> Effect {},
|
||||
putLine : Str -> Effect {},
|
||||
getLine : Effect Str
|
||||
}
|
||||
|
||||
mainForHost : Effect {} as Fx
|
||||
mainForHost = main
|
7
examples/balance/platform/host.c
Normal file
7
examples/balance/platform/host.c
Normal file
@ -0,0 +1,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
extern int rust_main();
|
||||
|
||||
int main() {
|
||||
return rust_main();
|
||||
}
|
118
examples/balance/platform/src/lib.rs
Normal file
118
examples/balance/platform/src/lib.rs
Normal file
@ -0,0 +1,118 @@
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use roc_std::alloca;
|
||||
use roc_std::RocCallResult;
|
||||
use roc_std::RocStr;
|
||||
use std::alloc::Layout;
|
||||
use std::time::SystemTime;
|
||||
|
||||
extern "C" {
|
||||
#[link_name = "Main_rocMain_1_exposed"]
|
||||
fn roc_main(output: *mut u8) -> ();
|
||||
|
||||
#[link_name = "Main_rocMain_1_size"]
|
||||
fn roc_main_size() -> i64;
|
||||
|
||||
#[link_name = "Main_rocMain_1_Fx_caller"]
|
||||
fn call_Fx(function_pointer: *const u8, closure_data: *const u8, output: *mut u8) -> ();
|
||||
|
||||
#[link_name = "Main_rocMain_1_Fx_size"]
|
||||
fn size_Fx() -> i64;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn roc_fx_putChar(foo: i64) -> () {
|
||||
let character = foo as u8 as char;
|
||||
print!("{}", character);
|
||||
|
||||
()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn roc_fx_putLine(line: RocStr) -> () {
|
||||
let bytes = line.as_slice();
|
||||
let string = unsafe { std::str::from_utf8_unchecked(bytes) };
|
||||
println!("{}", string);
|
||||
|
||||
()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn roc_fx_getLine() -> RocStr {
|
||||
use std::io::{self, BufRead};
|
||||
|
||||
let stdin = io::stdin();
|
||||
let line1 = stdin.lock().lines().next().unwrap().unwrap();
|
||||
|
||||
RocStr::from_slice_with_capacity(line1.as_bytes(), line1.len())
|
||||
}
|
||||
|
||||
unsafe fn call_the_closure(function_pointer: *const u8, closure_data_ptr: *const u8) -> i64 {
|
||||
let size = size_Fx() as usize;
|
||||
|
||||
alloca::with_stack_bytes(size, |buffer| {
|
||||
let buffer: *mut std::ffi::c_void = buffer;
|
||||
let buffer: *mut u8 = buffer as *mut u8;
|
||||
|
||||
call_Fx(
|
||||
function_pointer,
|
||||
closure_data_ptr as *const u8,
|
||||
buffer as *mut u8,
|
||||
);
|
||||
|
||||
let output = &*(buffer as *mut RocCallResult<i64>);
|
||||
|
||||
// match output.into() {
|
||||
// Ok(v) => v,
|
||||
// Err(e) => panic!("failed with {}", e),
|
||||
// }
|
||||
32
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn rust_main() -> isize {
|
||||
println!("Running Roc closure");
|
||||
let start_time = SystemTime::now();
|
||||
|
||||
let size = unsafe { roc_main_size() } as usize;
|
||||
let layout = Layout::array::<u8>(size).unwrap();
|
||||
let answer = unsafe {
|
||||
let buffer = std::alloc::alloc(layout);
|
||||
|
||||
roc_main(buffer);
|
||||
|
||||
let output = &*(buffer as *mut RocCallResult<()>);
|
||||
|
||||
match output.into() {
|
||||
Ok(()) => {
|
||||
let function_pointer = {
|
||||
// this is a pointer to the location where the function pointer is stored
|
||||
// we pass just the function pointer
|
||||
let temp = buffer.offset(8) as *const i64;
|
||||
|
||||
(*temp) as *const u8
|
||||
};
|
||||
|
||||
let closure_data_ptr = buffer.offset(16);
|
||||
|
||||
call_the_closure(function_pointer as *const u8, closure_data_ptr as *const u8)
|
||||
}
|
||||
Err(msg) => {
|
||||
std::alloc::dealloc(buffer, layout);
|
||||
|
||||
panic!("Roc failed with message: {}", msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
let end_time = SystemTime::now();
|
||||
let duration = end_time.duration_since(start_time).unwrap();
|
||||
|
||||
println!(
|
||||
"Roc execution took {:.4} ms",
|
||||
duration.as_secs_f64() * 1000.0,
|
||||
);
|
||||
|
||||
// Exit code
|
||||
0
|
||||
}
|
@ -1,31 +1,18 @@
|
||||
app "effect-example" provides [ main ] imports [ Effect, RBTree ]
|
||||
|
||||
toAndFro : Int
|
||||
toAndFro =
|
||||
empty : RBTree.Dict Int {}
|
||||
empty = RBTree.empty
|
||||
|
||||
empty
|
||||
|> (\d -> RBTree.insert 1 {} d)
|
||||
|> RBTree.toList
|
||||
|> List.len
|
||||
|
||||
|
||||
app "effect-example" imports [ Effect ] provides [ main ] to "./platform"
|
||||
|
||||
|
||||
main : Effect.Effect {} as Fx
|
||||
main =
|
||||
# if RBTree.isEmpty empty then
|
||||
if toAndFro == 2 then
|
||||
Effect.putLine "Yay"
|
||||
|> Effect.after (\{} -> Effect.getLine)
|
||||
|> Effect.after (\line -> Effect.putLine line)
|
||||
else
|
||||
Effect.putLine "Nay"
|
||||
when if 1 == 1 then True 3 else False 3.14 is
|
||||
True 3 -> Effect.putLine "Yay"
|
||||
_ -> Effect.putLine "Yay"
|
||||
|
||||
|
||||
# Effect.always "Write a thing"
|
||||
# |> Effect.map (\line -> Str.concat line "!")
|
||||
# |> Effect.after (\line -> Effect.putLine line)
|
||||
# |> Effect.after (\{} -> Effect.getLine)
|
||||
# |> Effect.after (\line -> Effect.putLine line)
|
||||
# main : Effect.Effect {} as Fx
|
||||
# main =
|
||||
# if RBTree.isEmpty (RBTree.insert 1 2 Empty) then
|
||||
# Effect.putLine "Yay"
|
||||
# |> Effect.after (\{} -> Effect.getLine)
|
||||
# |> Effect.after (\line -> Effect.putLine line)
|
||||
# else
|
||||
# Effect.putLine "Nay"
|
||||
#
|
||||
|
@ -1,4 +1,4 @@
|
||||
interface RBTree exposes [ Dict, empty, size, singleton, isEmpty, insert, remove, update, fromList, toList ] imports []
|
||||
interface RBTree exposes [ Dict, empty, size, singleton, isEmpty, insert, remove, update, fromList, toList, balance ] imports []
|
||||
|
||||
# The color of a node. Leaves are considered Black.
|
||||
NodeColor : [ Red, Black ]
|
||||
|
@ -7,16 +7,16 @@ use std::alloc::Layout;
|
||||
use std::time::SystemTime;
|
||||
|
||||
extern "C" {
|
||||
#[link_name = "Main_main_1_exposed"]
|
||||
#[link_name = "roc__main_1_exposed"]
|
||||
fn roc_main(output: *mut u8) -> ();
|
||||
|
||||
#[link_name = "Main_main_1_size"]
|
||||
#[link_name = "roc__main_1_size"]
|
||||
fn roc_main_size() -> i64;
|
||||
|
||||
#[link_name = "Main_main_1_Fx_caller"]
|
||||
#[link_name = "roc__main_1_Fx_caller"]
|
||||
fn call_Fx(function_pointer: *const u8, closure_data: *const u8, output: *mut u8) -> ();
|
||||
|
||||
#[link_name = "Main_main_1_Fx_size"]
|
||||
#[link_name = "roc__main_1_Fx_size"]
|
||||
fn size_Fx() -> i64;
|
||||
}
|
||||
|
||||
@ -60,10 +60,10 @@ unsafe fn call_the_closure(function_pointer: *const u8, closure_data_ptr: *const
|
||||
buffer as *mut u8,
|
||||
);
|
||||
|
||||
let output = &*(buffer as *mut RocCallResult<i64>);
|
||||
let output = &*(buffer as *mut RocCallResult<()>);
|
||||
|
||||
match output.into() {
|
||||
Ok(v) => v,
|
||||
Ok(_) => 0,
|
||||
Err(e) => panic!("failed with {}", e),
|
||||
}
|
||||
})
|
||||
@ -95,7 +95,12 @@ pub fn rust_main() -> isize {
|
||||
|
||||
let closure_data_ptr = buffer.offset(16);
|
||||
|
||||
call_the_closure(function_pointer as *const u8, closure_data_ptr as *const u8)
|
||||
let result =
|
||||
call_the_closure(function_pointer as *const u8, closure_data_ptr as *const u8);
|
||||
|
||||
std::alloc::dealloc(buffer, layout);
|
||||
|
||||
result
|
||||
}
|
||||
Err(msg) => {
|
||||
std::alloc::dealloc(buffer, layout);
|
||||
|
@ -66,6 +66,9 @@ let
|
||||
libffi
|
||||
libxml2
|
||||
zlib
|
||||
llvmPkgs.libcxx
|
||||
llvmPkgs.libcxxabi
|
||||
libunwind
|
||||
# faster builds - see https://github.com/rtfeldman/roc/blob/trunk/BUILDING_FROM_SOURCE.md#use-lld-for-the-linker
|
||||
llvmPkgs.lld
|
||||
# dev tools
|
||||
@ -79,7 +82,7 @@ in mkShell {
|
||||
LLVM_SYS_100_PREFIX = "${llvmPkgs.llvm}";
|
||||
|
||||
APPEND_LIBRARY_PATH = stdenv.lib.makeLibraryPath
|
||||
([ pkgconfig llvmPkgs.libcxx llvmPkgs.libcxxabi libunwind ] ++ linux-only);
|
||||
([ pkg-config llvmPkgs.libcxx llvmPkgs.libcxxabi libunwind ] ++ linux-only);
|
||||
|
||||
# Aliases don't work cross shell, so we do this
|
||||
shellHook = ''
|
||||
|
Loading…
Reference in New Issue
Block a user