Merge branch 'main' into list-walk-with-index-until

This commit is contained in:
Bryce Miller 2023-12-18 17:25:06 +01:00 committed by GitHub
commit a710dd18ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 341 additions and 106 deletions

View file

@ -25,7 +25,7 @@ jobs:
run: ./ci/write_version.sh
- name: build release with lto
run: cargo build --profile=release-with-lto --locked --bin roc
run: cargo build --profile=release-with-lto --locked --bin roc --bin roc_ls
- name: get commit SHA
run: echo "SHA=$(git rev-parse --short "$GITHUB_SHA")" >> $GITHUB_ENV

View file

@ -25,7 +25,7 @@ jobs:
run: ./ci/write_version.sh
- name: build release with lto
run: RUSTFLAGS="-C target-cpu=x86-64" cargo build --profile=release-with-lto --locked --bin roc
run: RUSTFLAGS="-C target-cpu=x86-64" cargo build --profile=release-with-lto --locked --bin roc --bin roc_ls
# target-cpu=x86-64 -> For maximal compatibility for all CPU's. This was also faster in our tests: https://roc.zulipchat.com/#narrow/stream/231635-compiler-development/topic/.2Ecargo.2Fconfig.2Etoml/near/325726299
- name: get commit SHA

View file

@ -42,11 +42,7 @@ jobs:
run: ./ci/write_version.sh
- name: build nightly release
run: cargo build --locked --profile=release-with-lto --bin roc
# this makes the roc binary a lot smaller
- name: strip debug info
run: strip ./target/release-with-lto/roc
run: cargo build --locked --profile=release-with-lto --bin roc --bin roc_ls
- name: package release
run: ./ci/package_release.sh ${{ env.RELEASE_FOLDER_NAME }}

View file

@ -32,7 +32,7 @@ jobs:
# this issue may be caused by using older versions of XCode
- name: build release
run: RUSTFLAGS="-C target-cpu=x86-64" cargo build --profile=release-with-lto --locked --bin roc
run: RUSTFLAGS="-C target-cpu=x86-64" cargo build --profile=release-with-lto --locked --bin roc --bin roc_ls
# target-cpu=x86-64 -> For maximal compatibility for all CPU's.
- name: get commit SHA

View file

@ -53,9 +53,7 @@ build-nightly-release:
COPY --dir .git LICENSE LEGAL_DETAILS ci ./
# version.txt is used by the CLI: roc --version
RUN ./ci/write_version.sh
RUN RUSTFLAGS=$RUSTFLAGS cargo build --profile=release-with-lto --locked --bin roc
# strip debug info
RUN strip ./target/release-with-lto/roc
RUN RUSTFLAGS=$RUSTFLAGS cargo build --profile=release-with-lto --locked --bin roc --bin roc_ls
RUN ./ci/package_release.sh $RELEASE_FOLDER_NAME
RUN ls
SAVE ARTIFACT ./$RELEASE_FOLDER_NAME.tar.gz AS LOCAL $RELEASE_FOLDER_NAME.tar.gz

View file

@ -6,7 +6,7 @@
- [**tutorial**](https://roc-lang.org/tutorial)
- [**docs** for the standard library](https://www.roc-lang.org/builtins)
- [**examples**](https://github.com/roc-lang/examples/tree/main/examples)
- [**faq**: frequently asked questions](https://github.com/roc-lang/roc/blob/main/FAQ.md)
- [**faq**: frequently asked questions](https://github.com/roc-lang/roc/blob/main/www/content/faq.md)
- [**group chat**](https://roc.zulipchat.com) for help, questions and discussions
If you'd like to contribute, check out [good first issues](https://github.com/roc-lang/roc/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22). Don't hesitate to ask for help on our [group chat](https://roc.zulipchat.com), we're friendly!

View file

@ -3,15 +3,21 @@
# https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
set -euxo pipefail
cp target/release-with-lto/roc ./roc # to be able to delete "target" later
# this makes the binaries a lot smaller
strip ./target/release-with-lto/roc
strip ./target/release-with-lto/roc_ls
# to be able to delete "target" later
cp target/release-with-lto/roc ./roc
cp target/release-with-lto/roc_ls ./roc_lang_server
# delete unnecessary files and folders
git clean -fdx --exclude roc
git clean -fdx --exclude roc --exclude roc_lang_server
mkdir $1
mv roc LICENSE LEGAL_DETAILS $1
mv roc roc_lang_server LICENSE LEGAL_DETAILS $1
mkdir $1/examples
mv examples/helloWorld.roc examples/platform-switching examples/cli $1/examples

View file

@ -560,8 +560,6 @@ tau = 2 * pi
# ------- Functions
## Convert a number to a [Str].
##
## This is the same as calling `Num.format {}` - so for more details on
## exact formatting, see `Num.format`.
## ```
## Num.toStr 42
## ```
@ -573,7 +571,6 @@ tau = 2 * pi
## When this function is given a non-[finite](Num.isFinite)
## [F64] or [F32] value, the returned string will be `"NaN"`, `"∞"`, or `"-∞"`.
##
## To get strings in hexadecimal, octal, or binary format, use `Num.format`.
toStr : Num * -> Str
intCast : Int a -> Int b

View file

@ -30,12 +30,25 @@ pub fn call_bitcode_fn<'ctx>(
args: &[BasicValueEnum<'ctx>],
fn_name: &str,
) -> BasicValueEnum<'ctx> {
call_bitcode_fn_help(env, args, fn_name)
let ret = call_bitcode_fn_help(env, args, fn_name)
.try_as_basic_value()
.left()
.unwrap_or_else(|| {
panic!("LLVM error: Did not get return value from bitcode function {fn_name:?}")
})
});
if env.target_info.operating_system == roc_target::OperatingSystem::Windows {
// On windows zig uses a vector type <2xi64> instead of a i128 value
let vec_type = env.context.i64_type().vec_type(2);
if ret.get_type() == vec_type.into() {
return env
.builder
.build_bitcast(ret, env.context.i128_type(), "return_i128")
.unwrap();
}
}
ret
}
pub fn call_void_bitcode_fn<'ctx>(
@ -54,7 +67,35 @@ fn call_bitcode_fn_help<'ctx>(
args: &[BasicValueEnum<'ctx>],
fn_name: &str,
) -> CallSiteValue<'ctx> {
let it = args.iter().map(|x| (*x).into());
let it = args
.iter()
.map(|x| {
if env.target_info.operating_system == roc_target::OperatingSystem::Windows {
if x.get_type() == env.context.i128_type().into() {
let parent = env
.builder
.get_insert_block()
.and_then(|b| b.get_parent())
.unwrap();
let alloca = create_entry_block_alloca(
env,
parent,
x.get_type(),
"pass_u128_by_reference",
);
env.builder.build_store(alloca, *x).unwrap();
alloca.into()
} else {
*x
}
} else {
*x
}
})
.map(|x| (x).into());
let arguments = bumpalo::collections::Vec::from_iter_in(it, env.arena);
let fn_val = env

View file

@ -1067,11 +1067,42 @@ pub fn module_from_builtins<'ctx>(
// Also, must_keep is the functions we depend on that would normally be provide by libc.
// They are magically linked to by llvm builtins, so we must specify that they can't be DCE'd.
let must_keep = ["_fltused", "floorf", "memcpy", "memset"];
let must_keep = [
"_fltused",
"floorf",
"memcpy",
"memset",
// I have no idea why this function is special.
// Without it, some tests hang on M1 mac outside of nix.
"__muloti4",
// fixes `Undefined Symbol in relocation`
"__udivti3",
// Roc special functions
"__roc_force_longjmp",
"__roc_force_setjmp",
"set_shared_buffer",
];
for func in module.get_functions() {
let has_definition = func.count_basic_blocks() > 0;
let name = func.get_name().to_string_lossy();
if has_definition && !must_keep.contains(&name.as_ref()) {
if has_definition
&& !name.starts_with("roc_builtins.")
&& !must_keep.contains(&name.as_ref())
{
func.set_linkage(Linkage::Private);
}
}
// Note, running DCE here is faster then waiting until full app DCE.
let mpm = PassManager::create(());
mpm.add_global_dce_pass();
mpm.run_on(&module);
// Now that the unused compiler-rt functions have been removed,
// mark that the builtin functions are allowed to be DCE'd if they aren't used.
for func in module.get_functions() {
let name = func.get_name().to_string_lossy();
if name.starts_with("roc_builtins.") {
func.set_linkage(Linkage::Private);
}
}

View file

@ -1100,13 +1100,22 @@ pub(crate) fn run_low_level<'a, 'ctx>(
NumBytesToU128 => {
arguments!(list, position);
call_list_bitcode_fn(
let ret = call_list_bitcode_fn(
env,
&[list.into_struct_value()],
&[position],
BitcodeReturns::Basic,
bitcode::NUM_BYTES_TO_U128,
)
);
if env.target_info.operating_system == roc_target::OperatingSystem::Windows {
// On windows the return type is not a i128, likely due to alignment
env.builder
.build_bitcast(ret, env.context.i128_type(), "empty_string")
.unwrap()
} else {
ret
}
}
NumCompare => {
arguments_with_layouts!((lhs_arg, lhs_layout), (rhs_arg, rhs_layout));
@ -2596,7 +2605,16 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
}
}
PtrWidth::Bytes8 => {
if target_int_width.stack_size() as usize > env.target_info.ptr_size() {
let return_by_pointer = {
if env.target_info.operating_system
== roc_target::OperatingSystem::Windows
{
target_int_width.stack_size() as usize >= env.target_info.ptr_size()
} else {
target_int_width.stack_size() as usize > env.target_info.ptr_size()
}
};
if return_by_pointer {
let bitcode_return_type =
zig_to_int_checked_result_type(env, target_int_width.type_name());

View file

@ -684,6 +684,7 @@ impl MakeSpecializationsPass {
struct State<'a> {
pub root_id: ModuleId,
pub root_subs: Option<Subs>,
pub root_path: PathBuf,
pub cache_dir: PathBuf,
/// If the root is an app module, the shorthand specified in its header's `to` field
pub opt_platform_shorthand: Option<&'a str>,
@ -752,6 +753,7 @@ impl<'a> State<'a> {
fn new(
root_id: ModuleId,
root_path: PathBuf,
opt_platform_shorthand: Option<&'a str>,
target_info: TargetInfo,
function_kind: FunctionKind,
@ -770,6 +772,7 @@ impl<'a> State<'a> {
Self {
root_id,
root_path,
root_subs: None,
opt_platform_shorthand,
cache_dir,
@ -1077,8 +1080,9 @@ pub struct LoadStart<'a> {
arc_modules: Arc<Mutex<PackageModuleIds<'a>>>,
ident_ids_by_module: SharedIdentIdsByModule,
root_id: ModuleId,
opt_platform_shorthand: Option<&'a str>,
root_path: PathBuf,
root_msg: Msg<'a>,
opt_platform_shorthand: Option<&'a str>,
src_dir: PathBuf,
}
@ -1101,7 +1105,7 @@ impl<'a> LoadStart<'a> {
let res_loaded = load_filename(
arena,
filename,
filename.clone(),
true,
None,
None,
@ -1136,6 +1140,7 @@ impl<'a> LoadStart<'a> {
ident_ids_by_module,
src_dir,
root_id: header_output.module_id,
root_path: filename,
root_msg: header_output.msg,
opt_platform_shorthand: header_output.opt_platform_shorthand,
})
@ -1162,7 +1167,7 @@ impl<'a> LoadStart<'a> {
let header_output = load_from_str(
arena,
filename,
filename.clone(),
src,
Arc::clone(&arc_modules),
Arc::clone(&ident_ids_by_module),
@ -1178,6 +1183,7 @@ impl<'a> LoadStart<'a> {
src_dir,
ident_ids_by_module,
root_id,
root_path: filename,
root_msg,
opt_platform_shorthand: opt_platform_id,
})
@ -1352,6 +1358,7 @@ pub fn load_single_threaded<'a>(
arc_modules,
ident_ids_by_module,
root_id,
root_path,
root_msg,
src_dir,
opt_platform_shorthand,
@ -1367,6 +1374,7 @@ pub fn load_single_threaded<'a>(
let number_of_workers = 1;
let mut state = State::new(
root_id,
root_path,
opt_platform_shorthand,
target_info,
function_kind,
@ -1503,7 +1511,7 @@ fn state_thread_step<'a>(
Ok(ControlFlow::Break(LoadResult::Monomorphized(monomorphized)))
}
Msg::FailedToReadFile { filename, error } => {
let buf = to_file_problem_report_string(&filename, error);
let buf = to_file_problem_report_string(filename, error);
Err(LoadingProblem::FormattedReport(buf))
}
@ -1654,7 +1662,7 @@ pub fn report_loading_problem(
}
LoadingProblem::FormattedReport(report) => report,
LoadingProblem::FileProblem { filename, error } => {
to_file_problem_report_string(&filename, error)
to_file_problem_report_string(filename, error)
}
err => todo!("Loading error: {:?}", err),
}
@ -1677,6 +1685,7 @@ fn load_multi_threaded<'a>(
arc_modules,
ident_ids_by_module,
root_id,
root_path,
root_msg,
src_dir,
opt_platform_shorthand,
@ -1707,6 +1716,7 @@ fn load_multi_threaded<'a>(
let mut state = State::new(
root_id,
root_path,
opt_platform_shorthand,
target_info,
function_kind,
@ -2238,6 +2248,7 @@ fn update<'a>(
let buf = to_https_problem_report_string(
url,
Problem::InvalidUrl(url_err),
header.module_path,
);
return Err(LoadingProblem::FormattedReport(buf));
}
@ -3159,7 +3170,7 @@ fn finish_specialization<'a>(
}
Valid(To::NewPackage(p_or_p)) => PathBuf::from(p_or_p.as_str()),
other => {
let buf = to_missing_platform_report(state.root_id, other);
let buf = report_cannot_run(state.root_id, state.root_path, other);
return Err(LoadingProblem::FormattedReport(buf));
}
};
@ -3513,9 +3524,7 @@ fn load_builtin_module_help<'a>(
) -> (HeaderInfo<'a>, roc_parse::state::State<'a>) {
let is_root_module = false;
let opt_shorthand = None;
let filename = PathBuf::from(filename);
let parse_state = roc_parse::state::State::new(src_bytes.as_bytes());
let parsed = roc_parse::module::parse_header(arena, parse_state.clone());
@ -3968,6 +3977,7 @@ fn parse_header<'a>(
module_timing,
)?;
let filename = resolved_header.module_path.clone();
let mut messages = Vec::with_capacity(packages.len() + 1);
// It's important that the app header is first in the list!
@ -3982,6 +3992,7 @@ fn parse_header<'a>(
module_id,
module_ids,
ident_ids_by_module,
filename,
);
// Look at the app module's `to` keyword to determine which package was the platform.
@ -4084,6 +4095,7 @@ fn load_packages<'a>(
module_id: ModuleId,
module_ids: Arc<Mutex<PackageModuleIds<'a>>>,
ident_ids_by_module: SharedIdentIdsByModule,
filename: PathBuf,
) {
// Load all the packages
for Loc { value: entry, .. } in packages.iter() {
@ -4121,7 +4133,7 @@ fn load_packages<'a>(
}
}
Err(problem) => {
let buf = to_https_problem_report_string(src, problem);
let buf = to_https_problem_report_string(src, problem, filename);
load_messages.push(Msg::FailedToLoad(LoadingProblem::FormattedReport(buf)));
return;
@ -6581,7 +6593,11 @@ fn to_parse_problem_report<'a>(
buf
}
fn to_missing_platform_report(module_id: ModuleId, other: &PlatformPath) -> String {
fn report_cannot_run(
module_id: ModuleId,
filename: PathBuf,
platform_path: &PlatformPath,
) -> String {
use roc_reporting::report::{Report, RocDocAllocator, DEFAULT_PALETTE};
use ven_pretty::DocAllocator;
use PlatformPath::*;
@ -6591,20 +6607,20 @@ fn to_missing_platform_report(module_id: ModuleId, other: &PlatformPath) -> Stri
let alloc = RocDocAllocator::new(&[], module_id, &interns);
let report = {
match other {
match platform_path {
Valid(_) => unreachable!(),
NotSpecified => {
let doc = alloc.stack([
alloc.reflow("I could not find a platform based on your input file."),
alloc.reflow(r"Does the module header contain an entry that looks like this:"),
alloc.reflow(r"Does the module header have an entry that looks like this?"),
alloc
.parser_suggestion(" packages { pf: \"platform\" }")
.parser_suggestion("packages { blah: \"…path or URL to platform…\" }")
.indent(4),
alloc.reflow("See also TODO."),
alloc.reflow("Tip: The following part of the tutorial has an example of specifying a platform:\n\n<https://www.roc-lang.org/tutorial#building-an-application>"),
]);
Report {
filename: "UNKNOWN.roc".into(),
filename,
doc,
title: "NO PLATFORM".to_string(),
severity: Severity::RuntimeError,
@ -6619,7 +6635,7 @@ fn to_missing_platform_report(module_id: ModuleId, other: &PlatformPath) -> Stri
]);
Report {
filename: "UNKNOWN.roc".into(),
filename,
doc,
title: "NO PLATFORM".to_string(),
severity: Severity::RuntimeError,
@ -6634,7 +6650,7 @@ fn to_missing_platform_report(module_id: ModuleId, other: &PlatformPath) -> Stri
]);
Report {
filename: "UNKNOWN.roc".into(),
filename,
doc,
title: "NO PLATFORM".to_string(),
severity: Severity::RuntimeError,
@ -6649,7 +6665,7 @@ fn to_missing_platform_report(module_id: ModuleId, other: &PlatformPath) -> Stri
]);
Report {
filename: "UNKNOWN.roc".into(),
filename,
doc,
title: "NO PLATFORM".to_string(),
severity: Severity::RuntimeError,

View file

@ -234,7 +234,19 @@ fn verify_procedures<'a>(
if !has_changes.stdout.is_empty() {
println!("{}", std::str::from_utf8(&has_changes.stdout).unwrap());
panic!("Output changed: resolve conflicts and `git add` the file.");
panic!(indoc!(
r#"
Mono output has changed! This is normal when making changes to the builtins.
To fix it; run these commands locally:
cargo test -p test_mono -p uitest --no-fail-fast
git add -u
git commit -S -m "update mono tests"
git push origin YOUR_BRANCH_NAME
"#
));
}
}

View file

@ -1090,7 +1090,7 @@ pub fn can_problem<'b>(
title = "OVERAPPLIED CRASH".to_string();
}
Problem::FileProblem { filename, error } => {
let report = to_file_problem_report(alloc, &filename, error);
let report = to_file_problem_report(alloc, filename, error);
doc = report.doc;
title = report.title;
}

View file

@ -1101,7 +1101,11 @@ where
}
#[cfg(not(target_family = "wasm"))]
pub fn to_https_problem_report_string(url: &str, https_problem: Problem) -> String {
pub fn to_https_problem_report_string(
url: &str,
https_problem: Problem,
filename: PathBuf,
) -> String {
let src_lines: Vec<&str> = Vec::new();
let mut module_ids = ModuleIds::default();
@ -1115,7 +1119,7 @@ pub fn to_https_problem_report_string(url: &str, https_problem: Problem) -> Stri
let mut buf = String::new();
let palette = DEFAULT_PALETTE;
let report = to_https_problem_report(&alloc, url, https_problem);
let report = to_https_problem_report(&alloc, url, https_problem, filename);
report.render_color_terminal(&mut buf, &alloc, &palette);
buf
@ -1126,6 +1130,7 @@ pub fn to_https_problem_report<'b>(
alloc: &'b RocDocAllocator<'b>,
url: &'b str,
https_problem: Problem,
filename: PathBuf,
) -> Report<'b> {
match https_problem {
Problem::UnsupportedEncoding(not_supported_encoding) => {
@ -1154,7 +1159,7 @@ pub fn to_https_problem_report<'b>(
]);
Report {
filename: "UNKNOWN.roc".into(),
filename,
doc,
title: "UNSUPPORTED ENCODING".to_string(),
severity: Severity::Fatal,
@ -1189,7 +1194,7 @@ pub fn to_https_problem_report<'b>(
]);
Report {
filename: "UNKNOWN.roc".into(),
filename,
doc,
title: "MULTIPLE ENCODINGS".to_string(),
severity: Severity::Fatal,
@ -1224,7 +1229,7 @@ pub fn to_https_problem_report<'b>(
]);
Report {
filename: "UNKNOWN.roc".into(),
filename,
doc,
title: "INVALID CONTENT HASH".to_string(),
severity: Severity::Fatal,
@ -1241,7 +1246,7 @@ pub fn to_https_problem_report<'b>(
alloc.concat([alloc.tip(), alloc.reflow(r"Is the URL correct?")]),
]);
Report {
filename: "UNKNOWN.roc".into(),
filename,
doc,
title: "NOTFOUND".to_string(),
severity: Severity::Fatal,
@ -1268,7 +1273,7 @@ pub fn to_https_problem_report<'b>(
]);
Report {
filename: "UNKNOWN.roc".into(),
filename,
doc,
title: "IO ERROR".to_string(),
severity: Severity::Fatal,
@ -1295,7 +1300,7 @@ pub fn to_https_problem_report<'b>(
]);
Report {
filename: "UNKNOWN.roc".into(),
filename,
doc,
title: "IO ERROR".to_string(),
severity: Severity::Fatal,
@ -1324,7 +1329,7 @@ pub fn to_https_problem_report<'b>(
]);
Report {
filename: "UNKNOWN.roc".into(),
filename,
doc,
title: "HTTP ERROR".to_string(),
severity: Severity::Fatal,
@ -1365,7 +1370,7 @@ pub fn to_https_problem_report<'b>(
]);
Report {
filename: "UNKNOWN.roc".into(),
filename,
doc,
title: "INVALID EXTENSION SUFFIX".to_string(),
severity: Severity::Fatal,
@ -1398,7 +1403,7 @@ pub fn to_https_problem_report<'b>(
]);
Report {
filename: "UNKNOWN.roc".into(),
filename,
doc,
title: "INVALID EXTENSION".to_string(),
severity: Severity::Fatal,
@ -1436,7 +1441,7 @@ pub fn to_https_problem_report<'b>(
]);
Report {
filename: "UNKNOWN.roc".into(),
filename,
doc,
title: "INVALID FRAGMENT".to_string(),
severity: Severity::Fatal,
@ -1474,7 +1479,7 @@ pub fn to_https_problem_report<'b>(
]);
Report {
filename: "UNKNOWN.roc".into(),
filename,
doc,
title: "MISSING PACKAGE HASH".to_string(),
severity: Severity::Fatal,
@ -1500,7 +1505,7 @@ pub fn to_https_problem_report<'b>(
]);
Report {
filename: "UNKNOWN.roc".into(),
filename,
doc,
title: "HTTPS MANDATORY".to_string(),
severity: Severity::Fatal,
@ -1543,7 +1548,7 @@ pub fn to_https_problem_report<'b>(
]);
Report {
filename: "UNKNOWN.roc".into(),
filename,
doc,
title: "MISLEADING CHARACTERS".to_string(),
severity: Severity::Fatal,
@ -1573,7 +1578,7 @@ pub fn to_https_problem_report<'b>(
]);
Report {
filename: "UNKNOWN.roc".into(),
filename,
doc,
title: "FILE TOO LARGE".to_string(),
severity: Severity::Fatal,
@ -1582,13 +1587,10 @@ pub fn to_https_problem_report<'b>(
}
}
pub fn to_file_problem_report_string(filename: &Path, error: io::ErrorKind) -> String {
pub fn to_file_problem_report_string(filename: PathBuf, error: io::ErrorKind) -> String {
let src_lines: Vec<&str> = Vec::new();
let mut module_ids = ModuleIds::default();
let module_id = module_ids.get_or_insert(&"find module name somehow?".into());
let interns = Interns::default();
// Report parsing and canonicalization problems
@ -1604,16 +1606,16 @@ pub fn to_file_problem_report_string(filename: &Path, error: io::ErrorKind) -> S
pub fn to_file_problem_report<'b>(
alloc: &'b RocDocAllocator<'b>,
filename: &Path,
filename: PathBuf,
error: io::ErrorKind,
) -> Report<'b> {
let filename: String = filename.to_str().unwrap().to_string();
let filename_str: String = filename.to_str().unwrap().to_string();
match error {
io::ErrorKind::NotFound => {
let doc = alloc.stack([
alloc.reflow(r"I am looking for this file, but it's not there:"),
alloc
.string(filename)
.string(filename_str)
.annotate(Annotation::ParserSuggestion)
.indent(4),
alloc.concat([
@ -1623,7 +1625,7 @@ pub fn to_file_problem_report<'b>(
]);
Report {
filename: "UNKNOWN.roc".into(),
filename,
doc,
title: "FILE NOT FOUND".to_string(),
severity: Severity::Fatal,
@ -1633,7 +1635,7 @@ pub fn to_file_problem_report<'b>(
let doc = alloc.stack([
alloc.reflow(r"I don't have the required permissions to read this file:"),
alloc
.string(filename)
.string(filename_str)
.annotate(Annotation::ParserSuggestion)
.indent(4),
alloc
@ -1641,7 +1643,7 @@ pub fn to_file_problem_report<'b>(
]);
Report {
filename: "UNKNOWN.roc".into(),
filename,
doc,
title: "FILE PERMISSION DENIED".to_string(),
severity: Severity::Fatal,
@ -1652,13 +1654,16 @@ pub fn to_file_problem_report<'b>(
let formatted = format!("{error}");
let doc = alloc.stack([
alloc.reflow(r"I tried to read this file:"),
alloc.string(filename).annotate(Annotation::Error).indent(4),
alloc
.string(filename_str)
.annotate(Annotation::Error)
.indent(4),
alloc.reflow(r"But ran into:"),
alloc.text(formatted).annotate(Annotation::Error).indent(4),
]);
Report {
filename: "UNKNOWN.roc".into(),
filename,
doc,
title: "FILE PROBLEM".to_string(),
severity: Severity::Fatal,

View file

@ -27,11 +27,16 @@
};
outputs = { self, nixpkgs, rust-overlay, flake-utils, nixgl, ... }@inputs:
let supportedSystems = [ "x86_64-linux" "x86_64-darwin" "aarch64-darwin" "aarch64-linux" ];
in flake-utils.lib.eachSystem supportedSystems (system:
let
supportedSystems = [ "x86_64-linux" "x86_64-darwin" "aarch64-darwin" "aarch64-linux" ];
templates = import ./nix/templates { };
in
{ inherit templates; } //
flake-utils.lib.eachSystem supportedSystems (system:
let
overlays = [ (import rust-overlay) ]
++ (if system == "x86_64-linux" then [ nixgl.overlay ] else [ ]);
++ (if system == "x86_64-linux" then [ nixgl.overlay ] else [ ]);
pkgs = import nixpkgs { inherit system overlays; };
rocBuild = import ./nix { inherit pkgs; };
@ -105,7 +110,7 @@
devShell = pkgs.mkShell {
buildInputs = sharedInputs ++ sharedDevInputs ++ darwinInputs ++ darwinDevInputs ++ linuxDevInputs
++ (if system == "x86_64-linux" then
++ (if system == "x86_64-linux" then
[ pkgs.nixgl.nixVulkanIntel ]
else
[ ]);
@ -121,7 +126,7 @@
LD_LIBRARY_PATH = with pkgs;
lib.makeLibraryPath
([ pkg-config stdenv.cc.cc.lib libffi ncurses zlib ]
++ linuxDevInputs);
++ linuxDevInputs);
NIXPKGS_ALLOW_UNFREE =
1; # to run the GUI examples with NVIDIA's closed source drivers
@ -143,5 +148,12 @@
cli = rocBuild.roc-cli;
lang-server = rocBuild.roc-lang-server;
};
apps = {
default = {
type = "app";
program = "${rocBuild.roc-cli}/bin/roc";
};
};
});
}

View file

@ -6,11 +6,12 @@ play around with as long as you have a tolerance for missing features and compil
The [tutorial](https://roc-lang.org/tutorial) is the best place to learn about how to use the language - it assumes no prior knowledge of Roc or similar languages. (If you already know [Elm](https://elm-lang.org/), then [Roc for Elm Programmers](https://github.com/roc-lang/roc/blob/main/roc-for-elm-programmers.md) may be of interest.)
If you have a specific question, the [FAQ](../FAQ.md) might have an answer, although [Roc Zulip chat](https://roc.zulipchat.com) is overall the best place to ask questions and get help! It's also where we discuss [ideas](https://roc.zulipchat.com/#narrow/stream/304641-ideas) for the language. If you want to get involved in contributing to the language, Zulip is also a great place to ask about good first projects.
If you have a specific question, the [FAQ](../www/content/faq.md) might have an answer, although [Roc Zulip chat](https://roc.zulipchat.com) is overall the best place to ask questions and get help! It's also where we discuss [ideas](https://roc.zulipchat.com/#narrow/stream/304641-ideas) for the language. If you want to get involved in contributing to the language, Zulip is also a great place to ask about good first projects.
## Installation
- [🐧 Linux x86_64](linux_x86_64.md)
- [❄️ Nix Linux/MacOS](nix.md)
- [🍏 MacOS Apple Silicon](macos_apple_silicon.md)
- [🍏 MacOS x86_64](macos_x86_64.md)
- [🟦 Windows](windows.md)

48
getting_started/nix.md Normal file
View file

@ -0,0 +1,48 @@
## Try out
To quickly try out roc without installing, use `nix run`:
```shell
nix run roc-lang/roc -- <roc args>
# examples:
# - nix run roc-lang/roc -- repl
# - nix run roc-lang/roc -- dev main.roc
```
## Use with Flakes
### Start your project with our template
```shell
# use the template in the current directory
nix flake init --template github:roc-lang/roc#simple --refresh
```
### Add roc to existing flake
```nix
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
roc.url = "github:roc-lang/roc";
};
outputs = {nixpkgs, roc, flake-utils, ...}:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs { inherit system; };
rocPkgs = roc.packages.${system};
in
{
devShells = {
default = pkgs.mkShell {
buildInputs = with pkgs;
[
rocPkgs.cli
];
};
};
}
);
}
```

View file

@ -3,6 +3,8 @@ let
inherit (compile-deps) zigPkg llvmPkgs llvmVersion llvmMajorMinorStr glibcPath libGccSPath;
subPackagePath = if subPackage != null then "crates/${subPackage}" else null;
mainBin = if subPackage == "lang_srv" then "roc_ls" else "roc";
in
rustPlatform.buildRustPackage {
pname = "roc" + lib.optionalString (subPackage != null) "_${subPackage}";
@ -84,4 +86,11 @@ rustPlatform.buildRustPackage {
${wrapRoc}
fi
'';
# https://ryantm.github.io/nixpkgs/stdenv/meta/
meta = {
homepage = "https://www.roc-lang.org/";
license = lib.licenses.upl;
mainProgram = mainBin;
};
}

View file

@ -0,0 +1,7 @@
{ ... }: rec {
default = simple;
simple = {
description = "Basic flake with roc cli + lsp";
path = ./simple;
};
}

View file

@ -0,0 +1,38 @@
{
description = "Roc flake template";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
roc.url = "github:roc-lang/roc";
};
outputs = { self, nixpkgs, flake-utils, roc, ... }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs { inherit system; };
# see "packages =" in https://github.com/roc-lang/roc/blob/main/flake.nix
rocPkgs = roc.packages.${system};
rocFull = rocPkgs.full;
in
{
formatter = pkgs.nixpkgs-fmt;
devShells = {
default = pkgs.mkShell {
buildInputs = with pkgs;
[
rocFull # includes CLI
];
# For vscode plugin https://github.com/ivan-demchenko/roc-vscode-unofficial
shellHook = ''
export ROC_LSP_PATH=${rocFull}/bin/roc_ls
'';
};
};
});
}

View file

@ -1,4 +1,3 @@
# Documentation
- [builtins](/builtins) - docs for modules built into the language—`Str`, `Num`, etc.
@ -10,7 +9,7 @@ In the future, a language reference will be on this page too.
## [Guides](#guides) {#guides}
- [Frequently Asked Questions](https://github.com/roc-lang/roc/blob/main/FAQ.md)
- [Frequently Asked Questions](https://www.roc-lang.org/faq.html)
- [Roc for Elm Programmers](https://github.com/roc-lang/roc/blob/main/roc-for-elm-programmers.md)
- [Tutorial](/tutorial)

View file

@ -1,14 +1,16 @@
Click the ☰ button in the top left to see and search the table of contents.
# Frequently Asked Questions
## Where did the name Roc come from?
<img width="128" alt="The Roc logo, an origami bird" src="https://user-images.githubusercontent.com/1094080/92188927-e61ebd00-ee2b-11ea-97ef-2fc88e0094b0.png">
The Roc programming language is named after [a mythical bird](<https://en.wikipedia.org/wiki/Roc_(mythology)>).
Thats why the logo is a bird. Its specifically an [_origami_ bird](https://youtu.be/9gni1t1k1uY) as an homage
<svg viewBox="0 0 52 53" xmlns="http://www.w3.org/2000/svg">
<!-- Make this icon look nicer in dark mode. (Only Firefox supports this; others ignore it.) -->
<style>@media (prefers-color-scheme: dark){polygon{fill:#9c7bea}}</style>
<polygon fill="#7d59dd" points="0,0 23.8834,3.21052 37.2438,19.0101 45.9665,16.6324 50.5,22 45,22 44.0315,26.3689 26.4673,39.3424 27.4527,45.2132 17.655,53 23.6751,22.7086"/>
</svg>
That's why the logo is a bird. Its specifically an [_origami_ bird](https://youtu.be/9gni1t1k1uY) as an homage
to [Elm](https://elm-lang.org/)s tangram logo.
Roc is a direct descendant of Elm. The languages are similar, but not the same.
@ -55,8 +57,10 @@ Both of these would make revising code riskier across the entire language, which
Another option would be to define that function equality always returns `false`. So both of these would evaluate
to `false`:
- `(\x -> x + 1) == (\x -> 1 + x)`
- `(\x -> x + 1) == (\x -> x + 1)`
```roc
(\x -> x + 1) == (\x -> 1 + x) #false
(\x -> x + 1) == (\x -> x + 1) #false
```
This makes function equality effectively useless, while still technically allowing it. It has some other downsides:
@ -252,11 +256,11 @@ the downsides.
In Roc, both of these expressions evaluate to `"Hello, World!"`
```elixir
```roc
Str.concat "Hello, " "World!"
```
```elixir
```roc
"Hello, "
|> Str.concat "World!"
```
@ -273,12 +277,12 @@ In Roc, both expressions evaluate to the same thing because Roc's `|>` operator
This comes up in other situations besides string concatenation. For example, consider subtraction and division:
```elixir
```roc
someNumber
|> Num.div 2
```
```elixir
```roc
someNumber
|> Num.sub 1
```
@ -292,7 +296,7 @@ experienced users.
The way `|>` works in Roc has a second benefit when it comes to higher-order functions. Consider these two examples:
```elixir
```roc
answer = List.map numbers \num ->
someFunction
"some argument"
@ -300,7 +304,7 @@ answer = List.map numbers \num ->
anotherArg
```
```elixir
```roc
numbers
|> List.map Num.abs
```
@ -311,7 +315,7 @@ In a curried language, these two examples couldn't both be valid. In order for `
This means the first example would have to change from this...
```elixir
```roc
answer = List.map numbers \num ->
someFunction
"some argument"
@ -321,7 +325,7 @@ answer = List.map numbers \num ->
...to this:
```elixir
```roc
answer =
List.map
(\num ->
@ -370,7 +374,7 @@ And however easy Roc would be to learn if it had currying, the language is certa
a new function by composing together two existing functions without naming intermediate arguments.
Here's an example:
```elm
```roc
reverseSort : List elem -> List elem
reverseSort = compose List.reverse List.sort
@ -380,7 +384,7 @@ compose = \f, g, x -> f (g x)
Here's a way to write it without pointfree function composition:
```elm
```roc
reverseSort : List elem -> List elem
reverseSort = \list -> List.reverse (List.sort list)
```
@ -443,7 +447,3 @@ There were a few reasons for this rewrite.
4. Zig has more tools for working in a memory-unsafe environment, such as reporting memory leaks in tests. These have been helpful in finding bugs that are out of scope for safe Rust.
The split of Rust for the compiler and Zig for the standard library has worked well so far, and there are no plans to change it.
## Why is the website so basic?
We have a very basic website on purpose, it helps set expectations that roc is a work in progress and not ready yet for a first release.

View file

@ -5,7 +5,7 @@ Roc is a very young language with many incomplete features and known bugs. It do
There are currently a few known OS-specific issues:
* **macOS:** There are no known compatibility issues, but the compiler doesn't run as fast as it does on Linux or Windows, because we don't (yet) do our own linking like we do on those targets. (Linking works similarly on Linux and Windows, but the way macOS does it is both different and significantly more complicated.)
* **Windows:** There are some known Windows-specific compiler bugs, and probably some other unknown ones because more people have tried out Roc on Mac and Linux than on Windows.
* **Linux:** The nightlies are built with glibc, so they aren't usable on distros that don't use (dynamically linked) glibc, like Alpine or NixOS. In the future we plan to build Linux releases with [musl libc](https://wiki.musl-libc.org/) to address this, but this requires [building LLVM from source with musl](https://wiki.musl-libc.org/building-llvm.html).
* **Linux:** The nightlies are built with glibc, so they aren't usable on distros that don't use glibc, like Alpine. In the future we plan to build Linux releases with [musl libc](https://wiki.musl-libc.org/) to address this, but this requires [building LLVM from source with musl](https://wiki.musl-libc.org/building-llvm.html).
* **Other operating systems:** Roc has not been built on any other operating systems. [Building from source](https://github.com/roc-lang/roc/blob/main/BUILDING_FROM_SOURCE.md) on another OS might work, but you might very well be the first person ever to try it!
### [Getting Started](#getting-started) {#getting-started}
@ -14,6 +14,7 @@ Here are some Getting Started guides for different operating systems:
<!-- TODO detect current OS with browser and only show link for that, provide other button for others -->
- [Linux x86-64](https://github.com/roc-lang/roc/blob/main/getting_started/linux_x86_64.md)
- [Nix Linux/MacOS](https://github.com/roc-lang/roc/blob/main/getting_started/nix.md)
- [MacOS Apple Silicon](https://github.com/roc-lang/roc/blob/main/getting_started/macos_apple_silicon.md)
- [MacOS x86-64](https://github.com/roc-lang/roc/blob/main/getting_started/macos_x86_64.md)
- [Windows](https://github.com/roc-lang/roc/blob/main/getting_started/windows.md)

View file

@ -2076,8 +2076,8 @@ Here are various Roc expressions involving operators, and what they desugar to.
| `a && b` | `Bool.and a b` |
| <code>a \|\| b</code> | `Bool.or a b` |
| `!a` | `Bool.not a` |
| <code>a \|> b</code> | `b a` |
| <code>a b c \|> f x y</code> | `f (a b c) x y` |
| <code>a \|> f</code> | `f a` |
| <code>f a b \|> g x y</code> | `g (f a b) x y` |
</section>