mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 08:11:12 +00:00
Merge branch 'trunk' into fix-module-formatting
This commit is contained in:
commit
881bae7267
114 changed files with 4260 additions and 1986 deletions
|
@ -1,4 +1,4 @@
|
||||||
[alias]
|
[alias]
|
||||||
test-gen-llvm = "test -p test_gen"
|
test-gen-llvm = "test -p test_gen"
|
||||||
test-gen-dev = "test -p roc_gen_dev -p test_gen --no-default-features --features gen-dev"
|
test-gen-dev = "test -p roc_gen_dev -p test_gen --no-default-features --features gen-dev"
|
||||||
test-gen-wasm = "test -p test_gen --no-default-features --features gen-wasm"
|
test-gen-wasm = "test -p roc_gen_wasm -p test_gen --no-default-features --features gen-wasm"
|
||||||
|
|
36
Cargo.lock
generated
36
Cargo.lock
generated
|
@ -3204,6 +3204,17 @@ version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f1382d1f0a252c4bf97dc20d979a2fdd05b024acd7c2ed0f7595d7817666a157"
|
checksum = "f1382d1f0a252c4bf97dc20d979a2fdd05b024acd7c2ed0f7595d7817666a157"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "repl_test"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"indoc",
|
||||||
|
"roc_cli",
|
||||||
|
"roc_repl_cli",
|
||||||
|
"roc_test_utils",
|
||||||
|
"strip-ansi-escapes",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rkyv"
|
name = "rkyv"
|
||||||
version = "0.6.7"
|
version = "0.6.7"
|
||||||
|
@ -3669,14 +3680,20 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"const_format",
|
"const_format",
|
||||||
"indoc",
|
"inkwell 0.1.0",
|
||||||
|
"libloading 0.7.1",
|
||||||
|
"roc_build",
|
||||||
|
"roc_builtins",
|
||||||
|
"roc_collections",
|
||||||
|
"roc_gen_llvm",
|
||||||
|
"roc_load",
|
||||||
"roc_mono",
|
"roc_mono",
|
||||||
"roc_parse",
|
"roc_parse",
|
||||||
"roc_repl_eval",
|
"roc_repl_eval",
|
||||||
"roc_test_utils",
|
"roc_target",
|
||||||
|
"roc_types",
|
||||||
"rustyline",
|
"rustyline",
|
||||||
"rustyline-derive",
|
"rustyline-derive",
|
||||||
"strip-ansi-escapes",
|
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -3685,14 +3702,10 @@ name = "roc_repl_eval"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"inkwell 0.1.0",
|
|
||||||
"libloading 0.7.1",
|
|
||||||
"roc_build",
|
|
||||||
"roc_builtins",
|
"roc_builtins",
|
||||||
"roc_can",
|
"roc_can",
|
||||||
"roc_collections",
|
"roc_collections",
|
||||||
"roc_fmt",
|
"roc_fmt",
|
||||||
"roc_gen_llvm",
|
|
||||||
"roc_load",
|
"roc_load",
|
||||||
"roc_module",
|
"roc_module",
|
||||||
"roc_mono",
|
"roc_mono",
|
||||||
|
@ -3701,7 +3714,14 @@ dependencies = [
|
||||||
"roc_reporting",
|
"roc_reporting",
|
||||||
"roc_target",
|
"roc_target",
|
||||||
"roc_types",
|
"roc_types",
|
||||||
"target-lexicon",
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "roc_repl_wasm"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"roc_parse",
|
||||||
|
"roc_repl_eval",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -35,6 +35,8 @@ members = [
|
||||||
"reporting",
|
"reporting",
|
||||||
"repl_cli",
|
"repl_cli",
|
||||||
"repl_eval",
|
"repl_eval",
|
||||||
|
"repl_test",
|
||||||
|
"repl_wasm",
|
||||||
"roc_std",
|
"roc_std",
|
||||||
"test_utils",
|
"test_utils",
|
||||||
"utils",
|
"utils",
|
||||||
|
|
|
@ -47,7 +47,7 @@ install-zig-llvm-valgrind-clippy-rustfmt:
|
||||||
|
|
||||||
copy-dirs:
|
copy-dirs:
|
||||||
FROM +install-zig-llvm-valgrind-clippy-rustfmt
|
FROM +install-zig-llvm-valgrind-clippy-rustfmt
|
||||||
COPY --dir cli cli_utils compiler docs editor ast code_markup error_macros utils test_utils reporting repl_cli repl_eval roc_std vendor examples linker Cargo.toml Cargo.lock version.txt ./
|
COPY --dir cli cli_utils compiler docs editor ast code_markup error_macros utils test_utils reporting repl_cli repl_eval repl_test repl_wasm roc_std vendor examples linker Cargo.toml Cargo.lock version.txt ./
|
||||||
|
|
||||||
test-zig:
|
test-zig:
|
||||||
FROM +install-zig-llvm-valgrind-clippy-rustfmt
|
FROM +install-zig-llvm-valgrind-clippy-rustfmt
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_can::expr::Recursive;
|
use roc_can::expr::{IntValue, Recursive};
|
||||||
use roc_can::num::{finish_parsing_base, finish_parsing_float, finish_parsing_int};
|
use roc_can::num::{
|
||||||
|
finish_parsing_base, finish_parsing_float, finish_parsing_num, ParsedNumResult,
|
||||||
|
};
|
||||||
use roc_can::operator::desugar_expr;
|
use roc_can::operator::desugar_expr;
|
||||||
use roc_collections::all::MutSet;
|
use roc_collections::all::MutSet;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
|
@ -52,7 +54,7 @@ pub fn expr_to_expr2<'a>(
|
||||||
match parse_expr {
|
match parse_expr {
|
||||||
Float(string) => {
|
Float(string) => {
|
||||||
match finish_parsing_float(string) {
|
match finish_parsing_float(string) {
|
||||||
Ok(float) => {
|
Ok((float, _bound)) => {
|
||||||
let expr = Expr2::Float {
|
let expr = Expr2::Float {
|
||||||
number: FloatVal::F64(float),
|
number: FloatVal::F64(float),
|
||||||
var: env.var_store.fresh(),
|
var: env.var_store.fresh(),
|
||||||
|
@ -73,10 +75,13 @@ pub fn expr_to_expr2<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Num(string) => {
|
Num(string) => {
|
||||||
match finish_parsing_int(string) {
|
match finish_parsing_num(string) {
|
||||||
Ok(int) => {
|
Ok(ParsedNumResult::UnknownNum(int) | ParsedNumResult::Int(int, _)) => {
|
||||||
let expr = Expr2::SmallInt {
|
let expr = Expr2::SmallInt {
|
||||||
number: IntVal::I64(int),
|
number: IntVal::I64(match int {
|
||||||
|
IntValue::U128(_) => todo!(),
|
||||||
|
IntValue::I128(n) => n as i64, // FIXME
|
||||||
|
}),
|
||||||
var: env.var_store.fresh(),
|
var: env.var_store.fresh(),
|
||||||
// TODO non-hardcode
|
// TODO non-hardcode
|
||||||
style: IntStyle::Decimal,
|
style: IntStyle::Decimal,
|
||||||
|
@ -85,6 +90,15 @@ pub fn expr_to_expr2<'a>(
|
||||||
|
|
||||||
(expr, Output::default())
|
(expr, Output::default())
|
||||||
}
|
}
|
||||||
|
Ok(ParsedNumResult::Float(float, _)) => {
|
||||||
|
let expr = Expr2::Float {
|
||||||
|
number: FloatVal::F64(float),
|
||||||
|
var: env.var_store.fresh(),
|
||||||
|
text: PoolStr::new(string, env.pool),
|
||||||
|
};
|
||||||
|
|
||||||
|
(expr, Output::default())
|
||||||
|
}
|
||||||
Err((raw, error)) => {
|
Err((raw, error)) => {
|
||||||
// emit runtime error
|
// emit runtime error
|
||||||
let runtime_error = RuntimeError::InvalidInt(
|
let runtime_error = RuntimeError::InvalidInt(
|
||||||
|
@ -107,9 +121,12 @@ pub fn expr_to_expr2<'a>(
|
||||||
is_negative,
|
is_negative,
|
||||||
} => {
|
} => {
|
||||||
match finish_parsing_base(string, *base, *is_negative) {
|
match finish_parsing_base(string, *base, *is_negative) {
|
||||||
Ok(int) => {
|
Ok((int, _bound)) => {
|
||||||
let expr = Expr2::SmallInt {
|
let expr = Expr2::SmallInt {
|
||||||
number: IntVal::I64(int),
|
number: IntVal::I64(match int {
|
||||||
|
IntValue::U128(_) => todo!(),
|
||||||
|
IntValue::I128(n) => n as i64, // FIXME
|
||||||
|
}),
|
||||||
var: env.var_store.fresh(),
|
var: env.var_store.fresh(),
|
||||||
// TODO non-hardcode
|
// TODO non-hardcode
|
||||||
style: IntStyle::from_base(*base),
|
style: IntStyle::from_base(*base),
|
||||||
|
|
|
@ -3,8 +3,10 @@
|
||||||
#![allow(unused_imports)]
|
#![allow(unused_imports)]
|
||||||
|
|
||||||
use bumpalo::collections::Vec as BumpVec;
|
use bumpalo::collections::Vec as BumpVec;
|
||||||
use roc_can::expr::unescape_char;
|
use roc_can::expr::{unescape_char, IntValue};
|
||||||
use roc_can::num::{finish_parsing_base, finish_parsing_float, finish_parsing_int};
|
use roc_can::num::{
|
||||||
|
finish_parsing_base, finish_parsing_float, finish_parsing_num, ParsedNumResult,
|
||||||
|
};
|
||||||
use roc_collections::all::BumpMap;
|
use roc_collections::all::BumpMap;
|
||||||
use roc_module::symbol::{Interns, Symbol};
|
use roc_module::symbol::{Interns, Symbol};
|
||||||
use roc_parse::ast::{StrLiteral, StrSegment};
|
use roc_parse::ast::{StrLiteral, StrSegment};
|
||||||
|
@ -183,18 +185,35 @@ pub fn to_pattern2<'a>(
|
||||||
let problem = MalformedPatternProblem::MalformedFloat;
|
let problem = MalformedPatternProblem::MalformedFloat;
|
||||||
malformed_pattern(env, problem, region)
|
malformed_pattern(env, problem, region)
|
||||||
}
|
}
|
||||||
Ok(float) => Pattern2::FloatLiteral(FloatVal::F64(float)),
|
Ok((float, _bound)) => Pattern2::FloatLiteral(FloatVal::F64(float)),
|
||||||
},
|
},
|
||||||
ptype => unsupported_pattern(env, ptype, region),
|
ptype => unsupported_pattern(env, ptype, region),
|
||||||
},
|
},
|
||||||
|
|
||||||
NumLiteral(string) => match pattern_type {
|
NumLiteral(string) => match pattern_type {
|
||||||
WhenBranch => match finish_parsing_int(string) {
|
WhenBranch => match finish_parsing_num(string) {
|
||||||
Err(_error) => {
|
Err(_error) => {
|
||||||
let problem = MalformedPatternProblem::MalformedInt;
|
let problem = MalformedPatternProblem::MalformedInt;
|
||||||
malformed_pattern(env, problem, region)
|
malformed_pattern(env, problem, region)
|
||||||
}
|
}
|
||||||
Ok(int) => Pattern2::NumLiteral(env.var_store.fresh(), int),
|
Ok(ParsedNumResult::UnknownNum(int)) => {
|
||||||
|
Pattern2::NumLiteral(
|
||||||
|
env.var_store.fresh(),
|
||||||
|
match int {
|
||||||
|
IntValue::U128(_) => todo!(),
|
||||||
|
IntValue::I128(n) => n as i64, // FIXME
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Ok(ParsedNumResult::Int(int, _bound)) => {
|
||||||
|
Pattern2::IntLiteral(IntVal::I64(match int {
|
||||||
|
IntValue::U128(_) => todo!(),
|
||||||
|
IntValue::I128(n) => n as i64, // FIXME
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
Ok(ParsedNumResult::Float(int, _bound)) => {
|
||||||
|
Pattern2::FloatLiteral(FloatVal::F64(int))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
ptype => unsupported_pattern(env, ptype, region),
|
ptype => unsupported_pattern(env, ptype, region),
|
||||||
},
|
},
|
||||||
|
@ -209,7 +228,11 @@ pub fn to_pattern2<'a>(
|
||||||
let problem = MalformedPatternProblem::MalformedBase(*base);
|
let problem = MalformedPatternProblem::MalformedBase(*base);
|
||||||
malformed_pattern(env, problem, region)
|
malformed_pattern(env, problem, region)
|
||||||
}
|
}
|
||||||
Ok(int) => {
|
Ok((int, _bound)) => {
|
||||||
|
let int = match int {
|
||||||
|
IntValue::U128(_) => todo!(),
|
||||||
|
IntValue::I128(n) => n as i64, // FIXME
|
||||||
|
};
|
||||||
if *is_negative {
|
if *is_negative {
|
||||||
Pattern2::IntLiteral(IntVal::I64(-int))
|
Pattern2::IntLiteral(IntVal::I64(-int))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -12,8 +12,8 @@ use roc_parse::ast::{
|
||||||
TypeAnnotation, WhenBranch,
|
TypeAnnotation, WhenBranch,
|
||||||
};
|
};
|
||||||
use roc_parse::header::{
|
use roc_parse::header::{
|
||||||
AppHeader, Effects, ExposedName, HostedHeader, ImportsEntry, InterfaceHeader, ModuleName,
|
AppHeader, ExposedName, HostedHeader, ImportsEntry, InterfaceHeader, ModuleName, PackageEntry,
|
||||||
PackageEntry, PackageName, PlatformHeader, PlatformRequires, To, TypedIdent,
|
PackageName, PlatformHeader, PlatformRequires, To, TypedIdent,
|
||||||
};
|
};
|
||||||
use roc_parse::{
|
use roc_parse::{
|
||||||
ast::{Def, Module},
|
ast::{Def, Module},
|
||||||
|
@ -199,14 +199,6 @@ impl<'a> RemoveSpaces<'a> for Module<'a> {
|
||||||
packages: header.packages.remove_spaces(arena),
|
packages: header.packages.remove_spaces(arena),
|
||||||
imports: header.imports.remove_spaces(arena),
|
imports: header.imports.remove_spaces(arena),
|
||||||
provides: header.provides.remove_spaces(arena),
|
provides: header.provides.remove_spaces(arena),
|
||||||
effects: Effects {
|
|
||||||
spaces_before_effects_keyword: &[],
|
|
||||||
spaces_after_effects_keyword: &[],
|
|
||||||
spaces_after_type_name: &[],
|
|
||||||
effect_shortname: header.effects.effect_shortname.remove_spaces(arena),
|
|
||||||
effect_type_name: header.effects.effect_type_name.remove_spaces(arena),
|
|
||||||
entries: header.effects.entries.remove_spaces(arena),
|
|
||||||
},
|
|
||||||
before_header: &[],
|
before_header: &[],
|
||||||
after_platform_keyword: &[],
|
after_platform_keyword: &[],
|
||||||
before_requires: &[],
|
before_requires: &[],
|
||||||
|
|
|
@ -4,7 +4,6 @@ platform "examples/multi-module"
|
||||||
packages {}
|
packages {}
|
||||||
imports []
|
imports []
|
||||||
provides [ mainForHost ]
|
provides [ mainForHost ]
|
||||||
effects fx.Effect {}
|
|
||||||
|
|
||||||
mainForHost : Str
|
mainForHost : Str
|
||||||
mainForHost = main
|
mainForHost = main
|
||||||
|
|
|
@ -4,7 +4,6 @@ platform "examples/multi-dep-thunk"
|
||||||
packages {}
|
packages {}
|
||||||
imports []
|
imports []
|
||||||
provides [ mainForHost ]
|
provides [ mainForHost ]
|
||||||
effects fx.Effect {}
|
|
||||||
|
|
||||||
mainForHost : Str
|
mainForHost : Str
|
||||||
mainForHost = main
|
mainForHost = main
|
||||||
|
|
79
cli_utils/Cargo.lock
generated
79
cli_utils/Cargo.lock
generated
|
@ -2475,12 +2475,13 @@ dependencies = [
|
||||||
"roc_builtins",
|
"roc_builtins",
|
||||||
"roc_can",
|
"roc_can",
|
||||||
"roc_collections",
|
"roc_collections",
|
||||||
|
"roc_error_macros",
|
||||||
"roc_load",
|
"roc_load",
|
||||||
"roc_module",
|
"roc_module",
|
||||||
"roc_parse",
|
"roc_parse",
|
||||||
"roc_problem",
|
"roc_problem",
|
||||||
"roc_region",
|
"roc_region",
|
||||||
"roc_reporting",
|
"roc_target",
|
||||||
"roc_types",
|
"roc_types",
|
||||||
"roc_unify",
|
"roc_unify",
|
||||||
"snafu",
|
"snafu",
|
||||||
|
@ -2510,6 +2511,7 @@ dependencies = [
|
||||||
"roc_reporting",
|
"roc_reporting",
|
||||||
"roc_solve",
|
"roc_solve",
|
||||||
"roc_std",
|
"roc_std",
|
||||||
|
"roc_target",
|
||||||
"roc_types",
|
"roc_types",
|
||||||
"roc_unify",
|
"roc_unify",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -2524,6 +2526,7 @@ dependencies = [
|
||||||
"roc_collections",
|
"roc_collections",
|
||||||
"roc_module",
|
"roc_module",
|
||||||
"roc_region",
|
"roc_region",
|
||||||
|
"roc_target",
|
||||||
"roc_types",
|
"roc_types",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2549,31 +2552,24 @@ dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"clap 3.0.0-beta.5",
|
"clap 3.0.0-beta.5",
|
||||||
"const_format",
|
"const_format",
|
||||||
"inkwell 0.1.0",
|
|
||||||
"libloading 0.7.1",
|
|
||||||
"mimalloc",
|
"mimalloc",
|
||||||
"roc_build",
|
"roc_build",
|
||||||
"roc_builtins",
|
"roc_builtins",
|
||||||
"roc_can",
|
"roc_can",
|
||||||
"roc_collections",
|
"roc_collections",
|
||||||
"roc_constrain",
|
|
||||||
"roc_docs",
|
"roc_docs",
|
||||||
"roc_editor",
|
"roc_editor",
|
||||||
|
"roc_error_macros",
|
||||||
"roc_fmt",
|
"roc_fmt",
|
||||||
"roc_gen_llvm",
|
|
||||||
"roc_linker",
|
"roc_linker",
|
||||||
"roc_load",
|
"roc_load",
|
||||||
"roc_module",
|
"roc_module",
|
||||||
"roc_mono",
|
"roc_mono",
|
||||||
"roc_parse",
|
"roc_parse",
|
||||||
"roc_problem",
|
|
||||||
"roc_region",
|
"roc_region",
|
||||||
|
"roc_repl_cli",
|
||||||
"roc_reporting",
|
"roc_reporting",
|
||||||
"roc_solve",
|
"roc_target",
|
||||||
"roc_types",
|
|
||||||
"roc_unify",
|
|
||||||
"rustyline",
|
|
||||||
"rustyline-derive",
|
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
]
|
]
|
||||||
|
@ -2631,6 +2627,7 @@ dependencies = [
|
||||||
"roc_module",
|
"roc_module",
|
||||||
"roc_parse",
|
"roc_parse",
|
||||||
"roc_region",
|
"roc_region",
|
||||||
|
"roc_target",
|
||||||
"roc_types",
|
"roc_types",
|
||||||
"snafu",
|
"snafu",
|
||||||
]
|
]
|
||||||
|
@ -2680,6 +2677,10 @@ dependencies = [
|
||||||
"winit",
|
"winit",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "roc_error_macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "roc_fmt"
|
name = "roc_fmt"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -2700,12 +2701,13 @@ dependencies = [
|
||||||
"packed_struct",
|
"packed_struct",
|
||||||
"roc_builtins",
|
"roc_builtins",
|
||||||
"roc_collections",
|
"roc_collections",
|
||||||
|
"roc_error_macros",
|
||||||
"roc_module",
|
"roc_module",
|
||||||
"roc_mono",
|
"roc_mono",
|
||||||
"roc_problem",
|
"roc_problem",
|
||||||
"roc_region",
|
"roc_region",
|
||||||
"roc_reporting",
|
|
||||||
"roc_solve",
|
"roc_solve",
|
||||||
|
"roc_target",
|
||||||
"roc_types",
|
"roc_types",
|
||||||
"roc_unify",
|
"roc_unify",
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
|
@ -2720,10 +2722,11 @@ dependencies = [
|
||||||
"morphic_lib",
|
"morphic_lib",
|
||||||
"roc_builtins",
|
"roc_builtins",
|
||||||
"roc_collections",
|
"roc_collections",
|
||||||
|
"roc_error_macros",
|
||||||
"roc_module",
|
"roc_module",
|
||||||
"roc_mono",
|
"roc_mono",
|
||||||
"roc_reporting",
|
|
||||||
"roc_std",
|
"roc_std",
|
||||||
|
"roc_target",
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2734,10 +2737,11 @@ dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"roc_builtins",
|
"roc_builtins",
|
||||||
"roc_collections",
|
"roc_collections",
|
||||||
|
"roc_error_macros",
|
||||||
"roc_module",
|
"roc_module",
|
||||||
"roc_mono",
|
"roc_mono",
|
||||||
"roc_reporting",
|
|
||||||
"roc_std",
|
"roc_std",
|
||||||
|
"roc_target",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2782,6 +2786,7 @@ dependencies = [
|
||||||
"roc_region",
|
"roc_region",
|
||||||
"roc_reporting",
|
"roc_reporting",
|
||||||
"roc_solve",
|
"roc_solve",
|
||||||
|
"roc_target",
|
||||||
"roc_types",
|
"roc_types",
|
||||||
"roc_unify",
|
"roc_unify",
|
||||||
"ven_pretty",
|
"ven_pretty",
|
||||||
|
@ -2815,6 +2820,7 @@ dependencies = [
|
||||||
"roc_region",
|
"roc_region",
|
||||||
"roc_solve",
|
"roc_solve",
|
||||||
"roc_std",
|
"roc_std",
|
||||||
|
"roc_target",
|
||||||
"roc_types",
|
"roc_types",
|
||||||
"roc_unify",
|
"roc_unify",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
|
@ -2850,6 +2856,44 @@ dependencies = [
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "roc_repl_cli"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bumpalo",
|
||||||
|
"const_format",
|
||||||
|
"roc_mono",
|
||||||
|
"roc_parse",
|
||||||
|
"roc_repl_eval",
|
||||||
|
"rustyline",
|
||||||
|
"rustyline-derive",
|
||||||
|
"target-lexicon",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "roc_repl_eval"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bumpalo",
|
||||||
|
"inkwell 0.1.0",
|
||||||
|
"libloading 0.7.1",
|
||||||
|
"roc_build",
|
||||||
|
"roc_builtins",
|
||||||
|
"roc_can",
|
||||||
|
"roc_collections",
|
||||||
|
"roc_fmt",
|
||||||
|
"roc_gen_llvm",
|
||||||
|
"roc_load",
|
||||||
|
"roc_module",
|
||||||
|
"roc_mono",
|
||||||
|
"roc_parse",
|
||||||
|
"roc_region",
|
||||||
|
"roc_reporting",
|
||||||
|
"roc_target",
|
||||||
|
"roc_types",
|
||||||
|
"target-lexicon",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "roc_reporting"
|
name = "roc_reporting"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -2886,6 +2930,13 @@ dependencies = [
|
||||||
name = "roc_std"
|
name = "roc_std"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "roc_target"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"target-lexicon",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "roc_types"
|
name = "roc_types"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
|
@ -26,7 +26,7 @@ pub fn build(b: *Builder) void {
|
||||||
.default_target = CrossTarget{
|
.default_target = CrossTarget{
|
||||||
.cpu_model = .baseline,
|
.cpu_model = .baseline,
|
||||||
// TODO allow for native target for maximum speed
|
// TODO allow for native target for maximum speed
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
const i386_target = makeI386Target();
|
const i386_target = makeI386Target();
|
||||||
const wasm32_target = makeWasm32Target();
|
const wasm32_target = makeWasm32Target();
|
||||||
|
|
|
@ -750,7 +750,8 @@ pub fn dictWalk(
|
||||||
const alignment_u32 = alignment.toU32();
|
const alignment_u32 = alignment.toU32();
|
||||||
// allocate space to write the result of the stepper into
|
// allocate space to write the result of the stepper into
|
||||||
// experimentally aliasing the accum and output pointers is not a good idea
|
// experimentally aliasing the accum and output pointers is not a good idea
|
||||||
const bytes_ptr: [*]u8 = utils.alloc(accum_width, alignment_u32);
|
// TODO handle alloc failing!
|
||||||
|
const bytes_ptr: [*]u8 = utils.alloc(accum_width, alignment_u32) orelse unreachable;
|
||||||
var b1 = output orelse unreachable;
|
var b1 = output orelse unreachable;
|
||||||
var b2 = bytes_ptr;
|
var b2 = bytes_ptr;
|
||||||
|
|
||||||
|
|
162
compiler/builtins/bitcode/src/expect.zig
Normal file
162
compiler/builtins/bitcode/src/expect.zig
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const utils = @import("utils.zig");
|
||||||
|
const CSlice = utils.CSlice;
|
||||||
|
const always_inline = std.builtin.CallOptions.Modifier.always_inline;
|
||||||
|
|
||||||
|
const Failure = struct {
|
||||||
|
start_line: u32,
|
||||||
|
end_line: u32,
|
||||||
|
start_col: u16,
|
||||||
|
end_col: u16,
|
||||||
|
};
|
||||||
|
|
||||||
|
// BEGIN FAILURES GLOBALS ///////////////////
|
||||||
|
var failures_mutex = std.Thread.Mutex{};
|
||||||
|
var failures: [*]Failure = undefined;
|
||||||
|
var failure_length: usize = 0;
|
||||||
|
var failure_capacity: usize = 0;
|
||||||
|
// END FAILURES GLOBALS /////////////////////
|
||||||
|
|
||||||
|
pub fn expectFailed(
|
||||||
|
start_line: u32,
|
||||||
|
end_line: u32,
|
||||||
|
start_col: u16,
|
||||||
|
end_col: u16,
|
||||||
|
) void {
|
||||||
|
const new_failure = Failure{ .start_line = start_line, .end_line = end_line, .start_col = start_col, .end_col = end_col };
|
||||||
|
|
||||||
|
// Lock the failures mutex before reading from any of the failures globals,
|
||||||
|
// and then release the lock once we're done modifying things.
|
||||||
|
|
||||||
|
// TODO FOR ZIG 0.9: this API changed in https://github.com/ziglang/zig/commit/008b0ec5e58fc7e31f3b989868a7d1ea4df3f41d
|
||||||
|
// to this: https://github.com/ziglang/zig/blob/c710d5eefe3f83226f1651947239730e77af43cb/lib/std/Thread/Mutex.zig
|
||||||
|
//
|
||||||
|
// ...so just use these two lines of code instead of the non-commented-out ones to make this work in Zig 0.9:
|
||||||
|
//
|
||||||
|
// failures_mutex.lock();
|
||||||
|
// defer failures_mutex.release();
|
||||||
|
//
|
||||||
|
// 👆 👆 👆 IF UPGRADING TO ZIG 0.9, LOOK HERE! 👆 👆 👆
|
||||||
|
const held = failures_mutex.acquire();
|
||||||
|
defer held.release();
|
||||||
|
|
||||||
|
// If we don't have enough capacity to add a failure, allocate a new failures pointer.
|
||||||
|
if (failure_length >= failure_capacity) {
|
||||||
|
if (failure_capacity > 0) {
|
||||||
|
// We already had previous failures allocated, so try to realloc in order
|
||||||
|
// to grow the size in-place without having to memcpy bytes over.
|
||||||
|
const old_pointer = failures;
|
||||||
|
const old_bytes = failure_capacity * @sizeOf(Failure);
|
||||||
|
|
||||||
|
failure_capacity *= 2;
|
||||||
|
|
||||||
|
const new_bytes = failure_capacity * @sizeOf(Failure);
|
||||||
|
const failures_u8 = @ptrCast([*]u8, @alignCast(@alignOf(Failure), failures));
|
||||||
|
const raw_pointer = utils.realloc(failures_u8, new_bytes, old_bytes, @alignOf(Failure));
|
||||||
|
|
||||||
|
failures = @ptrCast([*]Failure, @alignCast(@alignOf(Failure), raw_pointer));
|
||||||
|
|
||||||
|
// If realloc wasn't able to expand in-place (that is, it returned a different pointer),
|
||||||
|
// then copy the data into the new pointer and dealloc the old one.
|
||||||
|
if (failures != old_pointer) {
|
||||||
|
const old_pointer_u8 = @ptrCast([*]u8, old_pointer);
|
||||||
|
utils.memcpy(@ptrCast([*]u8, failures), old_pointer_u8, old_bytes);
|
||||||
|
utils.dealloc(old_pointer_u8, @alignOf(Failure));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// We've never had any failures before, so allocate the failures for the first time.
|
||||||
|
failure_capacity = 10;
|
||||||
|
|
||||||
|
const raw_pointer = utils.alloc(failure_capacity * @sizeOf(Failure), @alignOf(Failure));
|
||||||
|
|
||||||
|
failures = @ptrCast([*]Failure, @alignCast(@alignOf(Failure), raw_pointer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
failures[failure_length] = new_failure;
|
||||||
|
failure_length += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expectFailedC(
|
||||||
|
start_line: u32,
|
||||||
|
end_line: u32,
|
||||||
|
start_col: u16,
|
||||||
|
end_col: u16,
|
||||||
|
) callconv(.C) void {
|
||||||
|
return @call(.{ .modifier = always_inline }, expectFailed, .{ start_line, end_line, start_col, end_col });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getExpectFailures() []Failure {
|
||||||
|
// TODO FOR ZIG 0.9: this API changed in https://github.com/ziglang/zig/commit/008b0ec5e58fc7e31f3b989868a7d1ea4df3f41d
|
||||||
|
// to this: https://github.com/ziglang/zig/blob/c710d5eefe3f83226f1651947239730e77af43cb/lib/std/Thread/Mutex.zig
|
||||||
|
//
|
||||||
|
// ...so just use these two lines of code instead of the non-commented-out ones to make this work in Zig 0.9:
|
||||||
|
//
|
||||||
|
// failures_mutex.lock();
|
||||||
|
// defer failures_mutex.release();
|
||||||
|
//
|
||||||
|
// 👆 👆 👆 IF UPGRADING TO ZIG 0.9, LOOK HERE! 👆 👆 👆
|
||||||
|
const held = failures_mutex.acquire();
|
||||||
|
defer held.release();
|
||||||
|
|
||||||
|
if (failure_length > 0) {
|
||||||
|
// defensively clone failures, in case someone modifies the originals after the mutex has been released.
|
||||||
|
const num_bytes = failure_length * @sizeOf(Failure);
|
||||||
|
// TODO handle the possibility of alloc failing
|
||||||
|
const raw_clones = utils.alloc(num_bytes, @alignOf(Failure)) orelse unreachable;
|
||||||
|
|
||||||
|
utils.memcpy(raw_clones, @ptrCast([*]u8, failures), num_bytes);
|
||||||
|
|
||||||
|
const clones = @ptrCast([*]Failure, @alignCast(@alignOf(Failure), raw_clones));
|
||||||
|
|
||||||
|
return clones[0..failure_length];
|
||||||
|
} else {
|
||||||
|
return failures[0..0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getExpectFailuresC() callconv(.C) CSlice {
|
||||||
|
var bytes = @ptrCast(*c_void, failures);
|
||||||
|
|
||||||
|
return .{ .pointer = bytes, .len = failure_length };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinitFailures() void {
|
||||||
|
// TODO FOR ZIG 0.9: this API changed in https://github.com/ziglang/zig/commit/008b0ec5e58fc7e31f3b989868a7d1ea4df3f41d
|
||||||
|
// to this: https://github.com/ziglang/zig/blob/c710d5eefe3f83226f1651947239730e77af43cb/lib/std/Thread/Mutex.zig
|
||||||
|
//
|
||||||
|
// ...so just use these two lines of code instead of the non-commented-out ones to make this work in Zig 0.9:
|
||||||
|
//
|
||||||
|
// failures_mutex.lock();
|
||||||
|
// defer failures_mutex.release();
|
||||||
|
//
|
||||||
|
// 👆 👆 👆 IF UPGRADING TO ZIG 0.9, LOOK HERE! 👆 👆 👆
|
||||||
|
const held = failures_mutex.acquire();
|
||||||
|
defer held.release();
|
||||||
|
|
||||||
|
utils.dealloc(@ptrCast([*]u8, failures), @alignOf(Failure));
|
||||||
|
failure_length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinitFailuresC() callconv(.C) void {
|
||||||
|
return @call(.{ .modifier = always_inline }, deinitFailures, .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
test "expectFailure does something" {
|
||||||
|
defer deinitFailures();
|
||||||
|
|
||||||
|
var fails = getExpectFailures();
|
||||||
|
try std.testing.expectEqual(fails.len, 0);
|
||||||
|
|
||||||
|
expectFailed(1, 2, 3, 4);
|
||||||
|
|
||||||
|
fails = getExpectFailures();
|
||||||
|
try std.testing.expectEqual(fails.len, 1);
|
||||||
|
utils.dealloc(@ptrCast([*]u8, fails.ptr), @alignOf([*]Failure));
|
||||||
|
|
||||||
|
const what_it_should_look_like = Failure{ .start_line = 1, .end_line = 2, .start_col = 3, .end_col = 4 };
|
||||||
|
|
||||||
|
fails = getExpectFailures();
|
||||||
|
try std.testing.expectEqual(fails[0], what_it_should_look_like);
|
||||||
|
utils.dealloc(@ptrCast([*]u8, fails.ptr), @alignOf([*]Failure));
|
||||||
|
}
|
|
@ -550,7 +550,8 @@ pub fn listKeepResult(
|
||||||
var output = RocList.allocate(alignment, list.len(), list.len() * after_width);
|
var output = RocList.allocate(alignment, list.len(), list.len() * after_width);
|
||||||
const target_ptr = output.bytes orelse unreachable;
|
const target_ptr = output.bytes orelse unreachable;
|
||||||
|
|
||||||
var temporary = @ptrCast([*]u8, utils.alloc(result_width, alignment));
|
// TODO handle alloc failing!
|
||||||
|
var temporary = utils.alloc(result_width, alignment) orelse unreachable;
|
||||||
|
|
||||||
if (data_is_owned) {
|
if (data_is_owned) {
|
||||||
inc_n_data(data, size);
|
inc_n_data(data, size);
|
||||||
|
@ -614,7 +615,8 @@ pub fn listWalk(
|
||||||
inc_n_data(data, list.len());
|
inc_n_data(data, list.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
const bytes_ptr: [*]u8 = utils.alloc(accum_width, alignment);
|
// TODO handle alloc failing!
|
||||||
|
const bytes_ptr: [*]u8 = utils.alloc(accum_width, alignment) orelse unreachable;
|
||||||
var b1 = output orelse unreachable;
|
var b1 = output orelse unreachable;
|
||||||
var b2 = bytes_ptr;
|
var b2 = bytes_ptr;
|
||||||
|
|
||||||
|
@ -660,7 +662,8 @@ pub fn listWalkBackwards(
|
||||||
inc_n_data(data, list.len());
|
inc_n_data(data, list.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
const bytes_ptr: [*]u8 = utils.alloc(accum_width, alignment);
|
// TODO handle alloc failing!
|
||||||
|
const bytes_ptr: [*]u8 = utils.alloc(accum_width, alignment) orelse unreachable;
|
||||||
var b1 = output orelse unreachable;
|
var b1 = output orelse unreachable;
|
||||||
var b2 = bytes_ptr;
|
var b2 = bytes_ptr;
|
||||||
|
|
||||||
|
@ -708,7 +711,8 @@ pub fn listWalkUntil(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bytes_ptr: [*]u8 = utils.alloc(continue_stop_width, alignment);
|
// TODO handle alloc failing!
|
||||||
|
const bytes_ptr: [*]u8 = utils.alloc(continue_stop_width, alignment) orelse unreachable;
|
||||||
|
|
||||||
// NOTE: assumes data bytes are the first bytes in a tag
|
// NOTE: assumes data bytes are the first bytes in a tag
|
||||||
@memcpy(bytes_ptr, accum orelse unreachable, accum_width);
|
@memcpy(bytes_ptr, accum orelse unreachable, accum_width);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const math = std.math;
|
const math = std.math;
|
||||||
const utils = @import("utils.zig");
|
const utils = @import("utils.zig");
|
||||||
|
const expect = @import("expect.zig");
|
||||||
|
|
||||||
const ROC_BUILTINS = "roc_builtins";
|
const ROC_BUILTINS = "roc_builtins";
|
||||||
const NUM = "num";
|
const NUM = "num";
|
||||||
|
@ -141,12 +142,14 @@ comptime {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
|
|
||||||
comptime {
|
comptime {
|
||||||
exportUtilsFn(utils.test_panic, "test_panic");
|
exportUtilsFn(utils.test_panic, "test_panic");
|
||||||
exportUtilsFn(utils.increfC, "incref");
|
exportUtilsFn(utils.increfC, "incref");
|
||||||
exportUtilsFn(utils.decrefC, "decref");
|
exportUtilsFn(utils.decrefC, "decref");
|
||||||
exportUtilsFn(utils.decrefCheckNullC, "decref_check_null");
|
exportUtilsFn(utils.decrefCheckNullC, "decref_check_null");
|
||||||
|
exportExpectFn(expect.expectFailedC, "expect_failed");
|
||||||
|
exportExpectFn(expect.getExpectFailuresC, "get_expect_failures");
|
||||||
|
exportExpectFn(expect.deinitFailuresC, "deinit_failures");
|
||||||
|
|
||||||
@export(utils.panic, .{ .name = "roc_builtins.utils." ++ "panic", .linkage = .Weak });
|
@export(utils.panic, .{ .name = "roc_builtins.utils." ++ "panic", .linkage = .Weak });
|
||||||
}
|
}
|
||||||
|
@ -175,6 +178,10 @@ fn exportUtilsFn(comptime func: anytype, comptime func_name: []const u8) void {
|
||||||
exportBuiltinFn(func, "utils." ++ func_name);
|
exportBuiltinFn(func, "utils." ++ func_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn exportExpectFn(comptime func: anytype, comptime func_name: []const u8) void {
|
||||||
|
exportBuiltinFn(func, "expect." ++ func_name);
|
||||||
|
}
|
||||||
|
|
||||||
// Custom panic function, as builtin Zig version errors during LLVM verification
|
// Custom panic function, as builtin Zig version errors during LLVM verification
|
||||||
pub fn panic(message: []const u8, stacktrace: ?*std.builtin.StackTrace) noreturn {
|
pub fn panic(message: []const u8, stacktrace: ?*std.builtin.StackTrace) noreturn {
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
|
|
@ -18,14 +18,18 @@ extern fn roc_dealloc(c_ptr: *c_void, alignment: u32) callconv(.C) void;
|
||||||
// Signals to the host that the program has panicked
|
// Signals to the host that the program has panicked
|
||||||
extern fn roc_panic(c_ptr: *c_void, tag_id: u32) callconv(.C) void;
|
extern fn roc_panic(c_ptr: *c_void, tag_id: u32) callconv(.C) void;
|
||||||
|
|
||||||
|
// should work just like libc memcpy (we can't assume libc is present)
|
||||||
|
extern fn roc_memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void;
|
||||||
|
|
||||||
comptime {
|
comptime {
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
// During tetsts, use the testing allocators to satisfy these functions.
|
// During tests, use the testing allocators to satisfy these functions.
|
||||||
if (builtin.is_test) {
|
if (builtin.is_test) {
|
||||||
@export(testing_roc_alloc, .{ .name = "roc_alloc", .linkage = .Strong });
|
@export(testing_roc_alloc, .{ .name = "roc_alloc", .linkage = .Strong });
|
||||||
@export(testing_roc_realloc, .{ .name = "roc_realloc", .linkage = .Strong });
|
@export(testing_roc_realloc, .{ .name = "roc_realloc", .linkage = .Strong });
|
||||||
@export(testing_roc_dealloc, .{ .name = "roc_dealloc", .linkage = .Strong });
|
@export(testing_roc_dealloc, .{ .name = "roc_dealloc", .linkage = .Strong });
|
||||||
@export(testing_roc_panic, .{ .name = "roc_panic", .linkage = .Strong });
|
@export(testing_roc_panic, .{ .name = "roc_panic", .linkage = .Strong });
|
||||||
|
@export(testing_roc_memcpy, .{ .name = "roc_memcpy", .linkage = .Strong });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,8 +57,16 @@ fn testing_roc_panic(c_ptr: *c_void, tag_id: u32) callconv(.C) void {
|
||||||
@panic("Roc panicked");
|
@panic("Roc panicked");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn alloc(size: usize, alignment: u32) [*]u8 {
|
fn testing_roc_memcpy(dest: *c_void, src: *c_void, bytes: usize) callconv(.C) ?*c_void {
|
||||||
return @ptrCast([*]u8, @call(.{ .modifier = always_inline }, roc_alloc, .{ size, alignment }));
|
const zig_dest = @ptrCast([*]u8, dest);
|
||||||
|
const zig_src = @ptrCast([*]u8, src);
|
||||||
|
|
||||||
|
@memcpy(zig_dest, zig_src, bytes);
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn alloc(size: usize, alignment: u32) ?[*]u8 {
|
||||||
|
return @ptrCast(?[*]u8, @call(.{ .modifier = always_inline }, roc_alloc, .{ size, alignment }));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn realloc(c_ptr: [*]u8, new_size: usize, old_size: usize, alignment: u32) [*]u8 {
|
pub fn realloc(c_ptr: [*]u8, new_size: usize, old_size: usize, alignment: u32) [*]u8 {
|
||||||
|
@ -70,6 +82,10 @@ pub fn panic(c_ptr: *c_void, alignment: u32) callconv(.C) void {
|
||||||
return @call(.{ .modifier = always_inline }, roc_panic, .{ c_ptr, alignment });
|
return @call(.{ .modifier = always_inline }, roc_panic, .{ c_ptr, alignment });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn memcpy(dst: [*]u8, src: [*]u8, size: usize) void {
|
||||||
|
@call(.{ .modifier = always_inline }, roc_memcpy, .{ dst, src, size });
|
||||||
|
}
|
||||||
|
|
||||||
// indirection because otherwise zig creates an alias to the panic function which our LLVM code
|
// indirection because otherwise zig creates an alias to the panic function which our LLVM code
|
||||||
// does not know how to deal with
|
// does not know how to deal with
|
||||||
pub fn test_panic(c_ptr: *c_void, alignment: u32) callconv(.C) void {
|
pub fn test_panic(c_ptr: *c_void, alignment: u32) callconv(.C) void {
|
||||||
|
@ -173,7 +189,8 @@ pub fn allocateWithRefcount(
|
||||||
|
|
||||||
switch (alignment) {
|
switch (alignment) {
|
||||||
16 => {
|
16 => {
|
||||||
var new_bytes: [*]align(16) u8 = @alignCast(16, alloc(length, alignment));
|
// TODO handle alloc failing!
|
||||||
|
var new_bytes: [*]align(16) u8 = @alignCast(16, alloc(length, alignment) orelse unreachable);
|
||||||
|
|
||||||
var as_usize_array = @ptrCast([*]usize, new_bytes);
|
var as_usize_array = @ptrCast([*]usize, new_bytes);
|
||||||
as_usize_array[0] = 0;
|
as_usize_array[0] = 0;
|
||||||
|
@ -185,7 +202,8 @@ pub fn allocateWithRefcount(
|
||||||
return first_slot;
|
return first_slot;
|
||||||
},
|
},
|
||||||
8 => {
|
8 => {
|
||||||
var raw = alloc(length, alignment);
|
// TODO handle alloc failing!
|
||||||
|
var raw = alloc(length, alignment) orelse unreachable;
|
||||||
var new_bytes: [*]align(8) u8 = @alignCast(8, raw);
|
var new_bytes: [*]align(8) u8 = @alignCast(8, raw);
|
||||||
|
|
||||||
var as_isize_array = @ptrCast([*]isize, new_bytes);
|
var as_isize_array = @ptrCast([*]isize, new_bytes);
|
||||||
|
@ -197,7 +215,8 @@ pub fn allocateWithRefcount(
|
||||||
return first_slot;
|
return first_slot;
|
||||||
},
|
},
|
||||||
4 => {
|
4 => {
|
||||||
var raw = alloc(length, alignment);
|
// TODO handle alloc failing!
|
||||||
|
var raw = alloc(length, alignment) orelse unreachable;
|
||||||
var new_bytes: [*]align(@alignOf(isize)) u8 = @alignCast(@alignOf(isize), raw);
|
var new_bytes: [*]align(@alignOf(isize)) u8 = @alignCast(@alignOf(isize), raw);
|
||||||
|
|
||||||
var as_isize_array = @ptrCast([*]isize, new_bytes);
|
var as_isize_array = @ptrCast([*]isize, new_bytes);
|
||||||
|
@ -217,6 +236,11 @@ pub fn allocateWithRefcount(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const CSlice = extern struct {
|
||||||
|
pointer: *c_void,
|
||||||
|
len: usize,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn unsafeReallocate(
|
pub fn unsafeReallocate(
|
||||||
source_ptr: [*]u8,
|
source_ptr: [*]u8,
|
||||||
alignment: u32,
|
alignment: u32,
|
||||||
|
|
|
@ -336,3 +336,6 @@ pub const UTILS_TEST_PANIC: &str = "roc_builtins.utils.test_panic";
|
||||||
pub const UTILS_INCREF: &str = "roc_builtins.utils.incref";
|
pub const UTILS_INCREF: &str = "roc_builtins.utils.incref";
|
||||||
pub const UTILS_DECREF: &str = "roc_builtins.utils.decref";
|
pub const UTILS_DECREF: &str = "roc_builtins.utils.decref";
|
||||||
pub const UTILS_DECREF_CHECK_NULL: &str = "roc_builtins.utils.decref_check_null";
|
pub const UTILS_DECREF_CHECK_NULL: &str = "roc_builtins.utils.decref_check_null";
|
||||||
|
pub const UTILS_EXPECT_FAILED: &str = "roc_builtins.expect.expect_failed";
|
||||||
|
pub const UTILS_GET_EXPECT_FAILURES: &str = "roc_builtins.expect.get_expect_failures";
|
||||||
|
pub const UTILS_DEINIT_FAILURES: &str = "roc_builtins.expect.deinit_failures";
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::def::Def;
|
use crate::def::Def;
|
||||||
use crate::expr::{self, ClosureData, Expr::*};
|
use crate::expr::{self, ClosureData, Expr::*, IntValue};
|
||||||
use crate::expr::{Expr, Field, Recursive};
|
use crate::expr::{Expr, Field, Recursive};
|
||||||
|
use crate::num::{FloatWidth, IntWidth, NumWidth, NumericBound};
|
||||||
use crate::pattern::Pattern;
|
use crate::pattern::Pattern;
|
||||||
use roc_collections::all::SendMap;
|
use roc_collections::all::SendMap;
|
||||||
use roc_module::called_via::CalledVia;
|
use roc_module::called_via::CalledVia;
|
||||||
|
@ -793,7 +794,7 @@ fn num_is_zero(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
op: LowLevel::Eq,
|
op: LowLevel::Eq,
|
||||||
args: vec![
|
args: vec![
|
||||||
(arg_var, Var(Symbol::ARG_1)),
|
(arg_var, Var(Symbol::ARG_1)),
|
||||||
(arg_var, num(unbound_zero_var, 0)),
|
(arg_var, num(unbound_zero_var, 0, num_no_bound())),
|
||||||
],
|
],
|
||||||
ret_var: bool_var,
|
ret_var: bool_var,
|
||||||
};
|
};
|
||||||
|
@ -816,7 +817,7 @@ fn num_is_negative(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
let body = RunLowLevel {
|
let body = RunLowLevel {
|
||||||
op: LowLevel::NumGt,
|
op: LowLevel::NumGt,
|
||||||
args: vec![
|
args: vec![
|
||||||
(arg_var, num(unbound_zero_var, 0)),
|
(arg_var, num(unbound_zero_var, 0, num_no_bound())),
|
||||||
(arg_var, Var(Symbol::ARG_1)),
|
(arg_var, Var(Symbol::ARG_1)),
|
||||||
],
|
],
|
||||||
ret_var: bool_var,
|
ret_var: bool_var,
|
||||||
|
@ -841,7 +842,7 @@ fn num_is_positive(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
op: LowLevel::NumGt,
|
op: LowLevel::NumGt,
|
||||||
args: vec![
|
args: vec![
|
||||||
(arg_var, Var(Symbol::ARG_1)),
|
(arg_var, Var(Symbol::ARG_1)),
|
||||||
(arg_var, num(unbound_zero_var, 0)),
|
(arg_var, num(unbound_zero_var, 0, num_no_bound())),
|
||||||
],
|
],
|
||||||
ret_var: bool_var,
|
ret_var: bool_var,
|
||||||
};
|
};
|
||||||
|
@ -866,7 +867,7 @@ fn num_is_odd(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
args: vec![
|
args: vec![
|
||||||
(
|
(
|
||||||
arg_var,
|
arg_var,
|
||||||
int::<i128>(var_store.fresh(), var_store.fresh(), 1),
|
int::<i128>(var_store.fresh(), var_store.fresh(), 1, num_no_bound()),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
arg_var,
|
arg_var,
|
||||||
|
@ -874,7 +875,7 @@ fn num_is_odd(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
op: LowLevel::NumRemUnchecked,
|
op: LowLevel::NumRemUnchecked,
|
||||||
args: vec![
|
args: vec![
|
||||||
(arg_var, Var(Symbol::ARG_1)),
|
(arg_var, Var(Symbol::ARG_1)),
|
||||||
(arg_var, num(unbound_two_var, 2)),
|
(arg_var, num(unbound_two_var, 2, num_no_bound())),
|
||||||
],
|
],
|
||||||
ret_var: arg_var,
|
ret_var: arg_var,
|
||||||
},
|
},
|
||||||
|
@ -901,14 +902,14 @@ fn num_is_even(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
let body = RunLowLevel {
|
let body = RunLowLevel {
|
||||||
op: LowLevel::Eq,
|
op: LowLevel::Eq,
|
||||||
args: vec![
|
args: vec![
|
||||||
(arg_var, num(arg_num_var, 0)),
|
(arg_var, num(arg_num_var, 0, num_no_bound())),
|
||||||
(
|
(
|
||||||
arg_var,
|
arg_var,
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
op: LowLevel::NumRemUnchecked,
|
op: LowLevel::NumRemUnchecked,
|
||||||
args: vec![
|
args: vec![
|
||||||
(arg_var, Var(Symbol::ARG_1)),
|
(arg_var, Var(Symbol::ARG_1)),
|
||||||
(arg_var, num(arg_num_var, 2)),
|
(arg_var, num(arg_num_var, 2, num_no_bound())),
|
||||||
],
|
],
|
||||||
ret_var: arg_var,
|
ret_var: arg_var,
|
||||||
},
|
},
|
||||||
|
@ -962,7 +963,10 @@ fn num_sqrt(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
op: LowLevel::NumGte,
|
op: LowLevel::NumGte,
|
||||||
args: vec![
|
args: vec![
|
||||||
(float_var, Var(Symbol::ARG_1)),
|
(float_var, Var(Symbol::ARG_1)),
|
||||||
(float_var, float(unbound_zero_var, precision_var, 0.0)),
|
(
|
||||||
|
float_var,
|
||||||
|
float(unbound_zero_var, precision_var, 0.0, num_no_bound()),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
ret_var: bool_var,
|
ret_var: bool_var,
|
||||||
}),
|
}),
|
||||||
|
@ -1008,7 +1012,10 @@ fn num_log(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
op: LowLevel::NumGt,
|
op: LowLevel::NumGt,
|
||||||
args: vec![
|
args: vec![
|
||||||
(float_var, Var(Symbol::ARG_1)),
|
(float_var, Var(Symbol::ARG_1)),
|
||||||
(float_var, float(unbound_zero_var, precision_var, 0.0)),
|
(
|
||||||
|
float_var,
|
||||||
|
float(unbound_zero_var, precision_var, 0.0, num_no_bound()),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
ret_var: bool_var,
|
ret_var: bool_var,
|
||||||
}),
|
}),
|
||||||
|
@ -1246,92 +1253,182 @@ fn num_int_cast(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
|
||||||
/// Num.minI8: I8
|
/// Num.minI8: I8
|
||||||
fn num_min_i8(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_min_i8(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
int_min_or_max::<i8>(symbol, var_store, i8::MIN)
|
int_min_or_max::<i8>(
|
||||||
|
symbol,
|
||||||
|
var_store,
|
||||||
|
i8::MIN,
|
||||||
|
NumericBound::Exact(IntWidth::I8),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Num.maxI8: I8
|
/// Num.maxI8: I8
|
||||||
fn num_max_i8(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_max_i8(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
int_min_or_max::<i8>(symbol, var_store, i8::MAX)
|
int_min_or_max::<i8>(
|
||||||
|
symbol,
|
||||||
|
var_store,
|
||||||
|
i8::MAX,
|
||||||
|
NumericBound::Exact(IntWidth::I8),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Num.minU8: U8
|
/// Num.minU8: U8
|
||||||
fn num_min_u8(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_min_u8(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
int_min_or_max::<u8>(symbol, var_store, u8::MIN)
|
int_min_or_max::<u8>(
|
||||||
|
symbol,
|
||||||
|
var_store,
|
||||||
|
u8::MIN,
|
||||||
|
NumericBound::Exact(IntWidth::U8),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Num.maxU8: U8
|
/// Num.maxU8: U8
|
||||||
fn num_max_u8(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_max_u8(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
int_min_or_max::<u8>(symbol, var_store, u8::MAX)
|
int_min_or_max::<u8>(
|
||||||
|
symbol,
|
||||||
|
var_store,
|
||||||
|
u8::MAX,
|
||||||
|
NumericBound::Exact(IntWidth::U8),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Num.minI16: I16
|
/// Num.minI16: I16
|
||||||
fn num_min_i16(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_min_i16(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
int_min_or_max::<i16>(symbol, var_store, i16::MIN)
|
int_min_or_max::<i16>(
|
||||||
|
symbol,
|
||||||
|
var_store,
|
||||||
|
i16::MIN,
|
||||||
|
NumericBound::Exact(IntWidth::I16),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Num.maxI16: I16
|
/// Num.maxI16: I16
|
||||||
fn num_max_i16(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_max_i16(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
int_min_or_max::<i16>(symbol, var_store, i16::MAX)
|
int_min_or_max::<i16>(
|
||||||
|
symbol,
|
||||||
|
var_store,
|
||||||
|
i16::MAX,
|
||||||
|
NumericBound::Exact(IntWidth::I16),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Num.minU16: U16
|
/// Num.minU16: U16
|
||||||
fn num_min_u16(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_min_u16(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
int_min_or_max::<u16>(symbol, var_store, u16::MIN)
|
int_min_or_max::<u16>(
|
||||||
|
symbol,
|
||||||
|
var_store,
|
||||||
|
u16::MIN,
|
||||||
|
NumericBound::Exact(IntWidth::U16),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Num.maxU16: U16
|
/// Num.maxU16: U16
|
||||||
fn num_max_u16(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_max_u16(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
int_min_or_max::<u16>(symbol, var_store, u16::MAX)
|
int_min_or_max::<u16>(
|
||||||
|
symbol,
|
||||||
|
var_store,
|
||||||
|
u16::MAX,
|
||||||
|
NumericBound::Exact(IntWidth::U16),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Num.minI32: I32
|
/// Num.minI32: I32
|
||||||
fn num_min_i32(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_min_i32(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
int_min_or_max::<i32>(symbol, var_store, i32::MIN)
|
int_min_or_max::<i32>(
|
||||||
|
symbol,
|
||||||
|
var_store,
|
||||||
|
i32::MIN,
|
||||||
|
NumericBound::Exact(IntWidth::I32),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Num.maxI32: I32
|
/// Num.maxI32: I32
|
||||||
fn num_max_i32(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_max_i32(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
int_min_or_max::<i32>(symbol, var_store, i32::MAX)
|
int_min_or_max::<i32>(
|
||||||
|
symbol,
|
||||||
|
var_store,
|
||||||
|
i32::MAX,
|
||||||
|
NumericBound::Exact(IntWidth::I32),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Num.minU32: U32
|
/// Num.minU32: U32
|
||||||
fn num_min_u32(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_min_u32(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
int_min_or_max::<u32>(symbol, var_store, u32::MIN)
|
int_min_or_max::<u32>(
|
||||||
|
symbol,
|
||||||
|
var_store,
|
||||||
|
u32::MIN,
|
||||||
|
NumericBound::Exact(IntWidth::U32),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Num.maxU32: U32
|
/// Num.maxU32: U32
|
||||||
fn num_max_u32(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_max_u32(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
int_min_or_max::<u32>(symbol, var_store, u32::MAX)
|
int_min_or_max::<u32>(
|
||||||
|
symbol,
|
||||||
|
var_store,
|
||||||
|
u32::MAX,
|
||||||
|
NumericBound::Exact(IntWidth::U32),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Num.minI64: I64
|
/// Num.minI64: I64
|
||||||
fn num_min_i64(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_min_i64(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
int_min_or_max::<i64>(symbol, var_store, i64::MIN)
|
int_min_or_max::<i64>(
|
||||||
|
symbol,
|
||||||
|
var_store,
|
||||||
|
i64::MIN,
|
||||||
|
NumericBound::Exact(IntWidth::I64),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Num.maxI64: I64
|
/// Num.maxI64: I64
|
||||||
fn num_max_i64(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_max_i64(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
int_min_or_max::<i64>(symbol, var_store, i64::MAX)
|
int_min_or_max::<i64>(
|
||||||
|
symbol,
|
||||||
|
var_store,
|
||||||
|
i64::MAX,
|
||||||
|
NumericBound::Exact(IntWidth::I64),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Num.minU64: U64
|
/// Num.minU64: U64
|
||||||
fn num_min_u64(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_min_u64(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
int_min_or_max::<u64>(symbol, var_store, u64::MIN)
|
int_min_or_max::<u64>(
|
||||||
|
symbol,
|
||||||
|
var_store,
|
||||||
|
u64::MIN,
|
||||||
|
NumericBound::Exact(IntWidth::U64),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Num.maxU64: U64
|
/// Num.maxU64: U64
|
||||||
fn num_max_u64(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_max_u64(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
int_min_or_max::<u64>(symbol, var_store, u64::MAX)
|
int_min_or_max::<u64>(
|
||||||
|
symbol,
|
||||||
|
var_store,
|
||||||
|
u64::MAX,
|
||||||
|
NumericBound::Exact(IntWidth::U64),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Num.minI128: I128
|
/// Num.minI128: I128
|
||||||
fn num_min_i128(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_min_i128(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
int_min_or_max::<i128>(symbol, var_store, i128::MIN)
|
int_min_or_max::<i128>(
|
||||||
|
symbol,
|
||||||
|
var_store,
|
||||||
|
i128::MIN,
|
||||||
|
NumericBound::Exact(IntWidth::I128),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Num.maxI128: I128
|
/// Num.maxI128: I128
|
||||||
fn num_max_i128(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_max_i128(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
int_min_or_max::<i128>(symbol, var_store, i128::MAX)
|
int_min_or_max::<i128>(
|
||||||
|
symbol,
|
||||||
|
var_store,
|
||||||
|
i128::MAX,
|
||||||
|
NumericBound::Exact(IntWidth::I128),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// List.isEmpty : List * -> Bool
|
/// List.isEmpty : List * -> Bool
|
||||||
|
@ -1344,7 +1441,7 @@ fn list_is_empty(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
let body = RunLowLevel {
|
let body = RunLowLevel {
|
||||||
op: LowLevel::Eq,
|
op: LowLevel::Eq,
|
||||||
args: vec![
|
args: vec![
|
||||||
(len_var, num(unbound_zero_var, 0)),
|
(len_var, num(unbound_zero_var, 0, num_no_bound())),
|
||||||
(
|
(
|
||||||
len_var,
|
len_var,
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
|
@ -1458,7 +1555,12 @@ fn str_to_num(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
errorcode_var,
|
errorcode_var,
|
||||||
int::<i128>(errorcode_var, Variable::UNSIGNED8, 0),
|
int::<i128>(
|
||||||
|
errorcode_var,
|
||||||
|
Variable::UNSIGNED8,
|
||||||
|
0,
|
||||||
|
NumericBound::Exact(IntWidth::U8),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
ret_var: bool_var,
|
ret_var: bool_var,
|
||||||
|
@ -2201,7 +2303,12 @@ fn list_swap(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
fn list_take_first(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn list_take_first(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
let list_var = var_store.fresh();
|
let list_var = var_store.fresh();
|
||||||
let len_var = var_store.fresh();
|
let len_var = var_store.fresh();
|
||||||
let zero = int::<i128>(len_var, Variable::NATURAL, 0);
|
let zero = int::<i128>(
|
||||||
|
len_var,
|
||||||
|
Variable::NATURAL,
|
||||||
|
0,
|
||||||
|
NumericBound::Exact(IntWidth::Nat),
|
||||||
|
);
|
||||||
|
|
||||||
let body = RunLowLevel {
|
let body = RunLowLevel {
|
||||||
op: LowLevel::ListSublist,
|
op: LowLevel::ListSublist,
|
||||||
|
@ -2227,7 +2334,12 @@ fn list_take_last(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
let list_var = var_store.fresh();
|
let list_var = var_store.fresh();
|
||||||
let len_var = var_store.fresh();
|
let len_var = var_store.fresh();
|
||||||
|
|
||||||
let zero = int::<i128>(len_var, Variable::NATURAL, 0);
|
let zero = int::<i128>(
|
||||||
|
len_var,
|
||||||
|
Variable::NATURAL,
|
||||||
|
0,
|
||||||
|
NumericBound::Exact(IntWidth::Nat),
|
||||||
|
);
|
||||||
let bool_var = var_store.fresh();
|
let bool_var = var_store.fresh();
|
||||||
|
|
||||||
let get_list_len = RunLowLevel {
|
let get_list_len = RunLowLevel {
|
||||||
|
@ -2337,7 +2449,12 @@ fn list_intersperse(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
let clos_elem_sym = Symbol::ARG_4;
|
let clos_elem_sym = Symbol::ARG_4;
|
||||||
|
|
||||||
let int_var = var_store.fresh();
|
let int_var = var_store.fresh();
|
||||||
let zero = int::<i128>(int_var, Variable::NATURAL, 0);
|
let zero = int::<i128>(
|
||||||
|
int_var,
|
||||||
|
Variable::NATURAL,
|
||||||
|
0,
|
||||||
|
NumericBound::Exact(IntWidth::Nat),
|
||||||
|
);
|
||||||
|
|
||||||
// \acc, elem -> acc |> List.append sep |> List.append elem
|
// \acc, elem -> acc |> List.append sep |> List.append elem
|
||||||
let clos = Closure(ClosureData {
|
let clos = Closure(ClosureData {
|
||||||
|
@ -2417,7 +2534,12 @@ fn list_split(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
let clos_ret_var = var_store.fresh();
|
let clos_ret_var = var_store.fresh();
|
||||||
|
|
||||||
let ret_var = var_store.fresh();
|
let ret_var = var_store.fresh();
|
||||||
let zero = int::<i128>(index_var, Variable::NATURAL, 0);
|
let zero = int::<i128>(
|
||||||
|
index_var,
|
||||||
|
Variable::NATURAL,
|
||||||
|
0,
|
||||||
|
NumericBound::Exact(IntWidth::Nat),
|
||||||
|
);
|
||||||
|
|
||||||
let clos = Closure(ClosureData {
|
let clos = Closure(ClosureData {
|
||||||
function_type: clos_fun_var,
|
function_type: clos_fun_var,
|
||||||
|
@ -2579,7 +2701,10 @@ fn list_drop_first(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
op: LowLevel::ListDropAt,
|
op: LowLevel::ListDropAt,
|
||||||
args: vec![
|
args: vec![
|
||||||
(list_var, Var(Symbol::ARG_1)),
|
(list_var, Var(Symbol::ARG_1)),
|
||||||
(index_var, int::<i128>(num_var, num_precision_var, 0)),
|
(
|
||||||
|
index_var,
|
||||||
|
int::<i128>(num_var, num_precision_var, 0, num_no_bound()),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
ret_var: list_var,
|
ret_var: list_var,
|
||||||
};
|
};
|
||||||
|
@ -2676,7 +2801,10 @@ fn list_drop_last(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
ret_var: len_var,
|
ret_var: len_var,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(arg_var, int::<i128>(num_var, num_precision_var, 1)),
|
(
|
||||||
|
arg_var,
|
||||||
|
int::<i128>(num_var, num_precision_var, 1, num_no_bound()),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
ret_var: len_var,
|
ret_var: len_var,
|
||||||
},
|
},
|
||||||
|
@ -2874,7 +3002,10 @@ fn list_min(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
op: LowLevel::NotEq,
|
op: LowLevel::NotEq,
|
||||||
args: vec![
|
args: vec![
|
||||||
(len_var, int::<i128>(num_var, num_precision_var, 0)),
|
(
|
||||||
|
len_var,
|
||||||
|
int::<i128>(num_var, num_precision_var, 0, num_no_bound()),
|
||||||
|
),
|
||||||
(
|
(
|
||||||
len_var,
|
len_var,
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
|
@ -2905,7 +3036,15 @@ fn list_min(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
op: LowLevel::ListGetUnsafe,
|
op: LowLevel::ListGetUnsafe,
|
||||||
args: vec![
|
args: vec![
|
||||||
(list_var, Var(Symbol::ARG_1)),
|
(list_var, Var(Symbol::ARG_1)),
|
||||||
(arg_var, int::<i128>(num_var, num_precision_var, 0)),
|
(
|
||||||
|
arg_var,
|
||||||
|
int::<i128>(
|
||||||
|
num_var,
|
||||||
|
num_precision_var,
|
||||||
|
0,
|
||||||
|
num_no_bound(),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
ret_var: list_elem_var,
|
ret_var: list_elem_var,
|
||||||
},
|
},
|
||||||
|
@ -3004,7 +3143,10 @@ fn list_max(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
op: LowLevel::NotEq,
|
op: LowLevel::NotEq,
|
||||||
args: vec![
|
args: vec![
|
||||||
(len_var, int::<i128>(num_var, num_precision_var, 0)),
|
(
|
||||||
|
len_var,
|
||||||
|
int::<i128>(num_var, num_precision_var, 0, num_no_bound()),
|
||||||
|
),
|
||||||
(
|
(
|
||||||
len_var,
|
len_var,
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
|
@ -3035,7 +3177,15 @@ fn list_max(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
op: LowLevel::ListGetUnsafe,
|
op: LowLevel::ListGetUnsafe,
|
||||||
args: vec![
|
args: vec![
|
||||||
(list_var, Var(Symbol::ARG_1)),
|
(list_var, Var(Symbol::ARG_1)),
|
||||||
(arg_var, int::<i128>(num_var, num_precision_var, 0)),
|
(
|
||||||
|
arg_var,
|
||||||
|
int::<i128>(
|
||||||
|
num_var,
|
||||||
|
num_precision_var,
|
||||||
|
0,
|
||||||
|
num_no_bound(),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
ret_var: list_elem_var,
|
ret_var: list_elem_var,
|
||||||
},
|
},
|
||||||
|
@ -3129,7 +3279,10 @@ fn list_sum(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
Box::new(function),
|
Box::new(function),
|
||||||
vec![
|
vec![
|
||||||
(list_var, Loc::at_zero(Var(Symbol::ARG_1))),
|
(list_var, Loc::at_zero(Var(Symbol::ARG_1))),
|
||||||
(num_var, Loc::at_zero(num(var_store.fresh(), 0))),
|
(
|
||||||
|
num_var,
|
||||||
|
Loc::at_zero(num(var_store.fresh(), 0, num_no_bound())),
|
||||||
|
),
|
||||||
(closure_var, Loc::at_zero(Var(Symbol::NUM_ADD))),
|
(closure_var, Loc::at_zero(Var(Symbol::NUM_ADD))),
|
||||||
],
|
],
|
||||||
CalledVia::Space,
|
CalledVia::Space,
|
||||||
|
@ -3161,7 +3314,10 @@ fn list_product(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
Box::new(function),
|
Box::new(function),
|
||||||
vec![
|
vec![
|
||||||
(list_var, Loc::at_zero(Var(Symbol::ARG_1))),
|
(list_var, Loc::at_zero(Var(Symbol::ARG_1))),
|
||||||
(num_var, Loc::at_zero(num(var_store.fresh(), 1))),
|
(
|
||||||
|
num_var,
|
||||||
|
Loc::at_zero(num(var_store.fresh(), 1, num_no_bound())),
|
||||||
|
),
|
||||||
(closure_var, Loc::at_zero(Var(Symbol::NUM_MUL))),
|
(closure_var, Loc::at_zero(Var(Symbol::NUM_MUL))),
|
||||||
],
|
],
|
||||||
CalledVia::Space,
|
CalledVia::Space,
|
||||||
|
@ -3815,7 +3971,7 @@ fn num_rem(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
op: LowLevel::NotEq,
|
op: LowLevel::NotEq,
|
||||||
args: vec![
|
args: vec![
|
||||||
(num_var, Var(Symbol::ARG_2)),
|
(num_var, Var(Symbol::ARG_2)),
|
||||||
(num_var, num(unbound_zero_var, 0)),
|
(num_var, num(unbound_zero_var, 0, num_no_bound())),
|
||||||
],
|
],
|
||||||
ret_var: bool_var,
|
ret_var: bool_var,
|
||||||
},
|
},
|
||||||
|
@ -3918,7 +4074,10 @@ fn num_div_float(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
op: LowLevel::NotEq,
|
op: LowLevel::NotEq,
|
||||||
args: vec![
|
args: vec![
|
||||||
(num_var, Var(Symbol::ARG_2)),
|
(num_var, Var(Symbol::ARG_2)),
|
||||||
(num_var, float(unbound_zero_var, precision_var, 0.0)),
|
(
|
||||||
|
num_var,
|
||||||
|
float(unbound_zero_var, precision_var, 0.0, num_no_bound()),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
ret_var: bool_var,
|
ret_var: bool_var,
|
||||||
},
|
},
|
||||||
|
@ -3983,7 +4142,12 @@ fn num_div_int(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
(num_var, Var(Symbol::ARG_2)),
|
(num_var, Var(Symbol::ARG_2)),
|
||||||
(
|
(
|
||||||
num_var,
|
num_var,
|
||||||
int::<i128>(unbound_zero_var, unbound_zero_precision_var, 0),
|
int::<i128>(
|
||||||
|
unbound_zero_var,
|
||||||
|
unbound_zero_precision_var,
|
||||||
|
0,
|
||||||
|
num_no_bound(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
ret_var: bool_var,
|
ret_var: bool_var,
|
||||||
|
@ -4049,7 +4213,12 @@ fn num_div_ceil(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
(num_var, Var(Symbol::ARG_2)),
|
(num_var, Var(Symbol::ARG_2)),
|
||||||
(
|
(
|
||||||
num_var,
|
num_var,
|
||||||
int::<i128>(unbound_zero_var, unbound_zero_precision_var, 0),
|
int::<i128>(
|
||||||
|
unbound_zero_var,
|
||||||
|
unbound_zero_precision_var,
|
||||||
|
0,
|
||||||
|
num_no_bound(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
ret_var: bool_var,
|
ret_var: bool_var,
|
||||||
|
@ -4119,7 +4288,10 @@ fn list_first(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
op: LowLevel::NotEq,
|
op: LowLevel::NotEq,
|
||||||
args: vec![
|
args: vec![
|
||||||
(len_var, int::<i128>(zero_var, zero_precision_var, 0)),
|
(
|
||||||
|
len_var,
|
||||||
|
int::<i128>(zero_var, zero_precision_var, 0, num_no_bound()),
|
||||||
|
),
|
||||||
(
|
(
|
||||||
len_var,
|
len_var,
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
|
@ -4143,7 +4315,10 @@ fn list_first(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
op: LowLevel::ListGetUnsafe,
|
op: LowLevel::ListGetUnsafe,
|
||||||
args: vec![
|
args: vec![
|
||||||
(list_var, Var(Symbol::ARG_1)),
|
(list_var, Var(Symbol::ARG_1)),
|
||||||
(len_var, int::<i128>(zero_var, zero_precision_var, 0)),
|
(
|
||||||
|
len_var,
|
||||||
|
int::<i128>(zero_var, zero_precision_var, 0, num_no_bound()),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
ret_var: list_elem_var,
|
ret_var: list_elem_var,
|
||||||
},
|
},
|
||||||
|
@ -4200,7 +4375,10 @@ fn list_last(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
op: LowLevel::NotEq,
|
op: LowLevel::NotEq,
|
||||||
args: vec![
|
args: vec![
|
||||||
(len_var, int::<i128>(num_var, num_precision_var, 0)),
|
(
|
||||||
|
len_var,
|
||||||
|
int::<i128>(num_var, num_precision_var, 0, num_no_bound()),
|
||||||
|
),
|
||||||
(
|
(
|
||||||
len_var,
|
len_var,
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
|
@ -4239,7 +4417,15 @@ fn list_last(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
ret_var: len_var,
|
ret_var: len_var,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(arg_var, int::<i128>(num_var, num_precision_var, 1)),
|
(
|
||||||
|
arg_var,
|
||||||
|
int::<i128>(
|
||||||
|
num_var,
|
||||||
|
num_precision_var,
|
||||||
|
1,
|
||||||
|
num_no_bound(),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
ret_var: len_var,
|
ret_var: len_var,
|
||||||
},
|
},
|
||||||
|
@ -4867,7 +5053,10 @@ fn num_bytes_to(symbol: Symbol, var_store: &mut VarStore, offset: i64, low_level
|
||||||
add_var,
|
add_var,
|
||||||
RunLowLevel {
|
RunLowLevel {
|
||||||
ret_var: cast_var,
|
ret_var: cast_var,
|
||||||
args: vec![(cast_var, num(var_store.fresh(), offset))],
|
args: vec![(
|
||||||
|
cast_var,
|
||||||
|
num(var_store.fresh(), offset, num_no_bound()),
|
||||||
|
)],
|
||||||
op: LowLevel::NumIntCast,
|
op: LowLevel::NumIntCast,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -4955,13 +5144,18 @@ fn defn_help(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn int_min_or_max<I128>(symbol: Symbol, var_store: &mut VarStore, i: I128) -> Def
|
fn int_min_or_max<I128>(
|
||||||
|
symbol: Symbol,
|
||||||
|
var_store: &mut VarStore,
|
||||||
|
i: I128,
|
||||||
|
bound: NumericBound<IntWidth>,
|
||||||
|
) -> Def
|
||||||
where
|
where
|
||||||
I128: Into<i128>,
|
I128: Into<i128>,
|
||||||
{
|
{
|
||||||
let int_var = var_store.fresh();
|
let int_var = var_store.fresh();
|
||||||
let int_precision_var = var_store.fresh();
|
let int_precision_var = var_store.fresh();
|
||||||
let body = int::<I128>(int_var, int_precision_var, i);
|
let body = int::<I128>(int_var, int_precision_var, i, bound);
|
||||||
|
|
||||||
let std = roc_builtins::std::types();
|
let std = roc_builtins::std::types();
|
||||||
let solved = std.get(&symbol).unwrap();
|
let solved = std.get(&symbol).unwrap();
|
||||||
|
@ -4984,21 +5178,53 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn num_no_bound<W: Copy>() -> NumericBound<W> {
|
||||||
|
NumericBound::None
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn int<I128>(num_var: Variable, precision_var: Variable, i: I128) -> Expr
|
fn int<I128>(
|
||||||
|
num_var: Variable,
|
||||||
|
precision_var: Variable,
|
||||||
|
i: I128,
|
||||||
|
bound: NumericBound<IntWidth>,
|
||||||
|
) -> Expr
|
||||||
where
|
where
|
||||||
I128: Into<i128>,
|
I128: Into<i128>,
|
||||||
{
|
{
|
||||||
let ii = i.into();
|
let ii = i.into();
|
||||||
Int(num_var, precision_var, ii.to_string().into_boxed_str(), ii)
|
Int(
|
||||||
|
num_var,
|
||||||
|
precision_var,
|
||||||
|
ii.to_string().into_boxed_str(),
|
||||||
|
IntValue::I128(ii),
|
||||||
|
bound,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn float(num_var: Variable, precision_var: Variable, f: f64) -> Expr {
|
fn float(
|
||||||
Float(num_var, precision_var, f.to_string().into_boxed_str(), f)
|
num_var: Variable,
|
||||||
|
precision_var: Variable,
|
||||||
|
f: f64,
|
||||||
|
bound: NumericBound<FloatWidth>,
|
||||||
|
) -> Expr {
|
||||||
|
Float(
|
||||||
|
num_var,
|
||||||
|
precision_var,
|
||||||
|
f.to_string().into_boxed_str(),
|
||||||
|
f,
|
||||||
|
bound,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn num(num_var: Variable, i: i64) -> Expr {
|
fn num<I: Into<i128>>(num_var: Variable, i: I, bound: NumericBound<NumWidth>) -> Expr {
|
||||||
Num(num_var, i.to_string().into_boxed_str(), i)
|
let i = i.into();
|
||||||
|
Num(
|
||||||
|
num_var,
|
||||||
|
i.to_string().into_boxed_str(),
|
||||||
|
IntValue::I128(i),
|
||||||
|
bound,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -840,9 +840,9 @@ fn pattern_to_vars_by_symbol(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NumLiteral(_, _, _)
|
NumLiteral(..)
|
||||||
| IntLiteral(_, _, _)
|
| IntLiteral(..)
|
||||||
| FloatLiteral(_, _, _)
|
| FloatLiteral(..)
|
||||||
| StrLiteral(_)
|
| StrLiteral(_)
|
||||||
| Underscore
|
| Underscore
|
||||||
| MalformedPattern(_, _)
|
| MalformedPattern(_, _)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use roc_can::annotation::IntroducedVariables;
|
use crate::annotation::IntroducedVariables;
|
||||||
use roc_can::def::{Declaration, Def};
|
use crate::def::{Declaration, Def};
|
||||||
use roc_can::env::Env;
|
use crate::env::Env;
|
||||||
use roc_can::expr::{ClosureData, Expr, Recursive};
|
use crate::expr::{ClosureData, Expr, Recursive};
|
||||||
use roc_can::pattern::Pattern;
|
use crate::pattern::Pattern;
|
||||||
use roc_can::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use roc_collections::all::{MutSet, SendMap};
|
use roc_collections::all::{MutSet, SendMap};
|
||||||
use roc_module::called_via::CalledVia;
|
use roc_module::called_via::CalledVia;
|
||||||
use roc_module::ident::TagName;
|
use roc_module::ident::TagName;
|
||||||
|
@ -220,7 +220,7 @@ fn build_effect_always(
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let def_annotation = roc_can::def::Annotation {
|
let def_annotation = crate::def::Annotation {
|
||||||
signature,
|
signature,
|
||||||
introduced_variables,
|
introduced_variables,
|
||||||
aliases: SendMap::default(),
|
aliases: SendMap::default(),
|
||||||
|
@ -432,7 +432,7 @@ fn build_effect_map(
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let def_annotation = roc_can::def::Annotation {
|
let def_annotation = crate::def::Annotation {
|
||||||
signature,
|
signature,
|
||||||
introduced_variables,
|
introduced_variables,
|
||||||
aliases: SendMap::default(),
|
aliases: SendMap::default(),
|
||||||
|
@ -599,7 +599,7 @@ fn build_effect_after(
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let def_annotation = roc_can::def::Annotation {
|
let def_annotation = crate::def::Annotation {
|
||||||
signature,
|
signature,
|
||||||
introduced_variables,
|
introduced_variables,
|
||||||
aliases: SendMap::default(),
|
aliases: SendMap::default(),
|
||||||
|
@ -852,7 +852,7 @@ fn build_effect_forever(
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let def_annotation = roc_can::def::Annotation {
|
let def_annotation = crate::def::Annotation {
|
||||||
signature,
|
signature,
|
||||||
introduced_variables,
|
introduced_variables,
|
||||||
aliases: SendMap::default(),
|
aliases: SendMap::default(),
|
||||||
|
@ -1150,7 +1150,7 @@ fn build_effect_loop(
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let def_annotation = roc_can::def::Annotation {
|
let def_annotation = crate::def::Annotation {
|
||||||
signature,
|
signature,
|
||||||
introduced_variables,
|
introduced_variables,
|
||||||
aliases: SendMap::default(),
|
aliases: SendMap::default(),
|
||||||
|
@ -1334,7 +1334,7 @@ fn build_effect_loop_inner_body(
|
||||||
|
|
||||||
let step_pattern = applied_tag_pattern(step_tag_name, &[new_state_symbol], var_store);
|
let step_pattern = applied_tag_pattern(step_tag_name, &[new_state_symbol], var_store);
|
||||||
|
|
||||||
roc_can::expr::WhenBranch {
|
crate::expr::WhenBranch {
|
||||||
patterns: vec![Loc::at_zero(step_pattern)],
|
patterns: vec![Loc::at_zero(step_pattern)],
|
||||||
value: Loc::at_zero(force_thunk2),
|
value: Loc::at_zero(force_thunk2),
|
||||||
guard: None,
|
guard: None,
|
||||||
|
@ -1345,7 +1345,7 @@ fn build_effect_loop_inner_body(
|
||||||
let done_tag_name = TagName::Global("Done".into());
|
let done_tag_name = TagName::Global("Done".into());
|
||||||
let done_pattern = applied_tag_pattern(done_tag_name, &[done_symbol], var_store);
|
let done_pattern = applied_tag_pattern(done_tag_name, &[done_symbol], var_store);
|
||||||
|
|
||||||
roc_can::expr::WhenBranch {
|
crate::expr::WhenBranch {
|
||||||
patterns: vec![Loc::at_zero(done_pattern)],
|
patterns: vec![Loc::at_zero(done_pattern)],
|
||||||
value: Loc::at_zero(Expr::Var(done_symbol)),
|
value: Loc::at_zero(Expr::Var(done_symbol)),
|
||||||
guard: None,
|
guard: None,
|
||||||
|
@ -1376,7 +1376,7 @@ pub fn build_host_exposed_def(
|
||||||
ident: &str,
|
ident: &str,
|
||||||
effect_tag_name: TagName,
|
effect_tag_name: TagName,
|
||||||
var_store: &mut VarStore,
|
var_store: &mut VarStore,
|
||||||
annotation: roc_can::annotation::Annotation,
|
annotation: crate::annotation::Annotation,
|
||||||
) -> Def {
|
) -> Def {
|
||||||
let expr_var = var_store.fresh();
|
let expr_var = var_store.fresh();
|
||||||
let pattern = Pattern::Identifier(symbol);
|
let pattern = Pattern::Identifier(symbol);
|
||||||
|
@ -1520,7 +1520,7 @@ pub fn build_host_exposed_def(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let def_annotation = roc_can::def::Annotation {
|
let def_annotation = crate::def::Annotation {
|
||||||
signature: annotation.typ,
|
signature: annotation.typ,
|
||||||
introduced_variables: annotation.introduced_variables,
|
introduced_variables: annotation.introduced_variables,
|
||||||
aliases: annotation.aliases,
|
aliases: annotation.aliases,
|
|
@ -3,8 +3,8 @@ use crate::builtins::builtin_defs_map;
|
||||||
use crate::def::{can_defs_with_return, Def};
|
use crate::def::{can_defs_with_return, Def};
|
||||||
use crate::env::Env;
|
use crate::env::Env;
|
||||||
use crate::num::{
|
use crate::num::{
|
||||||
finish_parsing_base, finish_parsing_float, finish_parsing_int, float_expr_from_result,
|
finish_parsing_base, finish_parsing_float, finish_parsing_num, float_expr_from_result,
|
||||||
int_expr_from_result, num_expr_from_result,
|
int_expr_from_result, num_expr_from_result, FloatWidth, IntWidth, NumWidth, NumericBound,
|
||||||
};
|
};
|
||||||
use crate::pattern::{canonicalize_pattern, Pattern};
|
use crate::pattern::{canonicalize_pattern, Pattern};
|
||||||
use crate::procedure::References;
|
use crate::procedure::References;
|
||||||
|
@ -20,7 +20,7 @@ use roc_problem::can::{PrecedenceProblem, Problem, RuntimeError};
|
||||||
use roc_region::all::{Loc, Region};
|
use roc_region::all::{Loc, Region};
|
||||||
use roc_types::subs::{VarStore, Variable};
|
use roc_types::subs::{VarStore, Variable};
|
||||||
use roc_types::types::Alias;
|
use roc_types::types::Alias;
|
||||||
use std::fmt::Debug;
|
use std::fmt::{Debug, Display};
|
||||||
use std::{char, u32};
|
use std::{char, u32};
|
||||||
|
|
||||||
#[derive(Clone, Default, Debug, PartialEq)]
|
#[derive(Clone, Default, Debug, PartialEq)]
|
||||||
|
@ -46,17 +46,38 @@ impl Output {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum IntValue {
|
||||||
|
I128(i128),
|
||||||
|
U128(u128),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for IntValue {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
IntValue::I128(n) => Display::fmt(&n, f),
|
||||||
|
IntValue::U128(n) => Display::fmt(&n, f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
// Literals
|
// Literals
|
||||||
|
|
||||||
// Num stores the `a` variable in `Num a`. Not the same as the variable
|
// Num stores the `a` variable in `Num a`. Not the same as the variable
|
||||||
// stored in Int and Float below, which is strictly for better error messages
|
// stored in Int and Float below, which is strictly for better error messages
|
||||||
Num(Variable, Box<str>, i64),
|
Num(Variable, Box<str>, IntValue, NumericBound<NumWidth>),
|
||||||
|
|
||||||
// Int and Float store a variable to generate better error messages
|
// Int and Float store a variable to generate better error messages
|
||||||
Int(Variable, Variable, Box<str>, i128),
|
Int(
|
||||||
Float(Variable, Variable, Box<str>, f64),
|
Variable,
|
||||||
|
Variable,
|
||||||
|
Box<str>,
|
||||||
|
IntValue,
|
||||||
|
NumericBound<IntWidth>,
|
||||||
|
),
|
||||||
|
Float(Variable, Variable, Box<str>, f64, NumericBound<FloatWidth>),
|
||||||
Str(Box<str>),
|
Str(Box<str>),
|
||||||
List {
|
List {
|
||||||
elem_var: Variable,
|
elem_var: Variable,
|
||||||
|
@ -208,20 +229,20 @@ pub fn canonicalize_expr<'a>(
|
||||||
use Expr::*;
|
use Expr::*;
|
||||||
|
|
||||||
let (expr, output) = match expr {
|
let (expr, output) = match expr {
|
||||||
ast::Expr::Num(str) => {
|
&ast::Expr::Num(str) => {
|
||||||
let answer = num_expr_from_result(
|
let answer = num_expr_from_result(
|
||||||
var_store,
|
var_store,
|
||||||
finish_parsing_int(*str).map(|int| (*str, int)),
|
finish_parsing_num(str).map(|result| (str, result)),
|
||||||
region,
|
region,
|
||||||
env,
|
env,
|
||||||
);
|
);
|
||||||
|
|
||||||
(answer, Output::default())
|
(answer, Output::default())
|
||||||
}
|
}
|
||||||
ast::Expr::Float(str) => {
|
&ast::Expr::Float(str) => {
|
||||||
let answer = float_expr_from_result(
|
let answer = float_expr_from_result(
|
||||||
var_store,
|
var_store,
|
||||||
finish_parsing_float(str).map(|f| (*str, f)),
|
finish_parsing_float(str).map(|(f, bound)| (str, f, bound)),
|
||||||
region,
|
region,
|
||||||
env,
|
env,
|
||||||
);
|
);
|
||||||
|
@ -790,21 +811,21 @@ pub fn canonicalize_expr<'a>(
|
||||||
|
|
||||||
(RuntimeError(problem), Output::default())
|
(RuntimeError(problem), Output::default())
|
||||||
}
|
}
|
||||||
ast::Expr::NonBase10Int {
|
&ast::Expr::NonBase10Int {
|
||||||
string,
|
string,
|
||||||
base,
|
base,
|
||||||
is_negative,
|
is_negative,
|
||||||
} => {
|
} => {
|
||||||
// the minus sign is added before parsing, to get correct overflow/underflow behavior
|
// the minus sign is added before parsing, to get correct overflow/underflow behavior
|
||||||
let answer = match finish_parsing_base(string, *base, *is_negative) {
|
let answer = match finish_parsing_base(string, base, is_negative) {
|
||||||
Ok(int) => {
|
Ok((int, bound)) => {
|
||||||
// Done in this kinda round about way with intermediate variables
|
// Done in this kinda round about way with intermediate variables
|
||||||
// to keep borrowed values around and make this compile
|
// to keep borrowed values around and make this compile
|
||||||
let int_string = int.to_string();
|
let int_string = int.to_string();
|
||||||
let int_str = int_string.as_str();
|
let int_str = int_string.as_str();
|
||||||
int_expr_from_result(var_store, Ok((int_str, int as i128)), region, *base, env)
|
int_expr_from_result(var_store, Ok((int_str, int, bound)), region, base, env)
|
||||||
}
|
}
|
||||||
Err(e) => int_expr_from_result(var_store, Err(e), region, *base, env),
|
Err(e) => int_expr_from_result(var_store, Err(e), region, base, env),
|
||||||
};
|
};
|
||||||
|
|
||||||
(answer, Output::default())
|
(answer, Output::default())
|
||||||
|
@ -1226,9 +1247,9 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
|
||||||
match expr {
|
match expr {
|
||||||
// Num stores the `a` variable in `Num a`. Not the same as the variable
|
// Num stores the `a` variable in `Num a`. Not the same as the variable
|
||||||
// stored in Int and Float below, which is strictly for better error messages
|
// stored in Int and Float below, which is strictly for better error messages
|
||||||
other @ Num(_, _, _)
|
other @ Num(..)
|
||||||
| other @ Int(_, _, _, _)
|
| other @ Int(..)
|
||||||
| other @ Float(_, _, _, _)
|
| other @ Float(..)
|
||||||
| other @ Str { .. }
|
| other @ Str { .. }
|
||||||
| other @ RuntimeError(_)
|
| other @ RuntimeError(_)
|
||||||
| other @ EmptyRecord
|
| other @ EmptyRecord
|
||||||
|
|
|
@ -5,6 +5,7 @@ pub mod annotation;
|
||||||
pub mod builtins;
|
pub mod builtins;
|
||||||
pub mod constraint;
|
pub mod constraint;
|
||||||
pub mod def;
|
pub mod def;
|
||||||
|
pub mod effect_module;
|
||||||
pub mod env;
|
pub mod env;
|
||||||
pub mod expected;
|
pub mod expected;
|
||||||
pub mod expr;
|
pub mod expr;
|
||||||
|
|
|
@ -6,15 +6,16 @@ use crate::pattern::Pattern;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_collections::all::{MutMap, MutSet, SendMap};
|
use roc_collections::all::{MutMap, MutSet, SendMap};
|
||||||
use roc_module::ident::Ident;
|
|
||||||
use roc_module::ident::Lowercase;
|
use roc_module::ident::Lowercase;
|
||||||
|
use roc_module::ident::{Ident, TagName};
|
||||||
use roc_module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol};
|
use roc_module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol};
|
||||||
use roc_parse::ast;
|
use roc_parse::ast;
|
||||||
|
use roc_parse::header::HeaderFor;
|
||||||
use roc_parse::pattern::PatternType;
|
use roc_parse::pattern::PatternType;
|
||||||
use roc_problem::can::{Problem, RuntimeError};
|
use roc_problem::can::{Problem, RuntimeError};
|
||||||
use roc_region::all::{Loc, Region};
|
use roc_region::all::{Loc, Region};
|
||||||
use roc_types::subs::{VarStore, Variable};
|
use roc_types::subs::{VarStore, Variable};
|
||||||
use roc_types::types::Alias;
|
use roc_types::types::{Alias, Type};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
|
@ -44,6 +45,7 @@ pub struct ModuleOutput {
|
||||||
pub fn canonicalize_module_defs<'a, F>(
|
pub fn canonicalize_module_defs<'a, F>(
|
||||||
arena: &Bump,
|
arena: &Bump,
|
||||||
loc_defs: &'a [Loc<ast::Def<'a>>],
|
loc_defs: &'a [Loc<ast::Def<'a>>],
|
||||||
|
header_for: &roc_parse::header::HeaderFor,
|
||||||
home: ModuleId,
|
home: ModuleId,
|
||||||
module_ids: &ModuleIds,
|
module_ids: &ModuleIds,
|
||||||
exposed_ident_ids: IdentIds,
|
exposed_ident_ids: IdentIds,
|
||||||
|
@ -59,12 +61,49 @@ where
|
||||||
{
|
{
|
||||||
let mut can_exposed_imports = MutMap::default();
|
let mut can_exposed_imports = MutMap::default();
|
||||||
let mut scope = Scope::new(home, var_store);
|
let mut scope = Scope::new(home, var_store);
|
||||||
|
let mut env = Env::new(home, dep_idents, module_ids, exposed_ident_ids);
|
||||||
let num_deps = dep_idents.len();
|
let num_deps = dep_idents.len();
|
||||||
|
|
||||||
for (name, alias) in aliases.into_iter() {
|
for (name, alias) in aliases.into_iter() {
|
||||||
scope.add_alias(name, alias.region, alias.type_variables, alias.typ);
|
scope.add_alias(name, alias.region, alias.type_variables, alias.typ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let effect_symbol = if let HeaderFor::Hosted { generates, .. } = header_for {
|
||||||
|
// TODO extract effect name from the header
|
||||||
|
let name: &str = generates.into();
|
||||||
|
let effect_symbol = scope
|
||||||
|
.introduce(
|
||||||
|
name.into(),
|
||||||
|
&env.exposed_ident_ids,
|
||||||
|
&mut env.ident_ids,
|
||||||
|
Region::zero(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let effect_tag_name = TagName::Private(effect_symbol);
|
||||||
|
|
||||||
|
{
|
||||||
|
let a_var = var_store.fresh();
|
||||||
|
|
||||||
|
let actual = crate::effect_module::build_effect_actual(
|
||||||
|
effect_tag_name,
|
||||||
|
Type::Variable(a_var),
|
||||||
|
var_store,
|
||||||
|
);
|
||||||
|
|
||||||
|
scope.add_alias(
|
||||||
|
effect_symbol,
|
||||||
|
Region::zero(),
|
||||||
|
vec![Loc::at_zero(("a".into(), a_var))],
|
||||||
|
actual,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(effect_symbol)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
// Desugar operators (convert them to Apply calls, taking into account
|
// Desugar operators (convert them to Apply calls, taking into account
|
||||||
// operator precedence and associativity rules), before doing other canonicalization.
|
// operator precedence and associativity rules), before doing other canonicalization.
|
||||||
//
|
//
|
||||||
|
@ -82,7 +121,6 @@ where
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut env = Env::new(home, dep_idents, module_ids, exposed_ident_ids);
|
|
||||||
let mut lookups = Vec::with_capacity(num_deps);
|
let mut lookups = Vec::with_capacity(num_deps);
|
||||||
let mut rigid_variables = MutMap::default();
|
let mut rigid_variables = MutMap::default();
|
||||||
|
|
||||||
|
@ -143,7 +181,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (defs, scope, output, symbols_introduced) = canonicalize_defs(
|
let (defs, mut scope, output, symbols_introduced) = canonicalize_defs(
|
||||||
&mut env,
|
&mut env,
|
||||||
Output::default(),
|
Output::default(),
|
||||||
var_store,
|
var_store,
|
||||||
|
@ -208,7 +246,21 @@ where
|
||||||
(Ok(mut declarations), output) => {
|
(Ok(mut declarations), output) => {
|
||||||
use crate::def::Declaration::*;
|
use crate::def::Declaration::*;
|
||||||
|
|
||||||
for decl in declarations.iter() {
|
if let Some(effect_symbol) = effect_symbol {
|
||||||
|
let mut exposed_symbols = MutSet::default();
|
||||||
|
|
||||||
|
// NOTE this currently builds all functions, not just the ones that the user requested
|
||||||
|
crate::effect_module::build_effect_builtins(
|
||||||
|
&mut env,
|
||||||
|
&mut scope,
|
||||||
|
effect_symbol,
|
||||||
|
var_store,
|
||||||
|
&mut exposed_symbols,
|
||||||
|
&mut declarations,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for decl in declarations.iter_mut() {
|
||||||
match decl {
|
match decl {
|
||||||
Declare(def) => {
|
Declare(def) => {
|
||||||
for (symbol, _) in def.pattern_vars.iter() {
|
for (symbol, _) in def.pattern_vars.iter() {
|
||||||
|
@ -221,6 +273,59 @@ where
|
||||||
exposed_but_not_defined.remove(symbol);
|
exposed_but_not_defined.remove(symbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Temporary hack: we don't know exactly what symbols are hosted symbols,
|
||||||
|
// and which are meant to be normal definitions without a body. So for now
|
||||||
|
// we just assume they are hosted functions (meant to be provided by the platform)
|
||||||
|
if let Some(effect_symbol) = effect_symbol {
|
||||||
|
macro_rules! make_hosted_def {
|
||||||
|
() => {
|
||||||
|
let symbol = def.pattern_vars.iter().next().unwrap().0;
|
||||||
|
let ident_id = symbol.ident_id();
|
||||||
|
let ident =
|
||||||
|
env.ident_ids.get_name(ident_id).unwrap().to_string();
|
||||||
|
let def_annotation = def.annotation.clone().unwrap();
|
||||||
|
let annotation = crate::annotation::Annotation {
|
||||||
|
typ: def_annotation.signature,
|
||||||
|
introduced_variables: def_annotation.introduced_variables,
|
||||||
|
references: Default::default(),
|
||||||
|
aliases: Default::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let hosted_def = crate::effect_module::build_host_exposed_def(
|
||||||
|
&mut env,
|
||||||
|
&mut scope,
|
||||||
|
*symbol,
|
||||||
|
&ident,
|
||||||
|
TagName::Private(effect_symbol),
|
||||||
|
var_store,
|
||||||
|
annotation,
|
||||||
|
);
|
||||||
|
|
||||||
|
*def = hosted_def;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
match &def.loc_expr.value {
|
||||||
|
Expr::RuntimeError(RuntimeError::NoImplementationNamed {
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
make_hosted_def!();
|
||||||
|
}
|
||||||
|
Expr::Closure(closure_data)
|
||||||
|
if matches!(
|
||||||
|
closure_data.loc_body.value,
|
||||||
|
Expr::RuntimeError(
|
||||||
|
RuntimeError::NoImplementationNamed { .. }
|
||||||
|
)
|
||||||
|
) =>
|
||||||
|
{
|
||||||
|
make_hosted_def!();
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DeclareRec(defs) => {
|
DeclareRec(defs) => {
|
||||||
for def in defs {
|
for def in defs {
|
||||||
|
@ -253,6 +358,18 @@ where
|
||||||
|
|
||||||
let mut aliases = MutMap::default();
|
let mut aliases = MutMap::default();
|
||||||
|
|
||||||
|
if let Some(effect_symbol) = effect_symbol {
|
||||||
|
// Remove this from exposed_symbols,
|
||||||
|
// so that at the end of the process,
|
||||||
|
// we can see if there were any
|
||||||
|
// exposed symbols which did not have
|
||||||
|
// corresponding defs.
|
||||||
|
exposed_but_not_defined.remove(&effect_symbol);
|
||||||
|
|
||||||
|
let hosted_alias = scope.lookup_alias(effect_symbol).unwrap().clone();
|
||||||
|
aliases.insert(effect_symbol, hosted_alias);
|
||||||
|
}
|
||||||
|
|
||||||
for (symbol, alias) in output.aliases {
|
for (symbol, alias) in output.aliases {
|
||||||
// Remove this from exposed_symbols,
|
// Remove this from exposed_symbols,
|
||||||
// so that at the end of the process,
|
// so that at the end of the process,
|
||||||
|
@ -397,9 +514,9 @@ fn fix_values_captured_in_closure_pattern(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Identifier(_)
|
Identifier(_)
|
||||||
| NumLiteral(_, _, _)
|
| NumLiteral(..)
|
||||||
| IntLiteral(_, _, _)
|
| IntLiteral(..)
|
||||||
| FloatLiteral(_, _, _)
|
| FloatLiteral(..)
|
||||||
| StrLiteral(_)
|
| StrLiteral(_)
|
||||||
| Underscore
|
| Underscore
|
||||||
| Shadowed(..)
|
| Shadowed(..)
|
||||||
|
@ -453,9 +570,9 @@ fn fix_values_captured_in_closure_expr(
|
||||||
fix_values_captured_in_closure_expr(&mut loc_body.value, no_capture_symbols);
|
fix_values_captured_in_closure_expr(&mut loc_body.value, no_capture_symbols);
|
||||||
}
|
}
|
||||||
|
|
||||||
Num(_, _, _)
|
Num(..)
|
||||||
| Int(_, _, _, _)
|
| Int(..)
|
||||||
| Float(_, _, _, _)
|
| Float(..)
|
||||||
| Str(_)
|
| Str(_)
|
||||||
| Var(_)
|
| Var(_)
|
||||||
| EmptyRecord
|
| EmptyRecord
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::env::Env;
|
use crate::env::Env;
|
||||||
use crate::expr::Expr;
|
use crate::expr::{Expr, IntValue};
|
||||||
use roc_parse::ast::Base;
|
use roc_parse::ast::Base;
|
||||||
use roc_problem::can::Problem;
|
use roc_problem::can::Problem;
|
||||||
use roc_problem::can::RuntimeError::*;
|
use roc_problem::can::RuntimeError::*;
|
||||||
|
@ -7,21 +7,33 @@ use roc_problem::can::{FloatErrorKind, IntErrorKind};
|
||||||
use roc_region::all::Region;
|
use roc_region::all::Region;
|
||||||
use roc_types::subs::VarStore;
|
use roc_types::subs::VarStore;
|
||||||
use std::i64;
|
use std::i64;
|
||||||
|
use std::str;
|
||||||
// TODO use rust's integer parsing again
|
|
||||||
//
|
|
||||||
// We're waiting for libcore here, see https://github.com/rust-lang/rust/issues/22639
|
|
||||||
// There is a nightly API for exposing the parse error.
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn num_expr_from_result(
|
pub fn num_expr_from_result(
|
||||||
var_store: &mut VarStore,
|
var_store: &mut VarStore,
|
||||||
result: Result<(&str, i64), (&str, IntErrorKind)>,
|
result: Result<(&str, ParsedNumResult), (&str, IntErrorKind)>,
|
||||||
region: Region,
|
region: Region,
|
||||||
env: &mut Env,
|
env: &mut Env,
|
||||||
) -> Expr {
|
) -> Expr {
|
||||||
match result {
|
match result {
|
||||||
Ok((str, num)) => Expr::Num(var_store.fresh(), (*str).into(), num),
|
Ok((str, ParsedNumResult::UnknownNum(num))) => {
|
||||||
|
Expr::Num(var_store.fresh(), (*str).into(), num, NumericBound::None)
|
||||||
|
}
|
||||||
|
Ok((str, ParsedNumResult::Int(num, bound))) => Expr::Int(
|
||||||
|
var_store.fresh(),
|
||||||
|
var_store.fresh(),
|
||||||
|
(*str).into(),
|
||||||
|
num,
|
||||||
|
bound,
|
||||||
|
),
|
||||||
|
Ok((str, ParsedNumResult::Float(num, bound))) => Expr::Float(
|
||||||
|
var_store.fresh(),
|
||||||
|
var_store.fresh(),
|
||||||
|
(*str).into(),
|
||||||
|
num,
|
||||||
|
bound,
|
||||||
|
),
|
||||||
Err((raw, error)) => {
|
Err((raw, error)) => {
|
||||||
// (Num *) compiles to Int if it doesn't
|
// (Num *) compiles to Int if it doesn't
|
||||||
// get specialized to something else first,
|
// get specialized to something else first,
|
||||||
|
@ -38,14 +50,20 @@ pub fn num_expr_from_result(
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn int_expr_from_result(
|
pub fn int_expr_from_result(
|
||||||
var_store: &mut VarStore,
|
var_store: &mut VarStore,
|
||||||
result: Result<(&str, i128), (&str, IntErrorKind)>,
|
result: Result<(&str, IntValue, NumericBound<IntWidth>), (&str, IntErrorKind)>,
|
||||||
region: Region,
|
region: Region,
|
||||||
base: Base,
|
base: Base,
|
||||||
env: &mut Env,
|
env: &mut Env,
|
||||||
) -> Expr {
|
) -> Expr {
|
||||||
// Int stores a variable to generate better error messages
|
// Int stores a variable to generate better error messages
|
||||||
match result {
|
match result {
|
||||||
Ok((str, int)) => Expr::Int(var_store.fresh(), var_store.fresh(), (*str).into(), int),
|
Ok((str, int, bound)) => Expr::Int(
|
||||||
|
var_store.fresh(),
|
||||||
|
var_store.fresh(),
|
||||||
|
(*str).into(),
|
||||||
|
int,
|
||||||
|
bound,
|
||||||
|
),
|
||||||
Err((raw, error)) => {
|
Err((raw, error)) => {
|
||||||
let runtime_error = InvalidInt(error, base, region, raw.into());
|
let runtime_error = InvalidInt(error, base, region, raw.into());
|
||||||
|
|
||||||
|
@ -59,13 +77,19 @@ pub fn int_expr_from_result(
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn float_expr_from_result(
|
pub fn float_expr_from_result(
|
||||||
var_store: &mut VarStore,
|
var_store: &mut VarStore,
|
||||||
result: Result<(&str, f64), (&str, FloatErrorKind)>,
|
result: Result<(&str, f64, NumericBound<FloatWidth>), (&str, FloatErrorKind)>,
|
||||||
region: Region,
|
region: Region,
|
||||||
env: &mut Env,
|
env: &mut Env,
|
||||||
) -> Expr {
|
) -> Expr {
|
||||||
// Float stores a variable to generate better error messages
|
// Float stores a variable to generate better error messages
|
||||||
match result {
|
match result {
|
||||||
Ok((str, float)) => Expr::Float(var_store.fresh(), var_store.fresh(), (*str).into(), float),
|
Ok((str, float, bound)) => Expr::Float(
|
||||||
|
var_store.fresh(),
|
||||||
|
var_store.fresh(),
|
||||||
|
(*str).into(),
|
||||||
|
float,
|
||||||
|
bound,
|
||||||
|
),
|
||||||
Err((raw, error)) => {
|
Err((raw, error)) => {
|
||||||
let runtime_error = InvalidFloat(error, region, raw.into());
|
let runtime_error = InvalidFloat(error, region, raw.into());
|
||||||
|
|
||||||
|
@ -76,11 +100,32 @@ pub fn float_expr_from_result(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum ParsedNumResult {
|
||||||
|
Int(IntValue, NumericBound<IntWidth>),
|
||||||
|
Float(f64, NumericBound<FloatWidth>),
|
||||||
|
UnknownNum(IntValue),
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn finish_parsing_int(raw: &str) -> Result<i64, (&str, IntErrorKind)> {
|
pub fn finish_parsing_num(raw: &str) -> Result<ParsedNumResult, (&str, IntErrorKind)> {
|
||||||
// Ignore underscores.
|
// Ignore underscores.
|
||||||
let radix = 10;
|
let radix = 10;
|
||||||
from_str_radix::<i64>(raw.replace("_", "").as_str(), radix).map_err(|e| (raw, e.kind))
|
let (num, bound) =
|
||||||
|
from_str_radix(raw.replace("_", "").as_str(), radix).map_err(|e| (raw, e))?;
|
||||||
|
// Let's try to specialize the number
|
||||||
|
Ok(match bound {
|
||||||
|
NumericBound::None => ParsedNumResult::UnknownNum(num),
|
||||||
|
NumericBound::Exact(NumWidth::Int(iw)) => {
|
||||||
|
ParsedNumResult::Int(num, NumericBound::Exact(iw))
|
||||||
|
}
|
||||||
|
NumericBound::Exact(NumWidth::Float(fw)) => {
|
||||||
|
let num = match num {
|
||||||
|
IntValue::I128(n) => n as f64,
|
||||||
|
IntValue::U128(n) => n as f64,
|
||||||
|
};
|
||||||
|
ParsedNumResult::Float(num, NumericBound::Exact(fw))
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -88,7 +133,7 @@ pub fn finish_parsing_base(
|
||||||
raw: &str,
|
raw: &str,
|
||||||
base: Base,
|
base: Base,
|
||||||
is_negative: bool,
|
is_negative: bool,
|
||||||
) -> Result<i64, (&str, IntErrorKind)> {
|
) -> Result<(IntValue, NumericBound<IntWidth>), (&str, IntErrorKind)> {
|
||||||
let radix = match base {
|
let radix = match base {
|
||||||
Base::Hex => 16,
|
Base::Hex => 16,
|
||||||
Base::Decimal => 10,
|
Base::Decimal => 10,
|
||||||
|
@ -98,18 +143,36 @@ pub fn finish_parsing_base(
|
||||||
|
|
||||||
// Ignore underscores, insert - when negative to get correct underflow/overflow behavior
|
// Ignore underscores, insert - when negative to get correct underflow/overflow behavior
|
||||||
(if is_negative {
|
(if is_negative {
|
||||||
from_str_radix::<i64>(format!("-{}", raw.replace("_", "")).as_str(), radix)
|
from_str_radix(format!("-{}", raw.replace("_", "")).as_str(), radix)
|
||||||
} else {
|
} else {
|
||||||
from_str_radix::<i64>(raw.replace("_", "").as_str(), radix)
|
from_str_radix(raw.replace("_", "").as_str(), radix)
|
||||||
})
|
})
|
||||||
.map_err(|e| (raw, e.kind))
|
.and_then(|(n, bound)| {
|
||||||
|
let bound = match bound {
|
||||||
|
NumericBound::None => NumericBound::None,
|
||||||
|
NumericBound::Exact(NumWidth::Int(iw)) => NumericBound::Exact(iw),
|
||||||
|
NumericBound::Exact(NumWidth::Float(_)) => return Err(IntErrorKind::FloatSuffix),
|
||||||
|
};
|
||||||
|
Ok((n, bound))
|
||||||
|
})
|
||||||
|
.map_err(|e| (raw, e))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn finish_parsing_float(raw: &str) -> Result<f64, (&str, FloatErrorKind)> {
|
pub fn finish_parsing_float(
|
||||||
|
raw: &str,
|
||||||
|
) -> Result<(f64, NumericBound<FloatWidth>), (&str, FloatErrorKind)> {
|
||||||
|
let (opt_bound, raw_without_suffix) = parse_literal_suffix(raw);
|
||||||
|
|
||||||
|
let bound = match opt_bound {
|
||||||
|
None => NumericBound::None,
|
||||||
|
Some(NumWidth::Float(fw)) => NumericBound::Exact(fw),
|
||||||
|
Some(NumWidth::Int(_)) => return Err((raw, FloatErrorKind::IntSuffix)),
|
||||||
|
};
|
||||||
|
|
||||||
// Ignore underscores.
|
// Ignore underscores.
|
||||||
match raw.replace("_", "").parse::<f64>() {
|
match raw_without_suffix.replace("_", "").parse::<f64>() {
|
||||||
Ok(float) if float.is_finite() => Ok(float),
|
Ok(float) if float.is_finite() => Ok((float, bound)),
|
||||||
Ok(float) => {
|
Ok(float) => {
|
||||||
if float.is_sign_positive() {
|
if float.is_sign_positive() {
|
||||||
Err((raw, FloatErrorKind::PositiveInfinity))
|
Err((raw, FloatErrorKind::PositiveInfinity))
|
||||||
|
@ -121,6 +184,35 @@ pub fn finish_parsing_float(raw: &str) -> Result<f64, (&str, FloatErrorKind)> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_literal_suffix(num_str: &str) -> (Option<NumWidth>, &str) {
|
||||||
|
macro_rules! parse_num_suffix {
|
||||||
|
($($suffix:expr, $width:expr)*) => {$(
|
||||||
|
if num_str.ends_with($suffix) {
|
||||||
|
return (Some($width), num_str.get(0..num_str.len() - $suffix.len()).unwrap());
|
||||||
|
}
|
||||||
|
)*}
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_num_suffix! {
|
||||||
|
"u8", NumWidth::Int(IntWidth::U8)
|
||||||
|
"u16", NumWidth::Int(IntWidth::U16)
|
||||||
|
"u32", NumWidth::Int(IntWidth::U32)
|
||||||
|
"u64", NumWidth::Int(IntWidth::U64)
|
||||||
|
"u128", NumWidth::Int(IntWidth::U128)
|
||||||
|
"i8", NumWidth::Int(IntWidth::I8)
|
||||||
|
"i16", NumWidth::Int(IntWidth::I16)
|
||||||
|
"i32", NumWidth::Int(IntWidth::I32)
|
||||||
|
"i64", NumWidth::Int(IntWidth::I64)
|
||||||
|
"i128", NumWidth::Int(IntWidth::I128)
|
||||||
|
"nat", NumWidth::Int(IntWidth::Nat)
|
||||||
|
"dec", NumWidth::Float(FloatWidth::Dec)
|
||||||
|
"f32", NumWidth::Float(FloatWidth::F32)
|
||||||
|
"f64", NumWidth::Float(FloatWidth::F64)
|
||||||
|
}
|
||||||
|
|
||||||
|
(None, num_str)
|
||||||
|
}
|
||||||
|
|
||||||
/// Integer parsing code taken from the rust libcore,
|
/// Integer parsing code taken from the rust libcore,
|
||||||
/// pulled in so we can give custom error messages
|
/// pulled in so we can give custom error messages
|
||||||
///
|
///
|
||||||
|
@ -129,44 +221,11 @@ pub fn finish_parsing_float(raw: &str) -> Result<f64, (&str, FloatErrorKind)> {
|
||||||
/// the LEGAL_DETAILS file in the root directory of this distribution.
|
/// the LEGAL_DETAILS file in the root directory of this distribution.
|
||||||
///
|
///
|
||||||
/// Thanks to the Rust project and its contributors!
|
/// Thanks to the Rust project and its contributors!
|
||||||
trait FromStrRadixHelper: PartialOrd + Copy {
|
fn from_str_radix(
|
||||||
fn min_value() -> Self;
|
src: &str,
|
||||||
fn max_value() -> Self;
|
radix: u32,
|
||||||
fn from_u32(u: u32) -> Self;
|
) -> Result<(IntValue, NumericBound<NumWidth>), IntErrorKind> {
|
||||||
fn checked_mul(&self, other: u32) -> Option<Self>;
|
|
||||||
fn checked_sub(&self, other: u32) -> Option<Self>;
|
|
||||||
fn checked_add(&self, other: u32) -> Option<Self>;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! doit {
|
|
||||||
($($t:ty)*) => ($(impl FromStrRadixHelper for $t {
|
|
||||||
#[inline]
|
|
||||||
fn min_value() -> Self { Self::min_value() }
|
|
||||||
#[inline]
|
|
||||||
fn max_value() -> Self { Self::max_value() }
|
|
||||||
#[inline]
|
|
||||||
fn from_u32(u: u32) -> Self { u as Self }
|
|
||||||
#[inline]
|
|
||||||
fn checked_mul(&self, other: u32) -> Option<Self> {
|
|
||||||
Self::checked_mul(*self, other as Self)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn checked_sub(&self, other: u32) -> Option<Self> {
|
|
||||||
Self::checked_sub(*self, other as Self)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn checked_add(&self, other: u32) -> Option<Self> {
|
|
||||||
Self::checked_add(*self, other as Self)
|
|
||||||
}
|
|
||||||
})*)
|
|
||||||
}
|
|
||||||
// We only need the i64 implementation, but libcore defines
|
|
||||||
// doit! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
|
|
||||||
doit! { i64 }
|
|
||||||
|
|
||||||
fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, ParseIntError> {
|
|
||||||
use self::IntErrorKind::*;
|
use self::IntErrorKind::*;
|
||||||
use self::ParseIntError as PIE;
|
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
(2..=36).contains(&radix),
|
(2..=36).contains(&radix),
|
||||||
|
@ -174,86 +233,260 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
|
||||||
radix
|
radix
|
||||||
);
|
);
|
||||||
|
|
||||||
if src.is_empty() {
|
let (opt_exact_bound, src) = parse_literal_suffix(src);
|
||||||
return Err(PIE { kind: Empty });
|
|
||||||
|
use std::num::IntErrorKind as StdIEK;
|
||||||
|
let result = match i128::from_str_radix(src, radix) {
|
||||||
|
Ok(result) => IntValue::I128(result),
|
||||||
|
Err(pie) => match pie.kind() {
|
||||||
|
StdIEK::Empty => return Err(IntErrorKind::Empty),
|
||||||
|
StdIEK::InvalidDigit => return Err(IntErrorKind::InvalidDigit),
|
||||||
|
StdIEK::NegOverflow => return Err(IntErrorKind::Underflow),
|
||||||
|
StdIEK::PosOverflow => {
|
||||||
|
// try a u128
|
||||||
|
match u128::from_str_radix(src, radix) {
|
||||||
|
Ok(result) => IntValue::U128(result),
|
||||||
|
Err(pie) => match pie.kind() {
|
||||||
|
StdIEK::InvalidDigit => return Err(IntErrorKind::InvalidDigit),
|
||||||
|
StdIEK::PosOverflow => return Err(IntErrorKind::Overflow),
|
||||||
|
StdIEK::Empty | StdIEK::Zero | StdIEK::NegOverflow => unreachable!(),
|
||||||
|
_ => unreachable!("I thought all possibilities were exhausted, but std::num added a new one")
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_signed_ty = T::from_u32(0) > T::min_value();
|
|
||||||
|
|
||||||
// all valid digits are ascii, so we will just iterate over the utf8 bytes
|
|
||||||
// and cast them to chars. .to_digit() will safely return None for anything
|
|
||||||
// other than a valid ascii digit for the given radix, including the first-byte
|
|
||||||
// of multi-byte sequences
|
|
||||||
let src = src.as_bytes();
|
|
||||||
|
|
||||||
let (is_positive, digits) = match src[0] {
|
|
||||||
b'+' => (true, &src[1..]),
|
|
||||||
b'-' if is_signed_ty => (false, &src[1..]),
|
|
||||||
_ => (true, src),
|
|
||||||
};
|
|
||||||
|
|
||||||
if digits.is_empty() {
|
|
||||||
return Err(PIE { kind: Empty });
|
|
||||||
}
|
}
|
||||||
|
StdIEK::Zero => unreachable!("Parsed a i128"),
|
||||||
|
_ => unreachable!(
|
||||||
|
"I thought all possibilities were exhausted, but std::num added a new one"
|
||||||
|
),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let mut result = T::from_u32(0);
|
let (lower_bound, is_negative) = match result {
|
||||||
if is_positive {
|
IntValue::I128(num) => (lower_bound_of_int(num), num <= 0),
|
||||||
// The number is positive
|
IntValue::U128(_) => (IntWidth::U128, false),
|
||||||
for &c in digits {
|
|
||||||
let x = match (c as char).to_digit(radix) {
|
|
||||||
Some(x) => x,
|
|
||||||
None => return Err(PIE { kind: InvalidDigit }),
|
|
||||||
};
|
|
||||||
result = match result.checked_mul(radix) {
|
|
||||||
Some(result) => result,
|
|
||||||
None => return Err(PIE { kind: Overflow }),
|
|
||||||
};
|
|
||||||
result = match result.checked_add(x) {
|
|
||||||
Some(result) => result,
|
|
||||||
None => return Err(PIE { kind: Overflow }),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
match opt_exact_bound {
|
||||||
|
None => {
|
||||||
|
// TODO: use the lower bound
|
||||||
|
Ok((result, NumericBound::None))
|
||||||
|
}
|
||||||
|
Some(bound @ NumWidth::Float(_)) => {
|
||||||
|
// For now, assume floats can represent all integers
|
||||||
|
// TODO: this is somewhat incorrect, revisit
|
||||||
|
Ok((result, NumericBound::Exact(bound)))
|
||||||
|
}
|
||||||
|
Some(NumWidth::Int(exact_width)) => {
|
||||||
|
// We need to check if the exact bound >= lower bound.
|
||||||
|
if exact_width.is_superset(&lower_bound, is_negative) {
|
||||||
|
// Great! Use the exact bound.
|
||||||
|
Ok((result, NumericBound::Exact(NumWidth::Int(exact_width))))
|
||||||
|
} else {
|
||||||
|
// This is something like 200i8; the lower bound is u8, which holds strictly more
|
||||||
|
// ints on the positive side than i8 does. Report an error depending on which side
|
||||||
|
// of the integers we checked.
|
||||||
|
let err = if is_negative {
|
||||||
|
UnderflowsSuffix {
|
||||||
|
suffix_type: exact_width.type_str(),
|
||||||
|
min_value: exact_width.min_value(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// The number is negative
|
OverflowsSuffix {
|
||||||
for &c in digits {
|
suffix_type: exact_width.type_str(),
|
||||||
let x = match (c as char).to_digit(radix) {
|
max_value: exact_width.max_value(),
|
||||||
Some(x) => x,
|
}
|
||||||
None => return Err(PIE { kind: InvalidDigit }),
|
|
||||||
};
|
|
||||||
result = match result.checked_mul(radix) {
|
|
||||||
Some(result) => result,
|
|
||||||
None => return Err(PIE { kind: Underflow }),
|
|
||||||
};
|
|
||||||
result = match result.checked_sub(x) {
|
|
||||||
Some(result) => result,
|
|
||||||
None => return Err(PIE { kind: Underflow }),
|
|
||||||
};
|
};
|
||||||
|
Err(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An error which can be returned when parsing an integer.
|
fn lower_bound_of_int(result: i128) -> IntWidth {
|
||||||
///
|
use IntWidth::*;
|
||||||
/// This error is used as the error type for the `from_str_radix()` functions
|
if result >= 0 {
|
||||||
/// on the primitive integer types, such as [`i8::from_str_radix`].
|
// Positive
|
||||||
///
|
let result = result as u128;
|
||||||
/// # Potential causes
|
if result > U64.max_value() {
|
||||||
///
|
I128
|
||||||
/// Among other causes, `ParseIntError` can be thrown because of leading or trailing whitespace
|
} else if result > I64.max_value() {
|
||||||
/// in the string e.g., when it is obtained from the standard input.
|
U64
|
||||||
/// Using the [`str.trim()`] method ensures that no whitespace remains before parsing.
|
} else if result > U32.max_value() {
|
||||||
///
|
I64
|
||||||
/// [`str.trim()`]: ../../std/primitive.str.html#method.trim
|
} else if result > I32.max_value() {
|
||||||
/// [`i8::from_str_radix`]: ../../std/primitive.i8.html#method.from_str_radix
|
U32
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
} else if result > U16.max_value() {
|
||||||
pub struct ParseIntError {
|
I32
|
||||||
kind: IntErrorKind,
|
} else if result > I16.max_value() {
|
||||||
}
|
U16
|
||||||
|
} else if result > U8.max_value() {
|
||||||
impl ParseIntError {
|
I16
|
||||||
/// Outputs the detailed cause of parsing an integer failing.
|
} else if result > I8.max_value() {
|
||||||
pub fn kind(&self) -> &IntErrorKind {
|
U8
|
||||||
&self.kind
|
} else {
|
||||||
|
I8
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Negative
|
||||||
|
if result < I64.min_value() {
|
||||||
|
I128
|
||||||
|
} else if result < I32.min_value() {
|
||||||
|
I64
|
||||||
|
} else if result < I16.min_value() {
|
||||||
|
I32
|
||||||
|
} else if result < I8.min_value() {
|
||||||
|
I16
|
||||||
|
} else {
|
||||||
|
I8
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
enum IntSign {
|
||||||
|
Unsigned,
|
||||||
|
Signed,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
pub enum IntWidth {
|
||||||
|
U8,
|
||||||
|
U16,
|
||||||
|
U32,
|
||||||
|
U64,
|
||||||
|
U128,
|
||||||
|
I8,
|
||||||
|
I16,
|
||||||
|
I32,
|
||||||
|
I64,
|
||||||
|
I128,
|
||||||
|
Nat,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntWidth {
|
||||||
|
/// Returns the `IntSign` and bit width of a variant.
|
||||||
|
fn sign_and_width(&self) -> (IntSign, u32) {
|
||||||
|
use IntSign::*;
|
||||||
|
use IntWidth::*;
|
||||||
|
match self {
|
||||||
|
U8 => (Unsigned, 8),
|
||||||
|
U16 => (Unsigned, 16),
|
||||||
|
U32 => (Unsigned, 32),
|
||||||
|
U64 => (Unsigned, 64),
|
||||||
|
U128 => (Unsigned, 128),
|
||||||
|
I8 => (Signed, 8),
|
||||||
|
I16 => (Signed, 16),
|
||||||
|
I32 => (Signed, 32),
|
||||||
|
I64 => (Signed, 64),
|
||||||
|
I128 => (Signed, 128),
|
||||||
|
// TODO: this is platform specific!
|
||||||
|
Nat => (Unsigned, 64),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn type_str(&self) -> &'static str {
|
||||||
|
use IntWidth::*;
|
||||||
|
match self {
|
||||||
|
U8 => "U8",
|
||||||
|
U16 => "U16",
|
||||||
|
U32 => "U32",
|
||||||
|
U64 => "U64",
|
||||||
|
U128 => "U128",
|
||||||
|
I8 => "I8",
|
||||||
|
I16 => "I16",
|
||||||
|
I32 => "I32",
|
||||||
|
I64 => "I64",
|
||||||
|
I128 => "I128",
|
||||||
|
Nat => "Nat",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn max_value(&self) -> u128 {
|
||||||
|
use IntWidth::*;
|
||||||
|
match self {
|
||||||
|
U8 => u8::MAX as u128,
|
||||||
|
U16 => u16::MAX as u128,
|
||||||
|
U32 => u32::MAX as u128,
|
||||||
|
U64 => u64::MAX as u128,
|
||||||
|
U128 => u128::MAX,
|
||||||
|
I8 => i8::MAX as u128,
|
||||||
|
I16 => i16::MAX as u128,
|
||||||
|
I32 => i32::MAX as u128,
|
||||||
|
I64 => i64::MAX as u128,
|
||||||
|
I128 => i128::MAX as u128,
|
||||||
|
// TODO: this is platform specific!
|
||||||
|
Nat => u64::MAX as u128,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn min_value(&self) -> i128 {
|
||||||
|
use IntWidth::*;
|
||||||
|
match self {
|
||||||
|
U8 | U16 | U32 | U64 | U128 | Nat => 0,
|
||||||
|
I8 => i8::MIN as i128,
|
||||||
|
I16 => i16::MIN as i128,
|
||||||
|
I32 => i32::MIN as i128,
|
||||||
|
I64 => i64::MIN as i128,
|
||||||
|
I128 => i128::MIN,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if `self` represents superset of integers that `lower_bound` represents, on a particular
|
||||||
|
/// side of the integers relative to 0.
|
||||||
|
///
|
||||||
|
/// If `is_negative` is true, the negative side is checked; otherwise the positive side is checked.
|
||||||
|
pub fn is_superset(&self, lower_bound: &Self, is_negative: bool) -> bool {
|
||||||
|
use IntSign::*;
|
||||||
|
|
||||||
|
if is_negative {
|
||||||
|
match (self.sign_and_width(), lower_bound.sign_and_width()) {
|
||||||
|
((Signed, us), (Signed, lower_bound)) => us >= lower_bound,
|
||||||
|
// Unsigned ints can never represent negative numbers; signed (non-zero width)
|
||||||
|
// ints always can.
|
||||||
|
((Unsigned, _), (Signed, _)) => false,
|
||||||
|
((Signed, _), (Unsigned, _)) => true,
|
||||||
|
// Trivially true; both can only express 0.
|
||||||
|
((Unsigned, _), (Unsigned, _)) => true,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match (self.sign_and_width(), lower_bound.sign_and_width()) {
|
||||||
|
((Signed, us), (Signed, lower_bound))
|
||||||
|
| ((Unsigned, us), (Unsigned, lower_bound)) => us >= lower_bound,
|
||||||
|
|
||||||
|
// Unsigned ints with the same bit width as their unsigned counterparts can always
|
||||||
|
// express 2x more integers on the positive side as unsigned ints.
|
||||||
|
((Unsigned, us), (Signed, lower_bound)) => us >= lower_bound,
|
||||||
|
|
||||||
|
// ...but that means signed int widths can represent less than their unsigned
|
||||||
|
// counterparts, so the below is true iff the bit width is strictly greater. E.g.
|
||||||
|
// i16 is a superset of u8, but i16 is not a superset of u16.
|
||||||
|
((Signed, us), (Unsigned, lower_bound)) => us > lower_bound,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
pub enum FloatWidth {
|
||||||
|
Dec,
|
||||||
|
F32,
|
||||||
|
F64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
pub enum NumWidth {
|
||||||
|
Int(IntWidth),
|
||||||
|
Float(FloatWidth),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Describes a bound on the width of a numeric literal.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
pub enum NumericBound<W>
|
||||||
|
where
|
||||||
|
W: Copy,
|
||||||
|
{
|
||||||
|
/// There is no bound on the width.
|
||||||
|
None,
|
||||||
|
/// Must have exactly the width `W`.
|
||||||
|
Exact(W),
|
||||||
|
}
|
||||||
|
|
|
@ -121,8 +121,8 @@ pub fn desugar_def<'a>(arena: &'a Bump, def: &'a Def<'a>) -> Def<'a> {
|
||||||
/// then replace the BinOp nodes with Apply nodes. Also drop SpaceBefore and SpaceAfter nodes.
|
/// then replace the BinOp nodes with Apply nodes. Also drop SpaceBefore and SpaceAfter nodes.
|
||||||
pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Loc<Expr<'a>>) -> &'a Loc<Expr<'a>> {
|
pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Loc<Expr<'a>>) -> &'a Loc<Expr<'a>> {
|
||||||
match &loc_expr.value {
|
match &loc_expr.value {
|
||||||
Float(_)
|
Float(..)
|
||||||
| Num(_)
|
| Num(..)
|
||||||
| NonBase10Int { .. }
|
| NonBase10Int { .. }
|
||||||
| Str(_)
|
| Str(_)
|
||||||
| AccessorFunction(_)
|
| AccessorFunction(_)
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
use crate::env::Env;
|
use crate::env::Env;
|
||||||
use crate::expr::{canonicalize_expr, unescape_char, Expr, Output};
|
use crate::expr::{canonicalize_expr, unescape_char, Expr, IntValue, Output};
|
||||||
use crate::num::{finish_parsing_base, finish_parsing_float, finish_parsing_int};
|
use crate::num::{
|
||||||
|
finish_parsing_base, finish_parsing_float, finish_parsing_num, FloatWidth, IntWidth, NumWidth,
|
||||||
|
NumericBound, ParsedNumResult,
|
||||||
|
};
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use roc_module::ident::{Ident, Lowercase, TagName};
|
use roc_module::ident::{Ident, Lowercase, TagName};
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
|
@ -9,6 +12,7 @@ use roc_parse::pattern::PatternType;
|
||||||
use roc_problem::can::{MalformedPatternProblem, Problem, RuntimeError};
|
use roc_problem::can::{MalformedPatternProblem, Problem, RuntimeError};
|
||||||
use roc_region::all::{Loc, Region};
|
use roc_region::all::{Loc, Region};
|
||||||
use roc_types::subs::{VarStore, Variable};
|
use roc_types::subs::{VarStore, Variable};
|
||||||
|
|
||||||
/// A pattern, including possible problems (e.g. shadowing) so that
|
/// A pattern, including possible problems (e.g. shadowing) so that
|
||||||
/// codegen can generate a runtime error if this pattern is reached.
|
/// codegen can generate a runtime error if this pattern is reached.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
@ -25,9 +29,15 @@ pub enum Pattern {
|
||||||
ext_var: Variable,
|
ext_var: Variable,
|
||||||
destructs: Vec<Loc<RecordDestruct>>,
|
destructs: Vec<Loc<RecordDestruct>>,
|
||||||
},
|
},
|
||||||
IntLiteral(Variable, Box<str>, i64),
|
NumLiteral(Variable, Box<str>, IntValue, NumericBound<NumWidth>),
|
||||||
NumLiteral(Variable, Box<str>, i64),
|
IntLiteral(
|
||||||
FloatLiteral(Variable, Box<str>, f64),
|
Variable,
|
||||||
|
Variable,
|
||||||
|
Box<str>,
|
||||||
|
IntValue,
|
||||||
|
NumericBound<IntWidth>,
|
||||||
|
),
|
||||||
|
FloatLiteral(Variable, Variable, Box<str>, f64, NumericBound<FloatWidth>),
|
||||||
StrLiteral(Box<str>),
|
StrLiteral(Box<str>),
|
||||||
Underscore,
|
Underscore,
|
||||||
|
|
||||||
|
@ -85,9 +95,9 @@ pub fn symbols_from_pattern_help(pattern: &Pattern, symbols: &mut Vec<Symbol>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NumLiteral(_, _, _)
|
NumLiteral(..)
|
||||||
| IntLiteral(_, _, _)
|
| IntLiteral(..)
|
||||||
| FloatLiteral(_, _, _)
|
| FloatLiteral(..)
|
||||||
| StrLiteral(_)
|
| StrLiteral(_)
|
||||||
| Underscore
|
| Underscore
|
||||||
| MalformedPattern(_, _)
|
| MalformedPattern(_, _)
|
||||||
|
@ -184,13 +194,19 @@ pub fn canonicalize_pattern<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FloatLiteral(str) => match pattern_type {
|
&FloatLiteral(str) => match pattern_type {
|
||||||
WhenBranch => match finish_parsing_float(str) {
|
WhenBranch => match finish_parsing_float(str) {
|
||||||
Err(_error) => {
|
Err(_error) => {
|
||||||
let problem = MalformedPatternProblem::MalformedFloat;
|
let problem = MalformedPatternProblem::MalformedFloat;
|
||||||
malformed_pattern(env, problem, region)
|
malformed_pattern(env, problem, region)
|
||||||
}
|
}
|
||||||
Ok(float) => Pattern::FloatLiteral(var_store.fresh(), (*str).into(), float),
|
Ok((float, bound)) => Pattern::FloatLiteral(
|
||||||
|
var_store.fresh(),
|
||||||
|
var_store.fresh(),
|
||||||
|
(str).into(),
|
||||||
|
float,
|
||||||
|
bound,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
ptype => unsupported_pattern(env, ptype, region),
|
ptype => unsupported_pattern(env, ptype, region),
|
||||||
},
|
},
|
||||||
|
@ -200,32 +216,58 @@ pub fn canonicalize_pattern<'a>(
|
||||||
TopLevelDef | DefExpr => bad_underscore(env, region),
|
TopLevelDef | DefExpr => bad_underscore(env, region),
|
||||||
},
|
},
|
||||||
|
|
||||||
NumLiteral(str) => match pattern_type {
|
&NumLiteral(str) => match pattern_type {
|
||||||
WhenBranch => match finish_parsing_int(str) {
|
WhenBranch => match finish_parsing_num(str) {
|
||||||
Err(_error) => {
|
Err(_error) => {
|
||||||
let problem = MalformedPatternProblem::MalformedInt;
|
let problem = MalformedPatternProblem::MalformedInt;
|
||||||
malformed_pattern(env, problem, region)
|
malformed_pattern(env, problem, region)
|
||||||
}
|
}
|
||||||
Ok(int) => Pattern::NumLiteral(var_store.fresh(), (*str).into(), int),
|
Ok(ParsedNumResult::UnknownNum(int)) => {
|
||||||
|
Pattern::NumLiteral(var_store.fresh(), (str).into(), int, NumericBound::None)
|
||||||
|
}
|
||||||
|
Ok(ParsedNumResult::Int(int, bound)) => Pattern::IntLiteral(
|
||||||
|
var_store.fresh(),
|
||||||
|
var_store.fresh(),
|
||||||
|
(str).into(),
|
||||||
|
int,
|
||||||
|
bound,
|
||||||
|
),
|
||||||
|
Ok(ParsedNumResult::Float(float, bound)) => Pattern::FloatLiteral(
|
||||||
|
var_store.fresh(),
|
||||||
|
var_store.fresh(),
|
||||||
|
(str).into(),
|
||||||
|
float,
|
||||||
|
bound,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
ptype => unsupported_pattern(env, ptype, region),
|
ptype => unsupported_pattern(env, ptype, region),
|
||||||
},
|
},
|
||||||
|
|
||||||
NonBase10Literal {
|
&NonBase10Literal {
|
||||||
string,
|
string,
|
||||||
base,
|
base,
|
||||||
is_negative,
|
is_negative,
|
||||||
} => match pattern_type {
|
} => match pattern_type {
|
||||||
WhenBranch => match finish_parsing_base(string, *base, *is_negative) {
|
WhenBranch => match finish_parsing_base(string, base, is_negative) {
|
||||||
Err(_error) => {
|
Err(_error) => {
|
||||||
let problem = MalformedPatternProblem::MalformedBase(*base);
|
let problem = MalformedPatternProblem::MalformedBase(base);
|
||||||
malformed_pattern(env, problem, region)
|
malformed_pattern(env, problem, region)
|
||||||
}
|
}
|
||||||
Ok(int) => {
|
Ok((IntValue::U128(_), _)) if is_negative => {
|
||||||
let sign_str = if *is_negative { "-" } else { "" };
|
// Can't negate a u128; that doesn't fit in any integer literal type we support.
|
||||||
|
let problem = MalformedPatternProblem::MalformedInt;
|
||||||
|
malformed_pattern(env, problem, region)
|
||||||
|
}
|
||||||
|
Ok((int, bound)) => {
|
||||||
|
let sign_str = if is_negative { "-" } else { "" };
|
||||||
let int_str = format!("{}{}", sign_str, int.to_string()).into_boxed_str();
|
let int_str = format!("{}{}", sign_str, int.to_string()).into_boxed_str();
|
||||||
let i = if *is_negative { -int } else { int };
|
let i = match int {
|
||||||
Pattern::IntLiteral(var_store.fresh(), int_str, i)
|
// Safety: this is fine because I128::MAX = |I128::MIN| - 1
|
||||||
|
IntValue::I128(n) if is_negative => IntValue::I128(-n),
|
||||||
|
IntValue::I128(n) => IntValue::I128(n),
|
||||||
|
IntValue::U128(_) => unreachable!(),
|
||||||
|
};
|
||||||
|
Pattern::IntLiteral(var_store.fresh(), var_store.fresh(), int_str, i, bound)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ptype => unsupported_pattern(env, ptype, region),
|
ptype => unsupported_pattern(env, ptype, region),
|
||||||
|
@ -473,9 +515,9 @@ fn add_bindings_from_patterns(
|
||||||
answer.push((*symbol, *region));
|
answer.push((*symbol, *region));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NumLiteral(_, _, _)
|
NumLiteral(..)
|
||||||
| IntLiteral(_, _, _)
|
| IntLiteral(..)
|
||||||
| FloatLiteral(_, _, _)
|
| FloatLiteral(..)
|
||||||
| StrLiteral(_)
|
| StrLiteral(_)
|
||||||
| Underscore
|
| Underscore
|
||||||
| MalformedPattern(_, _)
|
| MalformedPattern(_, _)
|
||||||
|
|
|
@ -15,7 +15,7 @@ mod test_can {
|
||||||
use crate::helpers::{can_expr_with, test_home, CanExprOut};
|
use crate::helpers::{can_expr_with, test_home, CanExprOut};
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_can::expr::Expr::{self, *};
|
use roc_can::expr::Expr::{self, *};
|
||||||
use roc_can::expr::{ClosureData, Recursive};
|
use roc_can::expr::{ClosureData, IntValue, Recursive};
|
||||||
use roc_problem::can::{CycleEntry, FloatErrorKind, IntErrorKind, Problem, RuntimeError};
|
use roc_problem::can::{CycleEntry, FloatErrorKind, IntErrorKind, Problem, RuntimeError};
|
||||||
use roc_region::all::{Position, Region};
|
use roc_region::all::{Position, Region};
|
||||||
use std::{f64, i64};
|
use std::{f64, i64};
|
||||||
|
@ -32,7 +32,7 @@ mod test_can {
|
||||||
let actual_out = can_expr_with(&arena, test_home(), input);
|
let actual_out = can_expr_with(&arena, test_home(), input);
|
||||||
|
|
||||||
match actual_out.loc_expr.value {
|
match actual_out.loc_expr.value {
|
||||||
Expr::Float(_, _, _, actual) => {
|
Expr::Float(_, _, _, actual, _) => {
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
}
|
}
|
||||||
actual => {
|
actual => {
|
||||||
|
@ -46,8 +46,8 @@ mod test_can {
|
||||||
let actual_out = can_expr_with(&arena, test_home(), input);
|
let actual_out = can_expr_with(&arena, test_home(), input);
|
||||||
|
|
||||||
match actual_out.loc_expr.value {
|
match actual_out.loc_expr.value {
|
||||||
Expr::Int(_, _, _, actual) => {
|
Expr::Int(_, _, _, actual, _) => {
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(IntValue::I128(expected), actual);
|
||||||
}
|
}
|
||||||
actual => {
|
actual => {
|
||||||
panic!("Expected an Int *, but got: {:?}", actual);
|
panic!("Expected an Int *, but got: {:?}", actual);
|
||||||
|
@ -55,13 +55,13 @@ mod test_can {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assert_can_num(input: &str, expected: i64) {
|
fn assert_can_num(input: &str, expected: i128) {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let actual_out = can_expr_with(&arena, test_home(), input);
|
let actual_out = can_expr_with(&arena, test_home(), input);
|
||||||
|
|
||||||
match actual_out.loc_expr.value {
|
match actual_out.loc_expr.value {
|
||||||
Expr::Num(_, _, actual) => {
|
Expr::Num(_, _, actual, _) => {
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(IntValue::I128(expected), actual);
|
||||||
}
|
}
|
||||||
actual => {
|
actual => {
|
||||||
panic!("Expected a Num, but got: {:?}", actual);
|
panic!("Expected a Num, but got: {:?}", actual);
|
||||||
|
@ -79,7 +79,7 @@ mod test_can {
|
||||||
fn int_too_large() {
|
fn int_too_large() {
|
||||||
use roc_parse::ast::Base;
|
use roc_parse::ast::Base;
|
||||||
|
|
||||||
let string = (i64::MAX as i128 + 1).to_string();
|
let string = "340_282_366_920_938_463_463_374_607_431_768_211_456".to_string();
|
||||||
|
|
||||||
assert_can(
|
assert_can(
|
||||||
&string.clone(),
|
&string.clone(),
|
||||||
|
@ -96,7 +96,7 @@ mod test_can {
|
||||||
fn int_too_small() {
|
fn int_too_small() {
|
||||||
use roc_parse::ast::Base;
|
use roc_parse::ast::Base;
|
||||||
|
|
||||||
let string = (i64::MIN as i128 - 1).to_string();
|
let string = "-170_141_183_460_469_231_731_687_303_715_884_105_729".to_string();
|
||||||
|
|
||||||
assert_can(
|
assert_can(
|
||||||
&string.clone(),
|
&string.clone(),
|
||||||
|
@ -186,12 +186,12 @@ mod test_can {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn num_max() {
|
fn num_max() {
|
||||||
assert_can_num(&(i64::MAX.to_string()), i64::MAX);
|
assert_can_num(&(i64::MAX.to_string()), i64::MAX.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn num_min() {
|
fn num_min() {
|
||||||
assert_can_num(&(i64::MIN.to_string()), i64::MIN);
|
assert_can_num(&(i64::MIN.to_string()), i64::MIN.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use roc_can::constraint::Constraint::{self, *};
|
use roc_can::constraint::Constraint::{self, *};
|
||||||
use roc_can::constraint::LetConstraint;
|
use roc_can::constraint::LetConstraint;
|
||||||
use roc_can::expected::Expected::{self, *};
|
use roc_can::expected::Expected::{self, *};
|
||||||
|
use roc_can::num::{FloatWidth, IntWidth, NumWidth, NumericBound};
|
||||||
use roc_collections::all::SendMap;
|
use roc_collections::all::SendMap;
|
||||||
use roc_module::ident::{Lowercase, TagName};
|
use roc_module::ident::{Lowercase, TagName};
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
|
@ -10,19 +11,39 @@ use roc_types::types::Category;
|
||||||
use roc_types::types::Reason;
|
use roc_types::types::Reason;
|
||||||
use roc_types::types::Type::{self, *};
|
use roc_types::types::Type::{self, *};
|
||||||
|
|
||||||
|
pub fn add_numeric_bound_constr(
|
||||||
|
constrs: &mut Vec<Constraint>,
|
||||||
|
num_type: Type,
|
||||||
|
bound: impl TypedNumericBound,
|
||||||
|
region: Region,
|
||||||
|
category: Category,
|
||||||
|
) {
|
||||||
|
if let Some(typ) = bound.concrete_num_type() {
|
||||||
|
constrs.push(Eq(
|
||||||
|
num_type,
|
||||||
|
Expected::ForReason(Reason::NumericLiteralSuffix, typ, region),
|
||||||
|
category,
|
||||||
|
region,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn int_literal(
|
pub fn int_literal(
|
||||||
num_var: Variable,
|
num_var: Variable,
|
||||||
precision_var: Variable,
|
precision_var: Variable,
|
||||||
expected: Expected<Type>,
|
expected: Expected<Type>,
|
||||||
region: Region,
|
region: Region,
|
||||||
|
bound: NumericBound<IntWidth>,
|
||||||
) -> Constraint {
|
) -> Constraint {
|
||||||
let num_type = Variable(num_var);
|
let num_type = Variable(num_var);
|
||||||
let reason = Reason::IntLiteral;
|
let reason = Reason::IntLiteral;
|
||||||
|
|
||||||
exists(
|
let mut constrs = Vec::with_capacity(3);
|
||||||
vec![num_var],
|
// Always add the bound first; this improves the resolved type quality in case it's an alias
|
||||||
And(vec![
|
// like "U8".
|
||||||
|
add_numeric_bound_constr(&mut constrs, num_type.clone(), bound, region, Category::Num);
|
||||||
|
constrs.extend(vec![
|
||||||
Eq(
|
Eq(
|
||||||
num_type.clone(),
|
num_type.clone(),
|
||||||
ForReason(reason, num_int(Type::Variable(precision_var)), region),
|
ForReason(reason, num_int(Type::Variable(precision_var)), region),
|
||||||
|
@ -30,8 +51,9 @@ pub fn int_literal(
|
||||||
region,
|
region,
|
||||||
),
|
),
|
||||||
Eq(num_type, expected, Category::Int, region),
|
Eq(num_type, expected, Category::Int, region),
|
||||||
]),
|
]);
|
||||||
)
|
|
||||||
|
exists(vec![num_var], And(constrs))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -40,13 +62,20 @@ pub fn float_literal(
|
||||||
precision_var: Variable,
|
precision_var: Variable,
|
||||||
expected: Expected<Type>,
|
expected: Expected<Type>,
|
||||||
region: Region,
|
region: Region,
|
||||||
|
bound: NumericBound<FloatWidth>,
|
||||||
) -> Constraint {
|
) -> Constraint {
|
||||||
let num_type = Variable(num_var);
|
let num_type = Variable(num_var);
|
||||||
let reason = Reason::FloatLiteral;
|
let reason = Reason::FloatLiteral;
|
||||||
|
|
||||||
exists(
|
let mut constrs = Vec::with_capacity(3);
|
||||||
vec![num_var, precision_var],
|
add_numeric_bound_constr(
|
||||||
And(vec![
|
&mut constrs,
|
||||||
|
num_type.clone(),
|
||||||
|
bound,
|
||||||
|
region,
|
||||||
|
Category::Float,
|
||||||
|
);
|
||||||
|
constrs.extend(vec![
|
||||||
Eq(
|
Eq(
|
||||||
num_type.clone(),
|
num_type.clone(),
|
||||||
ForReason(reason, num_float(Type::Variable(precision_var)), region),
|
ForReason(reason, num_float(Type::Variable(precision_var)), region),
|
||||||
|
@ -54,8 +83,25 @@ pub fn float_literal(
|
||||||
region,
|
region,
|
||||||
),
|
),
|
||||||
Eq(num_type, expected, Category::Float, region),
|
Eq(num_type, expected, Category::Float, region),
|
||||||
]),
|
]);
|
||||||
)
|
|
||||||
|
exists(vec![num_var, precision_var], And(constrs))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn num_literal(
|
||||||
|
num_var: Variable,
|
||||||
|
expected: Expected<Type>,
|
||||||
|
region: Region,
|
||||||
|
bound: NumericBound<NumWidth>,
|
||||||
|
) -> Constraint {
|
||||||
|
let num_type = crate::builtins::num_num(Type::Variable(num_var));
|
||||||
|
|
||||||
|
let mut constrs = Vec::with_capacity(3);
|
||||||
|
add_numeric_bound_constr(&mut constrs, num_type.clone(), bound, region, Category::Num);
|
||||||
|
constrs.extend(vec![Eq(num_type, expected, Category::Num, region)]);
|
||||||
|
|
||||||
|
exists(vec![num_var], And(constrs))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -148,6 +194,57 @@ pub fn num_int(range: Type) -> Type {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! num_types {
|
||||||
|
// Represent
|
||||||
|
// num_u8 ~ U8 : Num Integer Unsigned8 = @Num (@Integer (@Unsigned8))
|
||||||
|
// int_u8 ~ Integer Unsigned8 = @Integer (@Unsigned8)
|
||||||
|
//
|
||||||
|
// num_f32 ~ F32 : Num FloaingPoint Binary32 = @Num (@FloaingPoint (@Binary32))
|
||||||
|
// float_f32 ~ FloatingPoint Binary32 = @FloatingPoint (@Binary32)
|
||||||
|
// and so on, for all numeric types.
|
||||||
|
($($num_fn:ident, $sub_fn:ident, $num_type:ident, $alias:path, $inner_alias:path, $inner_private_tag:path)*) => {
|
||||||
|
$(
|
||||||
|
#[inline(always)]
|
||||||
|
fn $sub_fn() -> Type {
|
||||||
|
builtin_alias(
|
||||||
|
$inner_alias,
|
||||||
|
vec![],
|
||||||
|
Box::new(Type::TagUnion(
|
||||||
|
vec![(TagName::Private($inner_private_tag), vec![])],
|
||||||
|
Box::new(Type::EmptyTagUnion)
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn $num_fn() -> Type {
|
||||||
|
builtin_alias(
|
||||||
|
$alias,
|
||||||
|
vec![],
|
||||||
|
Box::new($num_type($sub_fn()))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
num_types! {
|
||||||
|
num_u8, int_u8, num_int, Symbol::NUM_U8, Symbol::NUM_UNSIGNED8, Symbol::NUM_AT_UNSIGNED8
|
||||||
|
num_u16, int_u16, num_int, Symbol::NUM_U16, Symbol::NUM_UNSIGNED16, Symbol::NUM_AT_UNSIGNED16
|
||||||
|
num_u32, int_u32, num_int, Symbol::NUM_U32, Symbol::NUM_UNSIGNED32, Symbol::NUM_AT_UNSIGNED32
|
||||||
|
num_u64, int_u64, num_int, Symbol::NUM_U64, Symbol::NUM_UNSIGNED64, Symbol::NUM_AT_UNSIGNED64
|
||||||
|
num_u128, int_u128, num_int, Symbol::NUM_U128, Symbol::NUM_UNSIGNED128, Symbol::NUM_AT_UNSIGNED128
|
||||||
|
num_i8, int_i8, num_int, Symbol::NUM_I8, Symbol::NUM_SIGNED8, Symbol::NUM_AT_SIGNED8
|
||||||
|
num_i16, int_i16, num_int, Symbol::NUM_I16, Symbol::NUM_SIGNED16, Symbol::NUM_AT_SIGNED16
|
||||||
|
num_i32, int_i32, num_int, Symbol::NUM_I32, Symbol::NUM_SIGNED32, Symbol::NUM_AT_SIGNED32
|
||||||
|
num_i64, int_i64, num_int, Symbol::NUM_I64, Symbol::NUM_SIGNED64, Symbol::NUM_AT_SIGNED64
|
||||||
|
num_i128, int_i128, num_int, Symbol::NUM_I128, Symbol::NUM_SIGNED128, Symbol::NUM_AT_SIGNED128
|
||||||
|
num_nat, int_nat, num_int, Symbol::NUM_NAT, Symbol::NUM_NATURAL, Symbol::NUM_AT_NATURAL
|
||||||
|
num_dec, float_dec, num_float, Symbol::NUM_DEC, Symbol::NUM_DECIMAL, Symbol::NUM_AT_DECIMAL
|
||||||
|
num_f32, float_f32, num_float, Symbol::NUM_F32, Symbol::NUM_BINARY32, Symbol::NUM_AT_BINARY32
|
||||||
|
num_f64, float_f64, num_float, Symbol::NUM_F64, Symbol::NUM_BINARY64, Symbol::NUM_AT_BINARY64
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn num_signed64() -> Type {
|
pub fn num_signed64() -> Type {
|
||||||
let alias_content = Type::TagUnion(
|
let alias_content = Type::TagUnion(
|
||||||
|
@ -188,3 +285,55 @@ pub fn num_num(typ: Type) -> Type {
|
||||||
Box::new(alias_content),
|
Box::new(alias_content),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait TypedNumericBound {
|
||||||
|
/// Get a concrete type for this number, if one exists.
|
||||||
|
/// Returns `None` e.g. if the bound is open, like `Int *`.
|
||||||
|
fn concrete_num_type(&self) -> Option<Type>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypedNumericBound for NumericBound<IntWidth> {
|
||||||
|
fn concrete_num_type(&self) -> Option<Type> {
|
||||||
|
match self {
|
||||||
|
NumericBound::None => None,
|
||||||
|
NumericBound::Exact(w) => Some(match w {
|
||||||
|
IntWidth::U8 => num_u8(),
|
||||||
|
IntWidth::U16 => num_u16(),
|
||||||
|
IntWidth::U32 => num_u32(),
|
||||||
|
IntWidth::U64 => num_u64(),
|
||||||
|
IntWidth::U128 => num_u128(),
|
||||||
|
IntWidth::I8 => num_i8(),
|
||||||
|
IntWidth::I16 => num_i16(),
|
||||||
|
IntWidth::I32 => num_i32(),
|
||||||
|
IntWidth::I64 => num_i64(),
|
||||||
|
IntWidth::I128 => num_i128(),
|
||||||
|
IntWidth::Nat => num_nat(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypedNumericBound for NumericBound<FloatWidth> {
|
||||||
|
fn concrete_num_type(&self) -> Option<Type> {
|
||||||
|
match self {
|
||||||
|
NumericBound::None => None,
|
||||||
|
NumericBound::Exact(w) => Some(match w {
|
||||||
|
FloatWidth::Dec => num_dec(),
|
||||||
|
FloatWidth::F32 => num_f32(),
|
||||||
|
FloatWidth::F64 => num_f64(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypedNumericBound for NumericBound<NumWidth> {
|
||||||
|
fn concrete_num_type(&self) -> Option<Type> {
|
||||||
|
match self {
|
||||||
|
NumericBound::None => None,
|
||||||
|
NumericBound::Exact(NumWidth::Int(iw)) => NumericBound::Exact(*iw).concrete_num_type(),
|
||||||
|
NumericBound::Exact(NumWidth::Float(fw)) => {
|
||||||
|
NumericBound::Exact(*fw).concrete_num_type()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
use crate::builtins::{empty_list_type, float_literal, int_literal, list_type, str_type};
|
use crate::builtins::{
|
||||||
|
empty_list_type, float_literal, int_literal, list_type, num_literal, str_type,
|
||||||
|
};
|
||||||
use crate::pattern::{constrain_pattern, PatternState};
|
use crate::pattern::{constrain_pattern, PatternState};
|
||||||
use roc_can::annotation::IntroducedVariables;
|
use roc_can::annotation::IntroducedVariables;
|
||||||
use roc_can::constraint::Constraint::{self, *};
|
use roc_can::constraint::Constraint::{self, *};
|
||||||
|
@ -96,17 +98,11 @@ pub fn constrain_expr(
|
||||||
expected: Expected<Type>,
|
expected: Expected<Type>,
|
||||||
) -> Constraint {
|
) -> Constraint {
|
||||||
match expr {
|
match expr {
|
||||||
Int(var, precision, _, _) => int_literal(*var, *precision, expected, region),
|
&Int(var, precision, _, _, bound) => int_literal(var, precision, expected, region, bound),
|
||||||
Num(var, _, _) => exists(
|
&Num(var, _, _, bound) => num_literal(var, expected, region, bound),
|
||||||
vec![*var],
|
&Float(var, precision, _, _, bound) => {
|
||||||
Eq(
|
float_literal(var, precision, expected, region, bound)
|
||||||
crate::builtins::num_num(Type::Variable(*var)),
|
}
|
||||||
expected,
|
|
||||||
Category::Num,
|
|
||||||
region,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Float(var, precision, _, _) => float_literal(*var, *precision, expected, region),
|
|
||||||
EmptyRecord => constrain_empty_record(region, expected),
|
EmptyRecord => constrain_empty_record(region, expected),
|
||||||
Expr::Record { record_var, fields } => {
|
Expr::Record { record_var, fields } => {
|
||||||
if fields.is_empty() {
|
if fields.is_empty() {
|
||||||
|
|
|
@ -55,9 +55,9 @@ fn headers_from_annotation_help(
|
||||||
Underscore
|
Underscore
|
||||||
| MalformedPattern(_, _)
|
| MalformedPattern(_, _)
|
||||||
| UnsupportedPattern(_)
|
| UnsupportedPattern(_)
|
||||||
| NumLiteral(_, _, _)
|
| NumLiteral(..)
|
||||||
| IntLiteral(_, _, _)
|
| IntLiteral(..)
|
||||||
| FloatLiteral(_, _, _)
|
| FloatLiteral(..)
|
||||||
| StrLiteral(_) => true,
|
| StrLiteral(_) => true,
|
||||||
|
|
||||||
RecordDestructure { destructs, .. } => match annotation.value.shallow_dealias() {
|
RecordDestructure { destructs, .. } => match annotation.value.shallow_dealias() {
|
||||||
|
@ -178,31 +178,83 @@ pub fn constrain_pattern(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
NumLiteral(var, _, _) => {
|
&NumLiteral(var, _, _, bound) => {
|
||||||
state.vars.push(*var);
|
state.vars.push(var);
|
||||||
|
|
||||||
|
let num_type = builtins::num_num(Type::Variable(var));
|
||||||
|
|
||||||
|
builtins::add_numeric_bound_constr(
|
||||||
|
&mut state.constraints,
|
||||||
|
num_type.clone(),
|
||||||
|
bound,
|
||||||
|
region,
|
||||||
|
Category::Num,
|
||||||
|
);
|
||||||
|
|
||||||
state.constraints.push(Constraint::Pattern(
|
state.constraints.push(Constraint::Pattern(
|
||||||
region,
|
region,
|
||||||
PatternCategory::Num,
|
PatternCategory::Num,
|
||||||
builtins::num_num(Type::Variable(*var)),
|
num_type,
|
||||||
expected,
|
expected,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
IntLiteral(precision_var, _, _) => {
|
&IntLiteral(num_var, precision_var, _, _, bound) => {
|
||||||
|
// First constraint on the free num var; this improves the resolved type quality in
|
||||||
|
// case the bound is an alias.
|
||||||
|
builtins::add_numeric_bound_constr(
|
||||||
|
&mut state.constraints,
|
||||||
|
Type::Variable(num_var),
|
||||||
|
bound,
|
||||||
|
region,
|
||||||
|
Category::Int,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Link the free num var with the int var and our expectation.
|
||||||
|
let int_type = builtins::num_int(Type::Variable(precision_var));
|
||||||
|
|
||||||
|
state.constraints.push(Constraint::Eq(
|
||||||
|
Type::Variable(num_var),
|
||||||
|
Expected::NoExpectation(int_type),
|
||||||
|
Category::Int,
|
||||||
|
region,
|
||||||
|
));
|
||||||
|
|
||||||
|
// Also constrain the pattern against the num var, again to reuse aliases if they're present.
|
||||||
state.constraints.push(Constraint::Pattern(
|
state.constraints.push(Constraint::Pattern(
|
||||||
region,
|
region,
|
||||||
PatternCategory::Int,
|
PatternCategory::Int,
|
||||||
builtins::num_int(Type::Variable(*precision_var)),
|
Type::Variable(num_var),
|
||||||
expected,
|
expected,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
FloatLiteral(precision_var, _, _) => {
|
&FloatLiteral(num_var, precision_var, _, _, bound) => {
|
||||||
|
// First constraint on the free num var; this improves the resolved type quality in
|
||||||
|
// case the bound is an alias.
|
||||||
|
builtins::add_numeric_bound_constr(
|
||||||
|
&mut state.constraints,
|
||||||
|
Type::Variable(num_var),
|
||||||
|
bound,
|
||||||
|
region,
|
||||||
|
Category::Float,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Link the free num var with the float var and our expectation.
|
||||||
|
let float_type = builtins::num_float(Type::Variable(precision_var));
|
||||||
|
|
||||||
|
state.constraints.push(Constraint::Eq(
|
||||||
|
Type::Variable(num_var),
|
||||||
|
Expected::NoExpectation(float_type),
|
||||||
|
Category::Float,
|
||||||
|
region,
|
||||||
|
));
|
||||||
|
|
||||||
|
// Also constrain the pattern against the num var, again to reuse aliases if they're present.
|
||||||
state.constraints.push(Constraint::Pattern(
|
state.constraints.push(Constraint::Pattern(
|
||||||
region,
|
region,
|
||||||
PatternCategory::Float,
|
PatternCategory::Float,
|
||||||
builtins::num_float(Type::Variable(*precision_var)),
|
Type::Variable(num_var),
|
||||||
expected,
|
expected,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,9 @@ impl<'a> Formattable for Def<'a> {
|
||||||
indent + INDENT,
|
indent + INDENT,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
buf.push_str(" : ");
|
buf.spaces(1);
|
||||||
|
buf.push_str(":");
|
||||||
|
buf.spaces(1);
|
||||||
loc_annotation.format_with_options(
|
loc_annotation.format_with_options(
|
||||||
buf,
|
buf,
|
||||||
Parens::NotNeeded,
|
Parens::NotNeeded,
|
||||||
|
|
|
@ -27,8 +27,8 @@ impl<'a> Formattable for Expr<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// These expressions never have newlines
|
// These expressions never have newlines
|
||||||
Float(_)
|
Float(..)
|
||||||
| Num(_)
|
| Num(..)
|
||||||
| NonBase10Int { .. }
|
| NonBase10Int { .. }
|
||||||
| Access(_, _)
|
| Access(_, _)
|
||||||
| AccessorFunction(_)
|
| AccessorFunction(_)
|
||||||
|
@ -196,17 +196,25 @@ impl<'a> Formattable for Expr<'a> {
|
||||||
buf.push(')');
|
buf.push(')');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Num(string) | Float(string) | GlobalTag(string) | PrivateTag(string) => {
|
&Num(string) => {
|
||||||
|
buf.indent(indent);
|
||||||
|
buf.push_str(string);
|
||||||
|
}
|
||||||
|
&Float(string) => {
|
||||||
|
buf.indent(indent);
|
||||||
|
buf.push_str(string);
|
||||||
|
}
|
||||||
|
GlobalTag(string) | PrivateTag(string) => {
|
||||||
buf.indent(indent);
|
buf.indent(indent);
|
||||||
buf.push_str(string)
|
buf.push_str(string)
|
||||||
}
|
}
|
||||||
NonBase10Int {
|
&NonBase10Int {
|
||||||
base,
|
base,
|
||||||
string,
|
string,
|
||||||
is_negative,
|
is_negative,
|
||||||
} => {
|
} => {
|
||||||
buf.indent(indent);
|
buf.indent(indent);
|
||||||
if *is_negative {
|
if is_negative {
|
||||||
buf.push('-');
|
buf.push('-');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,8 @@ use crate::spaces::{fmt_default_spaces, fmt_spaces, INDENT};
|
||||||
use crate::Buf;
|
use crate::Buf;
|
||||||
use roc_parse::ast::{Collection, Module, Spaced};
|
use roc_parse::ast::{Collection, Module, Spaced};
|
||||||
use roc_parse::header::{
|
use roc_parse::header::{
|
||||||
AppHeader, Effects, ExposedName, HostedHeader, ImportsEntry, InterfaceHeader, ModuleName,
|
AppHeader, ExposedName, HostedHeader, ImportsEntry, InterfaceHeader, ModuleName, PackageEntry,
|
||||||
PackageEntry, PackageName, PlatformHeader, PlatformRequires, To, TypedIdent,
|
PackageName, PlatformHeader, PlatformRequires, To, TypedIdent,
|
||||||
};
|
};
|
||||||
use roc_parse::ident::UppercaseIdent;
|
use roc_parse::ident::UppercaseIdent;
|
||||||
use roc_region::all::Loc;
|
use roc_region::all::Loc;
|
||||||
|
@ -170,8 +170,6 @@ pub fn fmt_platform_header<'a, 'buf>(buf: &mut Buf<'buf>, header: &'a PlatformHe
|
||||||
buf.push_str("provides");
|
buf.push_str("provides");
|
||||||
fmt_default_spaces(buf, header.after_provides, indent);
|
fmt_default_spaces(buf, header.after_provides, indent);
|
||||||
fmt_provides(buf, header.provides, None, indent);
|
fmt_provides(buf, header.provides, None, indent);
|
||||||
|
|
||||||
fmt_effects(buf, &header.effects, indent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmt_requires<'a, 'buf>(buf: &mut Buf<'buf>, requires: &PlatformRequires<'a>, indent: u16) {
|
fn fmt_requires<'a, 'buf>(buf: &mut Buf<'buf>, requires: &PlatformRequires<'a>, indent: u16) {
|
||||||
|
@ -183,29 +181,6 @@ fn fmt_requires<'a, 'buf>(buf: &mut Buf<'buf>, requires: &PlatformRequires<'a>,
|
||||||
buf.push_str(" }");
|
buf.push_str(" }");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmt_effects<'a, 'buf>(buf: &mut Buf<'buf>, effects: &Effects<'a>, indent: u16) {
|
|
||||||
fmt_default_spaces(buf, effects.spaces_before_effects_keyword, indent);
|
|
||||||
buf.indent(indent);
|
|
||||||
buf.push_str("effects");
|
|
||||||
fmt_default_spaces(buf, effects.spaces_after_effects_keyword, indent);
|
|
||||||
|
|
||||||
buf.indent(indent);
|
|
||||||
buf.push_str(effects.effect_shortname);
|
|
||||||
buf.push('.');
|
|
||||||
buf.push_str(effects.effect_type_name);
|
|
||||||
|
|
||||||
fmt_default_spaces(buf, effects.spaces_after_type_name, indent);
|
|
||||||
|
|
||||||
fmt_collection(
|
|
||||||
buf,
|
|
||||||
indent + INDENT,
|
|
||||||
'{',
|
|
||||||
'}',
|
|
||||||
effects.entries,
|
|
||||||
Newlines::No,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Formattable for TypedIdent<'a> {
|
impl<'a> Formattable for TypedIdent<'a> {
|
||||||
fn is_multiline(&self) -> bool {
|
fn is_multiline(&self) -> bool {
|
||||||
false
|
false
|
||||||
|
|
|
@ -31,9 +31,9 @@ impl<'a> Formattable for Pattern<'a> {
|
||||||
| Pattern::GlobalTag(_)
|
| Pattern::GlobalTag(_)
|
||||||
| Pattern::PrivateTag(_)
|
| Pattern::PrivateTag(_)
|
||||||
| Pattern::Apply(_, _)
|
| Pattern::Apply(_, _)
|
||||||
| Pattern::NumLiteral(_)
|
| Pattern::NumLiteral(..)
|
||||||
| Pattern::NonBase10Literal { .. }
|
| Pattern::NonBase10Literal { .. }
|
||||||
| Pattern::FloatLiteral(_)
|
| Pattern::FloatLiteral(..)
|
||||||
| Pattern::StrLiteral(_)
|
| Pattern::StrLiteral(_)
|
||||||
| Pattern::Underscore(_)
|
| Pattern::Underscore(_)
|
||||||
| Pattern::Malformed(_)
|
| Pattern::Malformed(_)
|
||||||
|
@ -116,17 +116,17 @@ impl<'a> Formattable for Pattern<'a> {
|
||||||
loc_pattern.format(buf, indent);
|
loc_pattern.format(buf, indent);
|
||||||
}
|
}
|
||||||
|
|
||||||
NumLiteral(string) => {
|
&NumLiteral(string) => {
|
||||||
buf.indent(indent);
|
buf.indent(indent);
|
||||||
buf.push_str(string);
|
buf.push_str(string);
|
||||||
}
|
}
|
||||||
NonBase10Literal {
|
&NonBase10Literal {
|
||||||
base,
|
base,
|
||||||
string,
|
string,
|
||||||
is_negative,
|
is_negative,
|
||||||
} => {
|
} => {
|
||||||
buf.indent(indent);
|
buf.indent(indent);
|
||||||
if *is_negative {
|
if is_negative {
|
||||||
buf.push('-');
|
buf.push('-');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ impl<'a> Formattable for Pattern<'a> {
|
||||||
|
|
||||||
buf.push_str(string);
|
buf.push_str(string);
|
||||||
}
|
}
|
||||||
FloatLiteral(string) => {
|
&FloatLiteral(string) => {
|
||||||
buf.indent(indent);
|
buf.indent(indent);
|
||||||
buf.push_str(string);
|
buf.push_str(string);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2675,13 +2675,7 @@ mod test_fmt {
|
||||||
exposes [] \
|
exposes [] \
|
||||||
packages {} \
|
packages {} \
|
||||||
imports [ Task.{ Task } ] \
|
imports [ Task.{ Task } ] \
|
||||||
provides [ mainForHost ] \
|
provides [ mainForHost ]",
|
||||||
effects fx.Effect \
|
|
||||||
{ \
|
|
||||||
putLine : Str -> Effect {}, \
|
|
||||||
putInt : I64 -> Effect {}, \
|
|
||||||
getInt : Effect { value : I64, errorCode : [ A, B ], isError : Bool } \
|
|
||||||
}",
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -771,11 +771,13 @@ pub fn build_exp_literal<'a, 'ctx, 'env>(
|
||||||
env.context.bool_type().const_int(*int as u64, false).into()
|
env.context.bool_type().const_int(*int as u64, false).into()
|
||||||
}
|
}
|
||||||
Layout::Builtin(Builtin::Int(int_width)) => {
|
Layout::Builtin(Builtin::Int(int_width)) => {
|
||||||
int_with_precision(env, *int as i128, *int_width).into()
|
int_with_precision(env, *int, *int_width).into()
|
||||||
}
|
}
|
||||||
_ => panic!("Invalid layout for int literal = {:?}", layout),
|
_ => panic!("Invalid layout for int literal = {:?}", layout),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
U128(int) => const_u128(env, *int).into(),
|
||||||
|
|
||||||
Float(float) => match layout {
|
Float(float) => match layout {
|
||||||
Layout::Builtin(Builtin::Float(float_width)) => {
|
Layout::Builtin(Builtin::Float(float_width)) => {
|
||||||
float_with_precision(env, *float, *float_width)
|
float_with_precision(env, *float, *float_width)
|
||||||
|
@ -3073,6 +3075,19 @@ fn const_i128<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>, value: i128) -> IntValu
|
||||||
.const_int_arbitrary_precision(&[a, b])
|
.const_int_arbitrary_precision(&[a, b])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn const_u128<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>, value: u128) -> IntValue<'ctx> {
|
||||||
|
// truncate the lower 64 bits
|
||||||
|
let value = value as u128;
|
||||||
|
let a = value as u64;
|
||||||
|
|
||||||
|
// get the upper 64 bits
|
||||||
|
let b = (value >> 64) as u64;
|
||||||
|
|
||||||
|
env.context
|
||||||
|
.i128_type()
|
||||||
|
.const_int_arbitrary_precision(&[a, b])
|
||||||
|
}
|
||||||
|
|
||||||
fn build_switch_ir<'a, 'ctx, 'env>(
|
fn build_switch_ir<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
|
@ -5284,11 +5299,6 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Fix me! I should be different in tests vs. user code!
|
|
||||||
fn expect_failed() {
|
|
||||||
panic!("An expectation failed!");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn run_low_level<'a, 'ctx, 'env>(
|
fn run_low_level<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
@ -5299,7 +5309,6 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
op: LowLevel,
|
op: LowLevel,
|
||||||
args: &[Symbol],
|
args: &[Symbol],
|
||||||
update_mode: UpdateMode,
|
update_mode: UpdateMode,
|
||||||
// expect_failed: *const (),
|
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
use LowLevel::*;
|
use LowLevel::*;
|
||||||
|
|
||||||
|
@ -6063,21 +6072,28 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
match env.target_info.ptr_width() {
|
match env.target_info.ptr_width() {
|
||||||
roc_target::PtrWidth::Bytes8 => {
|
roc_target::PtrWidth::Bytes8 => {
|
||||||
let fn_ptr_type = context
|
let func = env
|
||||||
.void_type()
|
.module
|
||||||
.fn_type(&[], false)
|
.get_function(bitcode::UTILS_EXPECT_FAILED)
|
||||||
.ptr_type(AddressSpace::Generic);
|
.unwrap();
|
||||||
let fn_addr = env
|
// TODO get the actual line info instead of
|
||||||
.ptr_int()
|
// hardcoding as zero!
|
||||||
.const_int(expect_failed as *const () as u64, false);
|
|
||||||
let func: PointerValue<'ctx> = bd.build_int_to_ptr(
|
|
||||||
fn_addr,
|
|
||||||
fn_ptr_type,
|
|
||||||
"cast_expect_failed_addr_to_ptr",
|
|
||||||
);
|
|
||||||
let callable = CallableValue::try_from(func).unwrap();
|
let callable = CallableValue::try_from(func).unwrap();
|
||||||
|
let start_line = context.i32_type().const_int(0, false);
|
||||||
|
let end_line = context.i32_type().const_int(0, false);
|
||||||
|
let start_col = context.i16_type().const_int(0, false);
|
||||||
|
let end_col = context.i16_type().const_int(0, false);
|
||||||
|
|
||||||
bd.build_call(callable, &[], "call_expect_failed");
|
bd.build_call(
|
||||||
|
callable,
|
||||||
|
&[
|
||||||
|
start_line.into(),
|
||||||
|
end_line.into(),
|
||||||
|
start_col.into(),
|
||||||
|
end_col.into(),
|
||||||
|
],
|
||||||
|
"call_expect_failed",
|
||||||
|
);
|
||||||
|
|
||||||
bd.build_unconditional_branch(then_block);
|
bd.build_unconditional_branch(then_block);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,43 @@ pub fn add_default_roc_externs(env: &Env<'_, '_, '_>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// roc_memcpy
|
||||||
|
{
|
||||||
|
// The type of this function (but not the implementation) should have
|
||||||
|
// already been defined by the builtins, which rely on it.
|
||||||
|
let fn_val = module.get_function("roc_memcpy").unwrap();
|
||||||
|
let mut params = fn_val.get_param_iter();
|
||||||
|
let dest_arg = params.next().unwrap();
|
||||||
|
let dest_alignment = 1;
|
||||||
|
let src_arg = params.next().unwrap();
|
||||||
|
let src_alignment = 1;
|
||||||
|
let bytes_arg = params.next().unwrap();
|
||||||
|
|
||||||
|
debug_assert!(params.next().is_none());
|
||||||
|
|
||||||
|
// Add a basic block for the entry point
|
||||||
|
let entry = ctx.append_basic_block(fn_val, "entry");
|
||||||
|
|
||||||
|
builder.position_at_end(entry);
|
||||||
|
|
||||||
|
// Call libc memcpy()
|
||||||
|
let _retval = builder
|
||||||
|
.build_memcpy(
|
||||||
|
dest_arg.into_pointer_value(),
|
||||||
|
dest_alignment,
|
||||||
|
src_arg.into_pointer_value(),
|
||||||
|
src_alignment,
|
||||||
|
bytes_arg.into_int_value(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
builder.build_return(None);
|
||||||
|
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
crate::llvm::build::verify_fn(fn_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// roc_realloc
|
// roc_realloc
|
||||||
{
|
{
|
||||||
let libc_realloc_val = {
|
let libc_realloc_val = {
|
||||||
|
|
|
@ -38,10 +38,23 @@ macro_rules! run_jit_function {
|
||||||
}};
|
}};
|
||||||
|
|
||||||
($lib: expr, $main_fn_name: expr, $ty:ty, $transform:expr, $errors:expr) => {{
|
($lib: expr, $main_fn_name: expr, $ty:ty, $transform:expr, $errors:expr) => {{
|
||||||
|
run_jit_function!($lib, $main_fn_name, $ty, $transform, $errors, &[])
|
||||||
|
}};
|
||||||
|
($lib: expr, $main_fn_name: expr, $ty:ty, $transform:expr, $errors:expr, $expect_failures:expr) => {{
|
||||||
use inkwell::context::Context;
|
use inkwell::context::Context;
|
||||||
|
use roc_builtins::bitcode;
|
||||||
use roc_gen_llvm::run_roc::RocCallResult;
|
use roc_gen_llvm::run_roc::RocCallResult;
|
||||||
use std::mem::MaybeUninit;
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct Failure {
|
||||||
|
start_line: u32,
|
||||||
|
end_line: u32,
|
||||||
|
start_col: u16,
|
||||||
|
end_col: u16,
|
||||||
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let main: libloading::Symbol<unsafe extern "C" fn(*mut RocCallResult<$ty>) -> ()> =
|
let main: libloading::Symbol<unsafe extern "C" fn(*mut RocCallResult<$ty>) -> ()> =
|
||||||
$lib.get($main_fn_name.as_bytes())
|
$lib.get($main_fn_name.as_bytes())
|
||||||
|
@ -49,11 +62,50 @@ macro_rules! run_jit_function {
|
||||||
.ok_or(format!("Unable to JIT compile `{}`", $main_fn_name))
|
.ok_or(format!("Unable to JIT compile `{}`", $main_fn_name))
|
||||||
.expect("errored");
|
.expect("errored");
|
||||||
|
|
||||||
let mut result = MaybeUninit::uninit();
|
#[repr(C)]
|
||||||
|
struct Failures {
|
||||||
|
failures: *const Failure,
|
||||||
|
count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
main(result.as_mut_ptr());
|
impl Drop for Failures {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
use std::alloc::{dealloc, Layout};
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
match result.assume_init().into() {
|
unsafe {
|
||||||
|
let layout = Layout::from_size_align_unchecked(
|
||||||
|
mem::size_of::<Failure>(),
|
||||||
|
mem::align_of::<Failure>(),
|
||||||
|
);
|
||||||
|
|
||||||
|
dealloc(self.failures as *mut u8, layout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let get_expect_failures: libloading::Symbol<unsafe extern "C" fn() -> Failures> = $lib
|
||||||
|
.get(bitcode::UTILS_GET_EXPECT_FAILURES.as_bytes())
|
||||||
|
.ok()
|
||||||
|
.ok_or(format!(
|
||||||
|
"Unable to JIT compile `{}`",
|
||||||
|
bitcode::UTILS_GET_EXPECT_FAILURES
|
||||||
|
))
|
||||||
|
.expect("errored");
|
||||||
|
let mut main_result = MaybeUninit::uninit();
|
||||||
|
|
||||||
|
main(main_result.as_mut_ptr());
|
||||||
|
let failures = get_expect_failures();
|
||||||
|
|
||||||
|
if failures.count > 0 {
|
||||||
|
// TODO tell the user about the failures!
|
||||||
|
let failures =
|
||||||
|
unsafe { core::slice::from_raw_parts(failures.failures, failures.count) };
|
||||||
|
|
||||||
|
panic!("Failed with {} failures. Failures: ", failures.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
match main_result.assume_init().into() {
|
||||||
Ok(success) => {
|
Ok(success) => {
|
||||||
// only if there are no exceptions thrown, check for errors
|
// only if there are no exceptions thrown, check for errors
|
||||||
assert!($errors.is_empty(), "Encountered errors:\n{}", $errors);
|
assert!($errors.is_empty(), "Encountered errors:\n{}", $errors);
|
||||||
|
|
|
@ -13,7 +13,7 @@ use roc_constrain::module::{
|
||||||
constrain_imports, pre_constrain_imports, ConstrainableImports, Import,
|
constrain_imports, pre_constrain_imports, ConstrainableImports, Import,
|
||||||
};
|
};
|
||||||
use roc_constrain::module::{constrain_module, ExposedModuleTypes, SubsByModule};
|
use roc_constrain::module::{constrain_module, ExposedModuleTypes, SubsByModule};
|
||||||
use roc_module::ident::{Ident, ModuleName, QualifiedModuleName, TagName};
|
use roc_module::ident::{Ident, ModuleName, QualifiedModuleName};
|
||||||
use roc_module::symbol::{
|
use roc_module::symbol::{
|
||||||
IdentIds, Interns, ModuleId, ModuleIds, PQModuleName, PackageModuleIds, PackageQualified,
|
IdentIds, Interns, ModuleId, ModuleIds, PQModuleName, PackageModuleIds, PackageQualified,
|
||||||
Symbol,
|
Symbol,
|
||||||
|
@ -23,9 +23,9 @@ use roc_mono::ir::{
|
||||||
UpdateModeIds,
|
UpdateModeIds,
|
||||||
};
|
};
|
||||||
use roc_mono::layout::{Layout, LayoutCache, LayoutProblem};
|
use roc_mono::layout::{Layout, LayoutCache, LayoutProblem};
|
||||||
use roc_parse::ast::{self, ExtractSpaces, Spaced, StrLiteral, TypeAnnotation};
|
use roc_parse::ast::{self, ExtractSpaces, Spaced, StrLiteral};
|
||||||
use roc_parse::header::PackageName;
|
|
||||||
use roc_parse::header::{ExposedName, ImportsEntry, PackageEntry, PlatformHeader, To, TypedIdent};
|
use roc_parse::header::{ExposedName, ImportsEntry, PackageEntry, PlatformHeader, To, TypedIdent};
|
||||||
|
use roc_parse::header::{HeaderFor, ModuleNameEnum, PackageName};
|
||||||
use roc_parse::ident::UppercaseIdent;
|
use roc_parse::ident::UppercaseIdent;
|
||||||
use roc_parse::module::module_defs;
|
use roc_parse::module::module_defs;
|
||||||
use roc_parse::parser::{FileError, Parser, SyntaxError};
|
use roc_parse::parser::{FileError, Parser, SyntaxError};
|
||||||
|
@ -35,7 +35,7 @@ use roc_solve::solve;
|
||||||
use roc_target::TargetInfo;
|
use roc_target::TargetInfo;
|
||||||
use roc_types::solved_types::Solved;
|
use roc_types::solved_types::Solved;
|
||||||
use roc_types::subs::{Subs, VarStore, Variable};
|
use roc_types::subs::{Subs, VarStore, Variable};
|
||||||
use roc_types::types::{Alias, Type};
|
use roc_types::types::Alias;
|
||||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::io;
|
use std::io;
|
||||||
|
@ -165,37 +165,6 @@ impl<'a> Dependencies<'a> {
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_effect_module(
|
|
||||||
&mut self,
|
|
||||||
module_id: ModuleId,
|
|
||||||
dependencies: &MutSet<ModuleId>,
|
|
||||||
goal_phase: Phase,
|
|
||||||
) -> MutSet<(ModuleId, Phase)> {
|
|
||||||
// add dependencies for self
|
|
||||||
// phase i + 1 of a file always depends on phase i being completed
|
|
||||||
{
|
|
||||||
let mut i = 2;
|
|
||||||
|
|
||||||
// platform modules should only start at CanonicalizeAndConstrain
|
|
||||||
debug_assert!(PHASES[i] == Phase::CanonicalizeAndConstrain);
|
|
||||||
while PHASES[i] < goal_phase {
|
|
||||||
self.add_dependency_help(module_id, module_id, PHASES[i + 1], PHASES[i]);
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.add_to_status(module_id, goal_phase);
|
|
||||||
|
|
||||||
let mut output = MutSet::default();
|
|
||||||
|
|
||||||
// all the dependencies can be loaded
|
|
||||||
for dep in dependencies {
|
|
||||||
output.insert((*dep, Phase::LoadHeader));
|
|
||||||
}
|
|
||||||
|
|
||||||
output
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_to_status(&mut self, module_id: ModuleId, goal_phase: Phase) {
|
fn add_to_status(&mut self, module_id: ModuleId, goal_phase: Phase) {
|
||||||
for phase in PHASES.iter() {
|
for phase in PHASES.iter() {
|
||||||
if *phase > goal_phase {
|
if *phase > goal_phase {
|
||||||
|
@ -674,24 +643,7 @@ struct ModuleHeader<'a> {
|
||||||
exposed_imports: MutMap<Ident, (Symbol, Region)>,
|
exposed_imports: MutMap<Ident, (Symbol, Region)>,
|
||||||
parse_state: roc_parse::state::State<'a>,
|
parse_state: roc_parse::state::State<'a>,
|
||||||
module_timing: ModuleTiming,
|
module_timing: ModuleTiming,
|
||||||
}
|
header_for: HeaderFor<'a>,
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum HeaderFor<'a> {
|
|
||||||
App {
|
|
||||||
to_platform: To<'a>,
|
|
||||||
},
|
|
||||||
PkgConfig {
|
|
||||||
/// usually `pf`
|
|
||||||
config_shorthand: &'a str,
|
|
||||||
/// the type scheme of the main function (required by the platform)
|
|
||||||
/// (currently unused)
|
|
||||||
#[allow(dead_code)]
|
|
||||||
platform_main_type: TypedIdent<'a>,
|
|
||||||
/// provided symbol to host (commonly `mainForHost`)
|
|
||||||
main_for_host: Symbol,
|
|
||||||
},
|
|
||||||
Interface,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -774,7 +726,6 @@ impl<'a> MonomorphizedModule<'a> {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct ParsedModule<'a> {
|
struct ParsedModule<'a> {
|
||||||
module_id: ModuleId,
|
module_id: ModuleId,
|
||||||
module_name: ModuleNameEnum<'a>,
|
|
||||||
module_path: PathBuf,
|
module_path: PathBuf,
|
||||||
src: &'a str,
|
src: &'a str,
|
||||||
module_timing: ModuleTiming,
|
module_timing: ModuleTiming,
|
||||||
|
@ -783,6 +734,8 @@ struct ParsedModule<'a> {
|
||||||
exposed_ident_ids: IdentIds,
|
exposed_ident_ids: IdentIds,
|
||||||
exposed_imports: MutMap<Ident, (Symbol, Region)>,
|
exposed_imports: MutMap<Ident, (Symbol, Region)>,
|
||||||
parsed_defs: &'a [Loc<roc_parse::ast::Def<'a>>],
|
parsed_defs: &'a [Loc<roc_parse::ast::Def<'a>>],
|
||||||
|
module_name: ModuleNameEnum<'a>,
|
||||||
|
header_for: HeaderFor<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A message sent out _from_ a worker thread,
|
/// A message sent out _from_ a worker thread,
|
||||||
|
@ -790,19 +743,13 @@ struct ParsedModule<'a> {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Msg<'a> {
|
enum Msg<'a> {
|
||||||
Many(Vec<Msg<'a>>),
|
Many(Vec<Msg<'a>>),
|
||||||
Header(ModuleHeader<'a>, HeaderFor<'a>),
|
Header(ModuleHeader<'a>),
|
||||||
Parsed(ParsedModule<'a>),
|
Parsed(ParsedModule<'a>),
|
||||||
CanonicalizedAndConstrained {
|
CanonicalizedAndConstrained {
|
||||||
constrained_module: ConstrainedModule,
|
constrained_module: ConstrainedModule,
|
||||||
canonicalization_problems: Vec<roc_problem::can::Problem>,
|
canonicalization_problems: Vec<roc_problem::can::Problem>,
|
||||||
module_docs: Option<ModuleDocumentation>,
|
module_docs: Option<ModuleDocumentation>,
|
||||||
},
|
},
|
||||||
MadeEffectModule {
|
|
||||||
type_shortname: &'a str,
|
|
||||||
constrained_module: ConstrainedModule,
|
|
||||||
canonicalization_problems: Vec<roc_problem::can::Problem>,
|
|
||||||
module_docs: ModuleDocumentation,
|
|
||||||
},
|
|
||||||
SolvedTypes {
|
SolvedTypes {
|
||||||
module_id: ModuleId,
|
module_id: ModuleId,
|
||||||
ident_ids: IdentIds,
|
ident_ids: IdentIds,
|
||||||
|
@ -861,6 +808,7 @@ enum PlatformPath<'a> {
|
||||||
NotSpecified,
|
NotSpecified,
|
||||||
Valid(To<'a>),
|
Valid(To<'a>),
|
||||||
RootIsInterface,
|
RootIsInterface,
|
||||||
|
RootIsHosted,
|
||||||
RootIsPkgConfig,
|
RootIsPkgConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1695,7 +1643,7 @@ fn update<'a>(
|
||||||
|
|
||||||
Ok(state)
|
Ok(state)
|
||||||
}
|
}
|
||||||
Header(header, header_extra) => {
|
Header(header) => {
|
||||||
use HeaderFor::*;
|
use HeaderFor::*;
|
||||||
|
|
||||||
log!("loaded header for {:?}", header.module_id);
|
log!("loaded header for {:?}", header.module_id);
|
||||||
|
@ -1712,13 +1660,13 @@ fn update<'a>(
|
||||||
|
|
||||||
if let PkgConfig {
|
if let PkgConfig {
|
||||||
config_shorthand, ..
|
config_shorthand, ..
|
||||||
} = header_extra
|
} = header.header_for
|
||||||
{
|
{
|
||||||
work.extend(state.dependencies.notify_package(config_shorthand));
|
work.extend(state.dependencies.notify_package(config_shorthand));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match header_extra {
|
match header.header_for {
|
||||||
App { to_platform } => {
|
App { to_platform } => {
|
||||||
debug_assert!(matches!(state.platform_path, PlatformPath::NotSpecified));
|
debug_assert!(matches!(state.platform_path, PlatformPath::NotSpecified));
|
||||||
state.platform_path = PlatformPath::Valid(to_platform);
|
state.platform_path = PlatformPath::Valid(to_platform);
|
||||||
|
@ -1742,6 +1690,12 @@ fn update<'a>(
|
||||||
state.platform_path = PlatformPath::RootIsInterface;
|
state.platform_path = PlatformPath::RootIsInterface;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Hosted { .. } => {
|
||||||
|
if header.is_root_module {
|
||||||
|
debug_assert!(matches!(state.platform_path, PlatformPath::NotSpecified));
|
||||||
|
state.platform_path = PlatformPath::RootIsHosted;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// store an ID to name mapping, so we know the file to read when fetching dependencies' headers
|
// store an ID to name mapping, so we know the file to read when fetching dependencies' headers
|
||||||
|
@ -1863,57 +1817,6 @@ fn update<'a>(
|
||||||
|
|
||||||
Ok(state)
|
Ok(state)
|
||||||
}
|
}
|
||||||
MadeEffectModule {
|
|
||||||
constrained_module,
|
|
||||||
canonicalization_problems,
|
|
||||||
module_docs,
|
|
||||||
type_shortname,
|
|
||||||
} => {
|
|
||||||
let module_id = constrained_module.module.module_id;
|
|
||||||
|
|
||||||
log!("made effect module for {:?}", module_id);
|
|
||||||
state
|
|
||||||
.module_cache
|
|
||||||
.can_problems
|
|
||||||
.insert(module_id, canonicalization_problems);
|
|
||||||
|
|
||||||
state
|
|
||||||
.module_cache
|
|
||||||
.documentation
|
|
||||||
.insert(module_id, module_docs);
|
|
||||||
|
|
||||||
state
|
|
||||||
.module_cache
|
|
||||||
.aliases
|
|
||||||
.insert(module_id, constrained_module.module.aliases.clone());
|
|
||||||
|
|
||||||
state
|
|
||||||
.module_cache
|
|
||||||
.constrained
|
|
||||||
.insert(module_id, constrained_module);
|
|
||||||
|
|
||||||
let mut work = state.dependencies.add_effect_module(
|
|
||||||
module_id,
|
|
||||||
&MutSet::default(),
|
|
||||||
state.goal_phase,
|
|
||||||
);
|
|
||||||
|
|
||||||
work.extend(state.dependencies.notify_package(type_shortname));
|
|
||||||
|
|
||||||
work.extend(state.dependencies.notify(module_id, Phase::LoadHeader));
|
|
||||||
|
|
||||||
work.extend(state.dependencies.notify(module_id, Phase::Parse));
|
|
||||||
|
|
||||||
work.extend(
|
|
||||||
state
|
|
||||||
.dependencies
|
|
||||||
.notify(module_id, Phase::CanonicalizeAndConstrain),
|
|
||||||
);
|
|
||||||
|
|
||||||
start_tasks(arena, &mut state, work, injector, worker_listeners)?;
|
|
||||||
|
|
||||||
Ok(state)
|
|
||||||
}
|
|
||||||
SolvedTypes {
|
SolvedTypes {
|
||||||
module_id,
|
module_id,
|
||||||
ident_ids,
|
ident_ids,
|
||||||
|
@ -2366,14 +2269,10 @@ fn load_pkg_config<'a>(
|
||||||
|
|
||||||
// Insert the first entries for this module's timings
|
// Insert the first entries for this module's timings
|
||||||
let mut pkg_module_timing = ModuleTiming::new(module_start_time);
|
let mut pkg_module_timing = ModuleTiming::new(module_start_time);
|
||||||
let mut effect_module_timing = ModuleTiming::new(module_start_time);
|
|
||||||
|
|
||||||
pkg_module_timing.read_roc_file = file_io_duration;
|
pkg_module_timing.read_roc_file = file_io_duration;
|
||||||
pkg_module_timing.parse_header = parse_header_duration;
|
pkg_module_timing.parse_header = parse_header_duration;
|
||||||
|
|
||||||
effect_module_timing.read_roc_file = file_io_duration;
|
|
||||||
effect_module_timing.parse_header = parse_header_duration;
|
|
||||||
|
|
||||||
match parsed {
|
match parsed {
|
||||||
Ok((ast::Module::Interface { header }, _parse_state)) => {
|
Ok((ast::Module::Interface { header }, _parse_state)) => {
|
||||||
Err(LoadingProblem::UnexpectedHeader(format!(
|
Err(LoadingProblem::UnexpectedHeader(format!(
|
||||||
|
@ -2396,23 +2295,13 @@ fn load_pkg_config<'a>(
|
||||||
filename,
|
filename,
|
||||||
parser_state,
|
parser_state,
|
||||||
module_ids.clone(),
|
module_ids.clone(),
|
||||||
ident_ids_by_module.clone(),
|
ident_ids_by_module,
|
||||||
&header,
|
&header,
|
||||||
pkg_module_timing,
|
pkg_module_timing,
|
||||||
)
|
)
|
||||||
.1;
|
.1;
|
||||||
|
|
||||||
let effects_module_msg = fabricate_effects_module(
|
Ok(pkg_config_module_msg)
|
||||||
arena,
|
|
||||||
header.effects.effect_shortname,
|
|
||||||
module_ids,
|
|
||||||
ident_ids_by_module,
|
|
||||||
header,
|
|
||||||
effect_module_timing,
|
|
||||||
)
|
|
||||||
.1;
|
|
||||||
|
|
||||||
Ok(Msg::Many(vec![effects_module_msg, pkg_config_module_msg]))
|
|
||||||
}
|
}
|
||||||
Ok((ast::Module::Hosted { header }, _parse_state)) => {
|
Ok((ast::Module::Hosted { header }, _parse_state)) => {
|
||||||
Err(LoadingProblem::UnexpectedHeader(format!(
|
Err(LoadingProblem::UnexpectedHeader(format!(
|
||||||
|
@ -2551,7 +2440,33 @@ fn parse_header<'a>(
|
||||||
packages: &[],
|
packages: &[],
|
||||||
exposes: unspace(arena, header.exposes.items),
|
exposes: unspace(arena, header.exposes.items),
|
||||||
imports: unspace(arena, header.imports.items),
|
imports: unspace(arena, header.imports.items),
|
||||||
to_platform: None,
|
extra: HeaderFor::Interface,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(send_header(
|
||||||
|
info,
|
||||||
|
parse_state,
|
||||||
|
module_ids,
|
||||||
|
ident_ids_by_module,
|
||||||
|
module_timing,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
Ok((ast::Module::Hosted { header }, parse_state)) => {
|
||||||
|
let info = HeaderInfo {
|
||||||
|
loc_name: Loc {
|
||||||
|
region: header.name.region,
|
||||||
|
value: ModuleNameEnum::Hosted(header.name.value),
|
||||||
|
},
|
||||||
|
filename,
|
||||||
|
is_root_module,
|
||||||
|
opt_shorthand,
|
||||||
|
packages: &[],
|
||||||
|
exposes: unspace(arena, header.exposes.items),
|
||||||
|
imports: unspace(arena, header.imports.items),
|
||||||
|
extra: HeaderFor::Hosted {
|
||||||
|
generates: header.generates,
|
||||||
|
generates_with: unspace(arena, header.generates_with.items),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(send_header(
|
Ok(send_header(
|
||||||
|
@ -2593,7 +2508,9 @@ fn parse_header<'a>(
|
||||||
packages,
|
packages,
|
||||||
exposes,
|
exposes,
|
||||||
imports: unspace(arena, header.imports.items),
|
imports: unspace(arena, header.imports.items),
|
||||||
to_platform: Some(header.to.value),
|
extra: HeaderFor::App {
|
||||||
|
to_platform: header.to.value,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let (module_id, app_module_header_msg) = send_header(
|
let (module_id, app_module_header_msg) = send_header(
|
||||||
|
@ -2661,37 +2578,13 @@ fn parse_header<'a>(
|
||||||
To::NewPackage(_package_name) => Ok((module_id, app_module_header_msg)),
|
To::NewPackage(_package_name) => Ok((module_id, app_module_header_msg)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok((ast::Module::Platform { header }, _parse_state)) => Ok(fabricate_effects_module(
|
Ok((ast::Module::Platform { header }, _parse_state)) => {
|
||||||
arena,
|
Err(LoadingProblem::UnexpectedHeader(format!(
|
||||||
"",
|
"got an unexpected platform header\n{:?}",
|
||||||
module_ids,
|
header
|
||||||
ident_ids_by_module,
|
)))
|
||||||
header,
|
|
||||||
module_timing,
|
|
||||||
)),
|
|
||||||
Ok((ast::Module::Hosted { header }, parse_state)) => {
|
|
||||||
let info = HeaderInfo {
|
|
||||||
loc_name: Loc {
|
|
||||||
region: header.name.region,
|
|
||||||
value: ModuleNameEnum::Hosted(header.name.value),
|
|
||||||
},
|
|
||||||
filename,
|
|
||||||
is_root_module,
|
|
||||||
opt_shorthand,
|
|
||||||
packages: &[],
|
|
||||||
exposes: unspace(arena, header.exposes.items),
|
|
||||||
imports: unspace(arena, header.imports.items),
|
|
||||||
to_platform: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(send_header(
|
|
||||||
info,
|
|
||||||
parse_state,
|
|
||||||
module_ids,
|
|
||||||
ident_ids_by_module,
|
|
||||||
module_timing,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(fail) => Err(LoadingProblem::ParsingFailed(
|
Err(fail) => Err(LoadingProblem::ParsingFailed(
|
||||||
fail.map_problem(SyntaxError::Header)
|
fail.map_problem(SyntaxError::Header)
|
||||||
.into_file_error(filename),
|
.into_file_error(filename),
|
||||||
|
@ -2760,15 +2653,6 @@ fn load_from_str<'a>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum ModuleNameEnum<'a> {
|
|
||||||
/// A filename
|
|
||||||
App(StrLiteral<'a>),
|
|
||||||
Interface(roc_parse::header::ModuleName<'a>),
|
|
||||||
Hosted(roc_parse::header::ModuleName<'a>),
|
|
||||||
PkgConfig,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct HeaderInfo<'a> {
|
struct HeaderInfo<'a> {
|
||||||
loc_name: Loc<ModuleNameEnum<'a>>,
|
loc_name: Loc<ModuleNameEnum<'a>>,
|
||||||
|
@ -2778,7 +2662,7 @@ struct HeaderInfo<'a> {
|
||||||
packages: &'a [Loc<PackageEntry<'a>>],
|
packages: &'a [Loc<PackageEntry<'a>>],
|
||||||
exposes: &'a [Loc<ExposedName<'a>>],
|
exposes: &'a [Loc<ExposedName<'a>>],
|
||||||
imports: &'a [Loc<ImportsEntry<'a>>],
|
imports: &'a [Loc<ImportsEntry<'a>>],
|
||||||
to_platform: Option<To<'a>>,
|
extra: HeaderFor<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
@ -2799,7 +2683,7 @@ fn send_header<'a>(
|
||||||
packages,
|
packages,
|
||||||
exposes,
|
exposes,
|
||||||
imports,
|
imports,
|
||||||
to_platform,
|
extra,
|
||||||
} = info;
|
} = info;
|
||||||
|
|
||||||
let declared_name: ModuleName = match &loc_name.value {
|
let declared_name: ModuleName = match &loc_name.value {
|
||||||
|
@ -2936,11 +2820,6 @@ fn send_header<'a>(
|
||||||
// We always need to send these, even if deps is empty,
|
// We always need to send these, even if deps is empty,
|
||||||
// because the coordinator thread needs to receive this message
|
// because the coordinator thread needs to receive this message
|
||||||
// to decrement its "pending" count.
|
// to decrement its "pending" count.
|
||||||
let extra = match to_platform {
|
|
||||||
Some(to_platform) => HeaderFor::App { to_platform },
|
|
||||||
None => HeaderFor::Interface,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut package_qualified_imported_modules = MutSet::default();
|
let mut package_qualified_imported_modules = MutSet::default();
|
||||||
for (pq_module_name, module_id) in &deps_by_name {
|
for (pq_module_name, module_id) in &deps_by_name {
|
||||||
match pq_module_name {
|
match pq_module_name {
|
||||||
|
@ -2957,8 +2836,7 @@ fn send_header<'a>(
|
||||||
|
|
||||||
(
|
(
|
||||||
home,
|
home,
|
||||||
Msg::Header(
|
Msg::Header(ModuleHeader {
|
||||||
ModuleHeader {
|
|
||||||
module_id: home,
|
module_id: home,
|
||||||
module_path: filename,
|
module_path: filename,
|
||||||
is_root_module,
|
is_root_module,
|
||||||
|
@ -2972,9 +2850,8 @@ fn send_header<'a>(
|
||||||
parse_state,
|
parse_state,
|
||||||
exposed_imports: scope,
|
exposed_imports: scope,
|
||||||
module_timing,
|
module_timing,
|
||||||
},
|
header_for: extra,
|
||||||
extra,
|
}),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3023,7 +2900,6 @@ fn send_header_two<'a>(
|
||||||
HashMap::with_capacity_and_hasher(num_exposes, default_hasher());
|
HashMap::with_capacity_and_hasher(num_exposes, default_hasher());
|
||||||
|
|
||||||
// add standard imports
|
// add standard imports
|
||||||
// TODO add Effect by default
|
|
||||||
imported_modules.insert(app_module_id, Region::zero());
|
imported_modules.insert(app_module_id, Region::zero());
|
||||||
deps_by_name.insert(
|
deps_by_name.insert(
|
||||||
PQModuleName::Unqualified(ModuleName::APP.into()),
|
PQModuleName::Unqualified(ModuleName::APP.into()),
|
||||||
|
@ -3198,8 +3074,7 @@ fn send_header_two<'a>(
|
||||||
|
|
||||||
(
|
(
|
||||||
home,
|
home,
|
||||||
Msg::Header(
|
Msg::Header(ModuleHeader {
|
||||||
ModuleHeader {
|
|
||||||
module_id: home,
|
module_id: home,
|
||||||
module_path: filename,
|
module_path: filename,
|
||||||
is_root_module,
|
is_root_module,
|
||||||
|
@ -3213,9 +3088,8 @@ fn send_header_two<'a>(
|
||||||
parse_state,
|
parse_state,
|
||||||
exposed_imports: scope,
|
exposed_imports: scope,
|
||||||
module_timing,
|
module_timing,
|
||||||
},
|
header_for: extra,
|
||||||
extra,
|
}),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3383,272 +3257,6 @@ fn fabricate_pkg_config_module<'a>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
fn fabricate_effects_module<'a>(
|
|
||||||
arena: &'a Bump,
|
|
||||||
shorthand: &'a str,
|
|
||||||
module_ids: Arc<Mutex<PackageModuleIds<'a>>>,
|
|
||||||
ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
|
|
||||||
header: PlatformHeader<'a>,
|
|
||||||
module_timing: ModuleTiming,
|
|
||||||
) -> (ModuleId, Msg<'a>) {
|
|
||||||
let num_exposes = header.provides.len() + 1;
|
|
||||||
let mut exposed: Vec<Symbol> = Vec::with_capacity(num_exposes);
|
|
||||||
|
|
||||||
let effects = header.effects;
|
|
||||||
|
|
||||||
let module_id: ModuleId;
|
|
||||||
|
|
||||||
let effect_entries = unpack_exposes_entries(arena, effects.entries.items);
|
|
||||||
let name = effects.effect_type_name;
|
|
||||||
let declared_name: ModuleName = name.into();
|
|
||||||
|
|
||||||
let hardcoded_effect_symbols = {
|
|
||||||
let mut functions: Vec<_> = crate::effect_module::BUILTIN_EFFECT_FUNCTIONS
|
|
||||||
.iter()
|
|
||||||
.map(|x| x.0)
|
|
||||||
.collect();
|
|
||||||
functions.push(name);
|
|
||||||
|
|
||||||
functions
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut module_ids = (*module_ids).lock();
|
|
||||||
|
|
||||||
for exposed in header.exposes.iter() {
|
|
||||||
let module_name = exposed.value.extract_spaces().item;
|
|
||||||
|
|
||||||
module_ids.get_or_insert(&PQModuleName::Qualified(
|
|
||||||
shorthand,
|
|
||||||
module_name.as_str().into(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let exposed_ident_ids = {
|
|
||||||
// Lock just long enough to perform the minimal operations necessary.
|
|
||||||
let mut module_ids = (*module_ids).lock();
|
|
||||||
let mut ident_ids_by_module = (*ident_ids_by_module).lock();
|
|
||||||
|
|
||||||
let name = PQModuleName::Qualified(shorthand, declared_name);
|
|
||||||
module_id = module_ids.get_or_insert(&name);
|
|
||||||
|
|
||||||
// Ensure this module has an entry in the exposed_ident_ids map.
|
|
||||||
ident_ids_by_module
|
|
||||||
.entry(module_id)
|
|
||||||
.or_insert_with(IdentIds::default);
|
|
||||||
|
|
||||||
let ident_ids = ident_ids_by_module.get_mut(&module_id).unwrap();
|
|
||||||
|
|
||||||
// Generate IdentIds entries for all values this module exposes.
|
|
||||||
// This way, when we encounter them in Defs later, they already
|
|
||||||
// have an IdentIds entry.
|
|
||||||
//
|
|
||||||
// We must *not* add them to scope yet, or else the Defs will
|
|
||||||
// incorrectly think they're shadowing them!
|
|
||||||
for (loc_exposed, _) in effect_entries.iter() {
|
|
||||||
// Use get_or_insert here because the ident_ids may already
|
|
||||||
// created an IdentId for this, when it was imported exposed
|
|
||||||
// in a dependent module.
|
|
||||||
//
|
|
||||||
// For example, if module A has [ B.{ foo } ], then
|
|
||||||
// when we get here for B, `foo` will already have
|
|
||||||
// an IdentId. We must reuse that!
|
|
||||||
let ident_id = ident_ids.get_or_insert(&loc_exposed.value.into());
|
|
||||||
let symbol = Symbol::new(module_id, ident_id);
|
|
||||||
|
|
||||||
exposed.push(symbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
for hardcoded in hardcoded_effect_symbols {
|
|
||||||
// Use get_or_insert here because the ident_ids may already
|
|
||||||
// created an IdentId for this, when it was imported exposed
|
|
||||||
// in a dependent module.
|
|
||||||
//
|
|
||||||
// For example, if module A has [ B.{ foo } ], then
|
|
||||||
// when we get here for B, `foo` will already have
|
|
||||||
// an IdentId. We must reuse that!
|
|
||||||
let ident_id = ident_ids.get_or_insert(&hardcoded.into());
|
|
||||||
let symbol = Symbol::new(module_id, ident_id);
|
|
||||||
|
|
||||||
exposed.push(symbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
if cfg!(debug_assertions) {
|
|
||||||
module_id.register_debug_idents(ident_ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
ident_ids.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
// a platform module has no dependencies, hence empty
|
|
||||||
let dep_idents: MutMap<ModuleId, IdentIds> = IdentIds::exposed_builtins(0);
|
|
||||||
|
|
||||||
let mut var_store = VarStore::default();
|
|
||||||
|
|
||||||
let module_ids = { (*module_ids).lock().clone() }.into_module_ids();
|
|
||||||
|
|
||||||
let mut scope = roc_can::scope::Scope::new(module_id, &mut var_store);
|
|
||||||
let mut can_env =
|
|
||||||
roc_can::env::Env::new(module_id, &dep_idents, &module_ids, exposed_ident_ids);
|
|
||||||
|
|
||||||
let effect_symbol = scope
|
|
||||||
.introduce(
|
|
||||||
name.into(),
|
|
||||||
&can_env.exposed_ident_ids,
|
|
||||||
&mut can_env.ident_ids,
|
|
||||||
Region::zero(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let effect_tag_name = TagName::Private(effect_symbol);
|
|
||||||
|
|
||||||
let mut aliases = MutMap::default();
|
|
||||||
let alias = {
|
|
||||||
let a_var = var_store.fresh();
|
|
||||||
|
|
||||||
let actual = crate::effect_module::build_effect_actual(
|
|
||||||
effect_tag_name,
|
|
||||||
Type::Variable(a_var),
|
|
||||||
&mut var_store,
|
|
||||||
);
|
|
||||||
|
|
||||||
scope.add_alias(
|
|
||||||
effect_symbol,
|
|
||||||
Region::zero(),
|
|
||||||
vec![Loc::at_zero(("a".into(), a_var))],
|
|
||||||
actual,
|
|
||||||
);
|
|
||||||
|
|
||||||
scope.lookup_alias(effect_symbol).unwrap().clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
aliases.insert(effect_symbol, alias);
|
|
||||||
|
|
||||||
let mut declarations = Vec::new();
|
|
||||||
|
|
||||||
let exposed_symbols: MutSet<Symbol> = {
|
|
||||||
let mut exposed_symbols = MutSet::default();
|
|
||||||
|
|
||||||
{
|
|
||||||
for (ident, ann) in effect_entries {
|
|
||||||
let symbol = {
|
|
||||||
scope
|
|
||||||
.introduce(
|
|
||||||
ident.value.into(),
|
|
||||||
&can_env.exposed_ident_ids,
|
|
||||||
&mut can_env.ident_ids,
|
|
||||||
Region::zero(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
};
|
|
||||||
|
|
||||||
let annotation = roc_can::annotation::canonicalize_annotation(
|
|
||||||
&mut can_env,
|
|
||||||
&mut scope,
|
|
||||||
&ann.value,
|
|
||||||
Region::zero(),
|
|
||||||
&mut var_store,
|
|
||||||
);
|
|
||||||
|
|
||||||
let def = crate::effect_module::build_host_exposed_def(
|
|
||||||
&mut can_env,
|
|
||||||
&mut scope,
|
|
||||||
symbol,
|
|
||||||
ident.value,
|
|
||||||
TagName::Private(effect_symbol),
|
|
||||||
&mut var_store,
|
|
||||||
annotation,
|
|
||||||
);
|
|
||||||
exposed_symbols.insert(symbol);
|
|
||||||
|
|
||||||
declarations.push(Declaration::Declare(def));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// define Effect.after, Effect.map etc.
|
|
||||||
crate::effect_module::build_effect_builtins(
|
|
||||||
&mut can_env,
|
|
||||||
&mut scope,
|
|
||||||
effect_symbol,
|
|
||||||
&mut var_store,
|
|
||||||
&mut exposed_symbols,
|
|
||||||
&mut declarations,
|
|
||||||
);
|
|
||||||
|
|
||||||
exposed_symbols
|
|
||||||
};
|
|
||||||
|
|
||||||
use roc_can::module::ModuleOutput;
|
|
||||||
let module_output = ModuleOutput {
|
|
||||||
aliases,
|
|
||||||
rigid_variables: MutMap::default(),
|
|
||||||
declarations,
|
|
||||||
exposed_imports: MutMap::default(),
|
|
||||||
lookups: Vec::new(),
|
|
||||||
problems: can_env.problems,
|
|
||||||
ident_ids: can_env.ident_ids,
|
|
||||||
references: MutSet::default(),
|
|
||||||
scope,
|
|
||||||
};
|
|
||||||
|
|
||||||
let constraint = constrain_module(&module_output.declarations, module_id);
|
|
||||||
|
|
||||||
let module = Module {
|
|
||||||
module_id,
|
|
||||||
exposed_imports: module_output.exposed_imports,
|
|
||||||
exposed_symbols,
|
|
||||||
references: module_output.references,
|
|
||||||
aliases: module_output.aliases,
|
|
||||||
rigid_variables: module_output.rigid_variables,
|
|
||||||
};
|
|
||||||
|
|
||||||
let imported_modules = MutMap::default();
|
|
||||||
|
|
||||||
// Should a effect module ever have a ModuleDocumentation?
|
|
||||||
let module_docs = ModuleDocumentation {
|
|
||||||
name: String::from(name),
|
|
||||||
entries: Vec::new(),
|
|
||||||
scope: module_output.scope,
|
|
||||||
};
|
|
||||||
|
|
||||||
let constrained_module = ConstrainedModule {
|
|
||||||
module,
|
|
||||||
declarations: module_output.declarations,
|
|
||||||
imported_modules,
|
|
||||||
var_store,
|
|
||||||
constraint,
|
|
||||||
ident_ids: module_output.ident_ids,
|
|
||||||
dep_idents,
|
|
||||||
module_timing,
|
|
||||||
};
|
|
||||||
|
|
||||||
(
|
|
||||||
module_id,
|
|
||||||
Msg::MadeEffectModule {
|
|
||||||
type_shortname: effects.effect_shortname,
|
|
||||||
constrained_module,
|
|
||||||
canonicalization_problems: module_output.problems,
|
|
||||||
module_docs,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unpack_exposes_entries<'a>(
|
|
||||||
arena: &'a Bump,
|
|
||||||
entries: &'a [Loc<Spaced<'a, TypedIdent<'a>>>],
|
|
||||||
) -> bumpalo::collections::Vec<'a, (Loc<&'a str>, Loc<TypeAnnotation<'a>>)> {
|
|
||||||
use bumpalo::collections::Vec;
|
|
||||||
|
|
||||||
let iter = entries.iter().map(|entry| {
|
|
||||||
let entry: TypedIdent<'a> = entry.value.extract_spaces().item;
|
|
||||||
(entry.ident, entry.ann)
|
|
||||||
});
|
|
||||||
|
|
||||||
Vec::from_iter_in(iter, arena)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
#[allow(clippy::unnecessary_wraps)]
|
#[allow(clippy::unnecessary_wraps)]
|
||||||
fn canonicalize_and_constrain<'a, F>(
|
fn canonicalize_and_constrain<'a, F>(
|
||||||
|
@ -3668,6 +3276,7 @@ where
|
||||||
let ParsedModule {
|
let ParsedModule {
|
||||||
module_id,
|
module_id,
|
||||||
module_name,
|
module_name,
|
||||||
|
header_for,
|
||||||
exposed_ident_ids,
|
exposed_ident_ids,
|
||||||
parsed_defs,
|
parsed_defs,
|
||||||
exposed_imports,
|
exposed_imports,
|
||||||
|
@ -3680,6 +3289,7 @@ where
|
||||||
let canonicalized = canonicalize_module_defs(
|
let canonicalized = canonicalize_module_defs(
|
||||||
arena,
|
arena,
|
||||||
parsed_defs,
|
parsed_defs,
|
||||||
|
&header_for,
|
||||||
module_id,
|
module_id,
|
||||||
module_ids,
|
module_ids,
|
||||||
exposed_ident_ids,
|
exposed_ident_ids,
|
||||||
|
@ -3702,12 +3312,14 @@ where
|
||||||
ModuleNameEnum::PkgConfig => None,
|
ModuleNameEnum::PkgConfig => None,
|
||||||
ModuleNameEnum::App(_) => None,
|
ModuleNameEnum::App(_) => None,
|
||||||
ModuleNameEnum::Interface(name) | ModuleNameEnum::Hosted(name) => {
|
ModuleNameEnum::Interface(name) | ModuleNameEnum::Hosted(name) => {
|
||||||
Some(crate::docs::generate_module_docs(
|
let docs = crate::docs::generate_module_docs(
|
||||||
module_output.scope,
|
module_output.scope,
|
||||||
name.as_str().into(),
|
name.as_str().into(),
|
||||||
&module_output.ident_ids,
|
&module_output.ident_ids,
|
||||||
parsed_defs,
|
parsed_defs,
|
||||||
))
|
);
|
||||||
|
|
||||||
|
Some(docs)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3784,6 +3396,7 @@ fn parse<'a>(arena: &'a Bump, header: ModuleHeader<'a>) -> Result<Msg<'a>, Loadi
|
||||||
exposed_ident_ids,
|
exposed_ident_ids,
|
||||||
exposed_imports,
|
exposed_imports,
|
||||||
module_path,
|
module_path,
|
||||||
|
header_for,
|
||||||
..
|
..
|
||||||
} = header;
|
} = header;
|
||||||
|
|
||||||
|
@ -3798,6 +3411,7 @@ fn parse<'a>(arena: &'a Bump, header: ModuleHeader<'a>) -> Result<Msg<'a>, Loadi
|
||||||
exposed_ident_ids,
|
exposed_ident_ids,
|
||||||
exposed_imports,
|
exposed_imports,
|
||||||
parsed_defs,
|
parsed_defs,
|
||||||
|
header_for,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Msg::Parsed(parsed))
|
Ok(Msg::Parsed(parsed))
|
||||||
|
@ -4430,7 +4044,23 @@ fn to_missing_platform_report(module_id: ModuleId, other: PlatformPath) -> Strin
|
||||||
}
|
}
|
||||||
RootIsInterface => {
|
RootIsInterface => {
|
||||||
let doc = alloc.stack(vec![
|
let doc = alloc.stack(vec![
|
||||||
alloc.reflow(r"The input file is a interface file, but only app modules can be ran."),
|
alloc.reflow(r"The input file is an interface module, but only app modules can be ran."),
|
||||||
|
alloc.concat(vec![
|
||||||
|
alloc.reflow(r"I will still parse and typecheck the input file and its dependencies, "),
|
||||||
|
alloc.reflow(r"but won't output any executable."),
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename: "UNKNOWN.roc".into(),
|
||||||
|
doc,
|
||||||
|
title: "NO PLATFORM".to_string(),
|
||||||
|
severity: Severity::RuntimeError,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RootIsHosted => {
|
||||||
|
let doc = alloc.stack(vec![
|
||||||
|
alloc.reflow(r"The input file is a hosted module, but only app modules can be ran."),
|
||||||
alloc.concat(vec![
|
alloc.concat(vec![
|
||||||
alloc.reflow(r"I will still parse and typecheck the input file and its dependencies, "),
|
alloc.reflow(r"I will still parse and typecheck the input file and its dependencies, "),
|
||||||
alloc.reflow(r"but won't output any executable."),
|
alloc.reflow(r"but won't output any executable."),
|
||||||
|
|
|
@ -2,5 +2,4 @@
|
||||||
// See github.com/rtfeldman/roc/issues/800 for discussion of the large_enum_variant check.
|
// See github.com/rtfeldman/roc/issues/800 for discussion of the large_enum_variant check.
|
||||||
#![allow(clippy::large_enum_variant)]
|
#![allow(clippy::large_enum_variant)]
|
||||||
pub mod docs;
|
pub mod docs;
|
||||||
pub mod effect_module;
|
|
||||||
pub mod file;
|
pub mod file;
|
||||||
|
|
|
@ -1638,7 +1638,9 @@ fn literal_spec(
|
||||||
|
|
||||||
match literal {
|
match literal {
|
||||||
Str(_) => new_static_string(builder, block),
|
Str(_) => new_static_string(builder, block),
|
||||||
Int(_) | Float(_) | Decimal(_) | Bool(_) | Byte(_) => builder.add_make_tuple(block, &[]),
|
Int(_) | U128(_) | Float(_) | Decimal(_) | Bool(_) | Byte(_) => {
|
||||||
|
builder.add_make_tuple(block, &[])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,6 +87,7 @@ enum Test<'a> {
|
||||||
arguments: Vec<(Pattern<'a>, Layout<'a>)>,
|
arguments: Vec<(Pattern<'a>, Layout<'a>)>,
|
||||||
},
|
},
|
||||||
IsInt(i128, IntWidth),
|
IsInt(i128, IntWidth),
|
||||||
|
IsU128(u128),
|
||||||
IsFloat(u64, FloatWidth),
|
IsFloat(u64, FloatWidth),
|
||||||
IsDecimal(RocDec),
|
IsDecimal(RocDec),
|
||||||
IsStr(Box<str>),
|
IsStr(Box<str>),
|
||||||
|
@ -136,6 +137,10 @@ impl<'a> Hash for Test<'a> {
|
||||||
state.write_u8(6);
|
state.write_u8(6);
|
||||||
v.0.hash(state);
|
v.0.hash(state);
|
||||||
}
|
}
|
||||||
|
IsU128(v) => {
|
||||||
|
state.write_u8(7);
|
||||||
|
v.hash(state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -311,6 +316,7 @@ fn tests_are_complete_help(last_test: &Test, number_of_tests: usize) -> bool {
|
||||||
Test::IsByte { num_alts, .. } => number_of_tests == *num_alts,
|
Test::IsByte { num_alts, .. } => number_of_tests == *num_alts,
|
||||||
Test::IsBit(_) => number_of_tests == 2,
|
Test::IsBit(_) => number_of_tests == 2,
|
||||||
Test::IsInt(_, _) => false,
|
Test::IsInt(_, _) => false,
|
||||||
|
Test::IsU128(_) => false,
|
||||||
Test::IsFloat(_, _) => false,
|
Test::IsFloat(_, _) => false,
|
||||||
Test::IsDecimal(_) => false,
|
Test::IsDecimal(_) => false,
|
||||||
Test::IsStr(_) => false,
|
Test::IsStr(_) => false,
|
||||||
|
@ -565,6 +571,7 @@ fn test_at_path<'a>(
|
||||||
num_alts: union.alternatives.len(),
|
num_alts: union.alternatives.len(),
|
||||||
},
|
},
|
||||||
IntLiteral(v, precision) => IsInt(*v, *precision),
|
IntLiteral(v, precision) => IsInt(*v, *precision),
|
||||||
|
U128Literal(v) => IsU128(*v),
|
||||||
FloatLiteral(v, precision) => IsFloat(*v, *precision),
|
FloatLiteral(v, precision) => IsFloat(*v, *precision),
|
||||||
DecimalLiteral(v) => IsDecimal(*v),
|
DecimalLiteral(v) => IsDecimal(*v),
|
||||||
StrLiteral(v) => IsStr(v.clone()),
|
StrLiteral(v) => IsStr(v.clone()),
|
||||||
|
@ -823,6 +830,18 @@ fn to_relevant_branch_help<'a>(
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
U128Literal(int) => match test {
|
||||||
|
IsU128(is_int) if int == *is_int => {
|
||||||
|
start.extend(end);
|
||||||
|
Some(Branch {
|
||||||
|
goal: branch.goal,
|
||||||
|
guard: branch.guard.clone(),
|
||||||
|
patterns: start,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
|
||||||
FloatLiteral(float, p1) => match test {
|
FloatLiteral(float, p1) => match test {
|
||||||
IsFloat(test_float, p2) if float == *test_float => {
|
IsFloat(test_float, p2) if float == *test_float => {
|
||||||
debug_assert_eq!(p1, *p2);
|
debug_assert_eq!(p1, *p2);
|
||||||
|
@ -934,6 +953,7 @@ fn needs_tests(pattern: &Pattern) -> bool {
|
||||||
| BitLiteral { .. }
|
| BitLiteral { .. }
|
||||||
| EnumLiteral { .. }
|
| EnumLiteral { .. }
|
||||||
| IntLiteral(_, _)
|
| IntLiteral(_, _)
|
||||||
|
| U128Literal(_)
|
||||||
| FloatLiteral(_, _)
|
| FloatLiteral(_, _)
|
||||||
| DecimalLiteral(_)
|
| DecimalLiteral(_)
|
||||||
| StrLiteral(_) => true,
|
| StrLiteral(_) => true,
|
||||||
|
@ -1305,6 +1325,14 @@ fn test_to_equality<'a>(
|
||||||
(stores, lhs_symbol, rhs_symbol, None)
|
(stores, lhs_symbol, rhs_symbol, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Test::IsU128(test_int) => {
|
||||||
|
let lhs = Expr::Literal(Literal::U128(test_int));
|
||||||
|
let lhs_symbol = env.unique_symbol();
|
||||||
|
stores.push((lhs_symbol, Layout::int_width(IntWidth::U128), lhs));
|
||||||
|
|
||||||
|
(stores, lhs_symbol, rhs_symbol, None)
|
||||||
|
}
|
||||||
|
|
||||||
Test::IsFloat(test_int, precision) => {
|
Test::IsFloat(test_int, precision) => {
|
||||||
// TODO maybe we can actually use i64 comparison here?
|
// TODO maybe we can actually use i64 comparison here?
|
||||||
let test_float = f64::from_bits(test_int as u64);
|
let test_float = f64::from_bits(test_int as u64);
|
||||||
|
|
|
@ -54,6 +54,7 @@ pub enum Pattern {
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum Literal {
|
pub enum Literal {
|
||||||
Int(i128),
|
Int(i128),
|
||||||
|
U128(u128),
|
||||||
Bit(bool),
|
Bit(bool),
|
||||||
Byte(u8),
|
Byte(u8),
|
||||||
Float(u64),
|
Float(u64),
|
||||||
|
@ -66,6 +67,7 @@ fn simplify(pattern: &crate::ir::Pattern) -> Pattern {
|
||||||
|
|
||||||
match pattern {
|
match pattern {
|
||||||
IntLiteral(v, _) => Literal(Literal::Int(*v)),
|
IntLiteral(v, _) => Literal(Literal::Int(*v)),
|
||||||
|
U128Literal(v) => Literal(Literal::U128(*v)),
|
||||||
FloatLiteral(v, _) => Literal(Literal::Float(*v)),
|
FloatLiteral(v, _) => Literal(Literal::Float(*v)),
|
||||||
DecimalLiteral(v) => Literal(Literal::Decimal(*v)),
|
DecimalLiteral(v) => Literal(Literal::Decimal(*v)),
|
||||||
StrLiteral(v) => Literal(Literal::Str(v.clone())),
|
StrLiteral(v) => Literal(Literal::Str(v.clone())),
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crate::layout::{
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||||
use roc_can::expr::ClosureData;
|
use roc_can::expr::{ClosureData, IntValue};
|
||||||
use roc_collections::all::{default_hasher, BumpMap, BumpMapDefault, MutMap};
|
use roc_collections::all::{default_hasher, BumpMap, BumpMapDefault, MutMap};
|
||||||
use roc_module::ident::{ForeignSymbol, Lowercase, TagName};
|
use roc_module::ident::{ForeignSymbol, Lowercase, TagName};
|
||||||
use roc_module::low_level::LowLevel;
|
use roc_module::low_level::LowLevel;
|
||||||
|
@ -1278,6 +1278,7 @@ impl ModifyRc {
|
||||||
pub enum Literal<'a> {
|
pub enum Literal<'a> {
|
||||||
// Literals
|
// Literals
|
||||||
Int(i128),
|
Int(i128),
|
||||||
|
U128(u128),
|
||||||
Float(f64),
|
Float(f64),
|
||||||
Decimal(RocDec),
|
Decimal(RocDec),
|
||||||
Str(&'a str),
|
Str(&'a str),
|
||||||
|
@ -1524,6 +1525,7 @@ impl<'a> Literal<'a> {
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Int(lit) => alloc.text(format!("{}i64", lit)),
|
Int(lit) => alloc.text(format!("{}i64", lit)),
|
||||||
|
U128(lit) => alloc.text(format!("{}u128", lit)),
|
||||||
Float(lit) => alloc.text(format!("{}f64", lit)),
|
Float(lit) => alloc.text(format!("{}f64", lit)),
|
||||||
// TODO: Add proper Dec.to_str
|
// TODO: Add proper Dec.to_str
|
||||||
Decimal(lit) => alloc.text(format!("{}Dec", lit.0)),
|
Decimal(lit) => alloc.text(format!("{}Dec", lit.0)),
|
||||||
|
@ -2020,7 +2022,7 @@ fn pattern_to_when<'a>(
|
||||||
(symbol, Loc::at_zero(wrapped_body))
|
(symbol, Loc::at_zero(wrapped_body))
|
||||||
}
|
}
|
||||||
|
|
||||||
IntLiteral(_, _, _) | NumLiteral(_, _, _) | FloatLiteral(_, _, _) | StrLiteral(_) => {
|
IntLiteral(..) | NumLiteral(..) | FloatLiteral(..) | StrLiteral(_) => {
|
||||||
// These patters are refutable, and thus should never occur outside a `when` expression
|
// These patters are refutable, and thus should never occur outside a `when` expression
|
||||||
// They should have been replaced with `UnsupportedPattern` during canonicalization
|
// They should have been replaced with `UnsupportedPattern` during canonicalization
|
||||||
unreachable!("refutable pattern {:?} where irrefutable pattern is expected. This should never happen!", pattern.value)
|
unreachable!("refutable pattern {:?} where irrefutable pattern is expected. This should never happen!", pattern.value)
|
||||||
|
@ -3009,14 +3011,17 @@ fn try_make_literal<'a>(
|
||||||
use roc_can::expr::Expr::*;
|
use roc_can::expr::Expr::*;
|
||||||
|
|
||||||
match can_expr {
|
match can_expr {
|
||||||
Int(_, precision, _, int) => {
|
Int(_, precision, _, int, _bound) => {
|
||||||
match num_argument_to_int_or_float(env.subs, env.target_info, *precision, false) {
|
match num_argument_to_int_or_float(env.subs, env.target_info, *precision, false) {
|
||||||
IntOrFloat::Int(_) => Some(Literal::Int(*int)),
|
IntOrFloat::Int(_) => Some(match *int {
|
||||||
|
IntValue::I128(n) => Literal::Int(n),
|
||||||
|
IntValue::U128(n) => Literal::U128(n),
|
||||||
|
}),
|
||||||
_ => unreachable!("unexpected float precision for integer"),
|
_ => unreachable!("unexpected float precision for integer"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Float(_, precision, float_str, float) => {
|
Float(_, precision, float_str, float, _bound) => {
|
||||||
match num_argument_to_int_or_float(env.subs, env.target_info, *precision, true) {
|
match num_argument_to_int_or_float(env.subs, env.target_info, *precision, true) {
|
||||||
IntOrFloat::Float(_) => Some(Literal::Float(*float)),
|
IntOrFloat::Float(_) => Some(Literal::Float(*float)),
|
||||||
IntOrFloat::DecimalFloatType => {
|
IntOrFloat::DecimalFloatType => {
|
||||||
|
@ -3036,11 +3041,17 @@ fn try_make_literal<'a>(
|
||||||
|
|
||||||
// TODO investigate lifetime trouble
|
// TODO investigate lifetime trouble
|
||||||
// Str(string) => Some(Literal::Str(env.arena.alloc(string))),
|
// Str(string) => Some(Literal::Str(env.arena.alloc(string))),
|
||||||
Num(var, num_str, num) => {
|
Num(var, num_str, num, _bound) => {
|
||||||
// first figure out what kind of number this is
|
// first figure out what kind of number this is
|
||||||
match num_argument_to_int_or_float(env.subs, env.target_info, *var, false) {
|
match num_argument_to_int_or_float(env.subs, env.target_info, *var, false) {
|
||||||
IntOrFloat::Int(_) => Some(Literal::Int((*num).into())),
|
IntOrFloat::Int(_) => Some(match *num {
|
||||||
IntOrFloat::Float(_) => Some(Literal::Float(*num as f64)),
|
IntValue::I128(n) => Literal::Int(n),
|
||||||
|
IntValue::U128(n) => Literal::U128(n),
|
||||||
|
}),
|
||||||
|
IntOrFloat::Float(_) => Some(match *num {
|
||||||
|
IntValue::I128(n) => Literal::Float(n as f64),
|
||||||
|
IntValue::U128(n) => Literal::Float(n as f64),
|
||||||
|
}),
|
||||||
IntOrFloat::DecimalFloatType => {
|
IntOrFloat::DecimalFloatType => {
|
||||||
let dec = match RocDec::from_str(num_str) {
|
let dec = match RocDec::from_str(num_str) {
|
||||||
Some(d) => d,
|
Some(d) => d,
|
||||||
|
@ -3072,11 +3083,14 @@ pub fn with_hole<'a>(
|
||||||
let arena = env.arena;
|
let arena = env.arena;
|
||||||
|
|
||||||
match can_expr {
|
match can_expr {
|
||||||
Int(_, precision, _, int) => {
|
Int(_, precision, _, int, _bound) => {
|
||||||
match num_argument_to_int_or_float(env.subs, env.target_info, precision, false) {
|
match num_argument_to_int_or_float(env.subs, env.target_info, precision, false) {
|
||||||
IntOrFloat::Int(precision) => Stmt::Let(
|
IntOrFloat::Int(precision) => Stmt::Let(
|
||||||
assigned,
|
assigned,
|
||||||
Expr::Literal(Literal::Int(int)),
|
Expr::Literal(match int {
|
||||||
|
IntValue::I128(n) => Literal::Int(n),
|
||||||
|
IntValue::U128(n) => Literal::U128(n),
|
||||||
|
}),
|
||||||
Layout::Builtin(Builtin::Int(precision)),
|
Layout::Builtin(Builtin::Int(precision)),
|
||||||
hole,
|
hole,
|
||||||
),
|
),
|
||||||
|
@ -3084,7 +3098,7 @@ pub fn with_hole<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Float(_, precision, float_str, float) => {
|
Float(_, precision, float_str, float, _bound) => {
|
||||||
match num_argument_to_int_or_float(env.subs, env.target_info, precision, true) {
|
match num_argument_to_int_or_float(env.subs, env.target_info, precision, true) {
|
||||||
IntOrFloat::Float(precision) => Stmt::Let(
|
IntOrFloat::Float(precision) => Stmt::Let(
|
||||||
assigned,
|
assigned,
|
||||||
|
@ -3115,18 +3129,24 @@ pub fn with_hole<'a>(
|
||||||
hole,
|
hole,
|
||||||
),
|
),
|
||||||
|
|
||||||
Num(var, num_str, num) => {
|
Num(var, num_str, num, _bound) => {
|
||||||
// first figure out what kind of number this is
|
// first figure out what kind of number this is
|
||||||
match num_argument_to_int_or_float(env.subs, env.target_info, var, false) {
|
match num_argument_to_int_or_float(env.subs, env.target_info, var, false) {
|
||||||
IntOrFloat::Int(precision) => Stmt::Let(
|
IntOrFloat::Int(precision) => Stmt::Let(
|
||||||
assigned,
|
assigned,
|
||||||
Expr::Literal(Literal::Int(num.into())),
|
Expr::Literal(match num {
|
||||||
|
IntValue::I128(n) => Literal::Int(n),
|
||||||
|
IntValue::U128(n) => Literal::U128(n),
|
||||||
|
}),
|
||||||
Layout::int_width(precision),
|
Layout::int_width(precision),
|
||||||
hole,
|
hole,
|
||||||
),
|
),
|
||||||
IntOrFloat::Float(precision) => Stmt::Let(
|
IntOrFloat::Float(precision) => Stmt::Let(
|
||||||
assigned,
|
assigned,
|
||||||
Expr::Literal(Literal::Float(num as f64)),
|
Expr::Literal(match num {
|
||||||
|
IntValue::I128(n) => Literal::Float(n as f64),
|
||||||
|
IntValue::U128(n) => Literal::Float(n as f64),
|
||||||
|
}),
|
||||||
Layout::float_width(precision),
|
Layout::float_width(precision),
|
||||||
hole,
|
hole,
|
||||||
),
|
),
|
||||||
|
@ -6211,6 +6231,7 @@ fn store_pattern_help<'a>(
|
||||||
return StorePattern::NotProductive(stmt);
|
return StorePattern::NotProductive(stmt);
|
||||||
}
|
}
|
||||||
IntLiteral(_, _)
|
IntLiteral(_, _)
|
||||||
|
| U128Literal(_)
|
||||||
| FloatLiteral(_, _)
|
| FloatLiteral(_, _)
|
||||||
| DecimalLiteral(_)
|
| DecimalLiteral(_)
|
||||||
| EnumLiteral { .. }
|
| EnumLiteral { .. }
|
||||||
|
@ -7583,6 +7604,7 @@ fn call_specialized_proc<'a>(
|
||||||
pub enum Pattern<'a> {
|
pub enum Pattern<'a> {
|
||||||
Identifier(Symbol),
|
Identifier(Symbol),
|
||||||
Underscore,
|
Underscore,
|
||||||
|
U128Literal(u128),
|
||||||
IntLiteral(i128, IntWidth),
|
IntLiteral(i128, IntWidth),
|
||||||
FloatLiteral(u64, FloatWidth),
|
FloatLiteral(u64, FloatWidth),
|
||||||
DecimalLiteral(RocDec),
|
DecimalLiteral(RocDec),
|
||||||
|
@ -7662,9 +7684,15 @@ fn from_can_pattern_help<'a>(
|
||||||
match can_pattern {
|
match can_pattern {
|
||||||
Underscore => Ok(Pattern::Underscore),
|
Underscore => Ok(Pattern::Underscore),
|
||||||
Identifier(symbol) => Ok(Pattern::Identifier(*symbol)),
|
Identifier(symbol) => Ok(Pattern::Identifier(*symbol)),
|
||||||
IntLiteral(var, _, int) => {
|
IntLiteral(_, precision_var, _, int, _bound) => {
|
||||||
match num_argument_to_int_or_float(env.subs, env.target_info, *var, false) {
|
match num_argument_to_int_or_float(env.subs, env.target_info, *precision_var, false) {
|
||||||
IntOrFloat::Int(precision) => Ok(Pattern::IntLiteral(*int as i128, precision)),
|
IntOrFloat::Int(precision) => {
|
||||||
|
let int = match *int {
|
||||||
|
IntValue::I128(n) => Pattern::IntLiteral(n, precision),
|
||||||
|
IntValue::U128(n) => Pattern::U128Literal(n),
|
||||||
|
};
|
||||||
|
Ok(int)
|
||||||
|
}
|
||||||
other => {
|
other => {
|
||||||
panic!(
|
panic!(
|
||||||
"Invalid precision for int pattern: {:?} has {:?}",
|
"Invalid precision for int pattern: {:?} has {:?}",
|
||||||
|
@ -7673,11 +7701,11 @@ fn from_can_pattern_help<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FloatLiteral(var, float_str, float) => {
|
FloatLiteral(_, precision_var, float_str, float, _bound) => {
|
||||||
// TODO: Can I reuse num_argument_to_int_or_float here if I pass in true?
|
// TODO: Can I reuse num_argument_to_int_or_float here if I pass in true?
|
||||||
match num_argument_to_int_or_float(env.subs, env.target_info, *var, true) {
|
match num_argument_to_int_or_float(env.subs, env.target_info, *precision_var, true) {
|
||||||
IntOrFloat::Int(_) => {
|
IntOrFloat::Int(_) => {
|
||||||
panic!("Invalid precision for float pattern {:?}", var)
|
panic!("Invalid precision for float pattern {:?}", precision_var)
|
||||||
}
|
}
|
||||||
IntOrFloat::Float(precision) => {
|
IntOrFloat::Float(precision) => {
|
||||||
Ok(Pattern::FloatLiteral(f64::to_bits(*float), precision))
|
Ok(Pattern::FloatLiteral(f64::to_bits(*float), precision))
|
||||||
|
@ -7704,10 +7732,20 @@ fn from_can_pattern_help<'a>(
|
||||||
// TODO preserve malformed problem information here?
|
// TODO preserve malformed problem information here?
|
||||||
Err(RuntimeError::UnsupportedPattern(*region))
|
Err(RuntimeError::UnsupportedPattern(*region))
|
||||||
}
|
}
|
||||||
NumLiteral(var, num_str, num) => {
|
NumLiteral(var, num_str, num, _bound) => {
|
||||||
match num_argument_to_int_or_float(env.subs, env.target_info, *var, false) {
|
match num_argument_to_int_or_float(env.subs, env.target_info, *var, false) {
|
||||||
IntOrFloat::Int(precision) => Ok(Pattern::IntLiteral(*num as i128, precision)),
|
IntOrFloat::Int(precision) => Ok(match num {
|
||||||
IntOrFloat::Float(precision) => Ok(Pattern::FloatLiteral(*num as u64, precision)),
|
IntValue::I128(num) => Pattern::IntLiteral(*num, precision),
|
||||||
|
IntValue::U128(num) => Pattern::U128Literal(*num),
|
||||||
|
}),
|
||||||
|
IntOrFloat::Float(precision) => {
|
||||||
|
// TODO: this may be lossy
|
||||||
|
let num = match *num {
|
||||||
|
IntValue::I128(n) => f64::to_bits(n as f64),
|
||||||
|
IntValue::U128(n) => f64::to_bits(n as f64),
|
||||||
|
};
|
||||||
|
Ok(Pattern::FloatLiteral(num, precision))
|
||||||
|
}
|
||||||
IntOrFloat::DecimalFloatType => {
|
IntOrFloat::DecimalFloatType => {
|
||||||
let dec = match RocDec::from_str(num_str) {
|
let dec = match RocDec::from_str(num_str) {
|
||||||
Some(d) => d,
|
Some(d) => d,
|
||||||
|
|
|
@ -514,7 +514,7 @@ fn numeric_negate_expression<'a, T>(
|
||||||
let start = state.pos();
|
let start = state.pos();
|
||||||
let region = Region::new(start, expr.region.end());
|
let region = Region::new(start, expr.region.end());
|
||||||
|
|
||||||
let new_expr = match &expr.value {
|
let new_expr = match expr.value {
|
||||||
Expr::Num(string) => {
|
Expr::Num(string) => {
|
||||||
let new_string =
|
let new_string =
|
||||||
unsafe { std::str::from_utf8_unchecked(&state.bytes()[..string.len() + 1]) };
|
unsafe { std::str::from_utf8_unchecked(&state.bytes()[..string.len() + 1]) };
|
||||||
|
@ -536,7 +536,7 @@ fn numeric_negate_expression<'a, T>(
|
||||||
Expr::NonBase10Int {
|
Expr::NonBase10Int {
|
||||||
is_negative: !is_negative,
|
is_negative: !is_negative,
|
||||||
string,
|
string,
|
||||||
base: *base,
|
base,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Expr::UnaryOp(arena.alloc(expr), Loc::at(loc_op.region, UnaryOp::Negate)),
|
_ => Expr::UnaryOp(arena.alloc(expr), Loc::at(loc_op.region, UnaryOp::Negate)),
|
||||||
|
@ -1450,8 +1450,8 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<
|
||||||
Ok(Pattern::RecordDestructure(patterns))
|
Ok(Pattern::RecordDestructure(patterns))
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::Float(string) => Ok(Pattern::FloatLiteral(string)),
|
&Expr::Float(string) => Ok(Pattern::FloatLiteral(string)),
|
||||||
Expr::Num(string) => Ok(Pattern::NumLiteral(string)),
|
&Expr::Num(string) => Ok(Pattern::NumLiteral(string)),
|
||||||
Expr::NonBase10Int {
|
Expr::NonBase10Int {
|
||||||
string,
|
string,
|
||||||
base,
|
base,
|
||||||
|
|
|
@ -8,6 +8,28 @@ use crate::string_literal;
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
use roc_region::all::Loc;
|
use roc_region::all::Loc;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum HeaderFor<'a> {
|
||||||
|
App {
|
||||||
|
to_platform: To<'a>,
|
||||||
|
},
|
||||||
|
Hosted {
|
||||||
|
generates: UppercaseIdent<'a>,
|
||||||
|
generates_with: &'a [Loc<ExposedName<'a>>],
|
||||||
|
},
|
||||||
|
PkgConfig {
|
||||||
|
/// usually `pf`
|
||||||
|
config_shorthand: &'a str,
|
||||||
|
/// the type scheme of the main function (required by the platform)
|
||||||
|
/// (currently unused)
|
||||||
|
#[allow(dead_code)]
|
||||||
|
platform_main_type: TypedIdent<'a>,
|
||||||
|
/// provided symbol to host (commonly `mainForHost`)
|
||||||
|
main_for_host: roc_module::symbol::Symbol,
|
||||||
|
},
|
||||||
|
Interface,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
pub enum Version<'a> {
|
pub enum Version<'a> {
|
||||||
Exact(&'a str),
|
Exact(&'a str),
|
||||||
|
@ -47,6 +69,15 @@ impl<'a> ModuleName<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ModuleNameEnum<'a> {
|
||||||
|
/// A filename
|
||||||
|
App(StrLiteral<'a>),
|
||||||
|
Interface(ModuleName<'a>),
|
||||||
|
Hosted(ModuleName<'a>),
|
||||||
|
PkgConfig,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
pub struct ExposedName<'a>(&'a str);
|
pub struct ExposedName<'a>(&'a str);
|
||||||
|
|
||||||
|
@ -162,7 +193,6 @@ pub struct PlatformHeader<'a> {
|
||||||
pub packages: Collection<'a, Loc<Spaced<'a, PackageEntry<'a>>>>,
|
pub packages: Collection<'a, Loc<Spaced<'a, PackageEntry<'a>>>>,
|
||||||
pub imports: Collection<'a, Loc<Spaced<'a, ImportsEntry<'a>>>>,
|
pub imports: Collection<'a, Loc<Spaced<'a, ImportsEntry<'a>>>>,
|
||||||
pub provides: Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>,
|
pub provides: Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>,
|
||||||
pub effects: Effects<'a>,
|
|
||||||
|
|
||||||
// Potential comments and newlines - these will typically all be empty.
|
// Potential comments and newlines - these will typically all be empty.
|
||||||
pub before_header: &'a [CommentOrNewline<'a>],
|
pub before_header: &'a [CommentOrNewline<'a>],
|
||||||
|
@ -179,17 +209,6 @@ pub struct PlatformHeader<'a> {
|
||||||
pub after_provides: &'a [CommentOrNewline<'a>],
|
pub after_provides: &'a [CommentOrNewline<'a>],
|
||||||
}
|
}
|
||||||
|
|
||||||
/// e.g. fx.Effects
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct Effects<'a> {
|
|
||||||
pub spaces_before_effects_keyword: &'a [CommentOrNewline<'a>],
|
|
||||||
pub spaces_after_effects_keyword: &'a [CommentOrNewline<'a>],
|
|
||||||
pub spaces_after_type_name: &'a [CommentOrNewline<'a>],
|
|
||||||
pub effect_shortname: &'a str,
|
|
||||||
pub effect_type_name: &'a str,
|
|
||||||
pub entries: Collection<'a, Loc<Spaced<'a, TypedIdent<'a>>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
pub enum ImportsEntry<'a> {
|
pub enum ImportsEntry<'a> {
|
||||||
/// e.g. `Task` or `Task.{ Task, after }`
|
/// e.g. `Task` or `Task.{ Task, after }`
|
||||||
|
|
|
@ -22,6 +22,12 @@ impl<'a> From<UppercaseIdent<'a>> for &'a str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a UppercaseIdent<'a>> for &'a str {
|
||||||
|
fn from(ident: &'a UppercaseIdent<'a>) -> Self {
|
||||||
|
ident.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The parser accepts all of these in any position where any one of them could
|
/// The parser accepts all of these in any position where any one of them could
|
||||||
/// appear. This way, canonicalization can give more helpful error messages like
|
/// appear. This way, canonicalization can give more helpful error messages like
|
||||||
/// "you can't redefine this tag!" if you wrote `Foo = ...` or
|
/// "you can't redefine this tag!" if you wrote `Foo = ...` or
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
use crate::ast::{Collection, CommentOrNewline, Def, Module, Spaced};
|
use crate::ast::{Collection, CommentOrNewline, Def, Module, Spaced};
|
||||||
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
|
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
|
||||||
use crate::header::{
|
use crate::header::{
|
||||||
package_entry, package_name, AppHeader, Effects, ExposedName, HostedHeader, ImportsEntry,
|
package_entry, package_name, AppHeader, ExposedName, HostedHeader, ImportsEntry,
|
||||||
InterfaceHeader, ModuleName, PackageEntry, PlatformHeader, PlatformRequires, To, TypedIdent,
|
InterfaceHeader, ModuleName, PackageEntry, PlatformHeader, PlatformRequires, To, TypedIdent,
|
||||||
};
|
};
|
||||||
use crate::ident::{
|
use crate::ident::{self, lowercase_ident, unqualified_ident, uppercase, UppercaseIdent};
|
||||||
self, lowercase_ident, unqualified_ident, uppercase, uppercase_ident, UppercaseIdent,
|
|
||||||
};
|
|
||||||
use crate::parser::Progress::{self, *};
|
use crate::parser::Progress::{self, *};
|
||||||
use crate::parser::{
|
use crate::parser::{
|
||||||
backtrackable, optional, specialize, specialize_region, word1, EEffects, EExposes, EGenerates,
|
backtrackable, optional, specialize, specialize_region, word1, EExposes, EGenerates,
|
||||||
EGeneratesWith, EHeader, EImports, EPackages, EProvides, ERequires, ETypedIdent, Parser,
|
EGeneratesWith, EHeader, EImports, EPackages, EProvides, ERequires, ETypedIdent, Parser,
|
||||||
SourceError, SyntaxError,
|
SourceError, SyntaxError,
|
||||||
};
|
};
|
||||||
|
@ -323,8 +321,6 @@ fn platform_header<'a>() -> impl Parser<'a, PlatformHeader<'a>, EHeader<'a>> {
|
||||||
let (_, ((before_provides, after_provides), (provides, _provides_type)), state) =
|
let (_, ((before_provides, after_provides), (provides, _provides_type)), state) =
|
||||||
specialize(EHeader::Provides, provides_without_to()).parse(arena, state)?;
|
specialize(EHeader::Provides, provides_without_to()).parse(arena, state)?;
|
||||||
|
|
||||||
let (_, effects, state) = specialize(EHeader::Effects, effects()).parse(arena, state)?;
|
|
||||||
|
|
||||||
let header = PlatformHeader {
|
let header = PlatformHeader {
|
||||||
name,
|
name,
|
||||||
requires,
|
requires,
|
||||||
|
@ -332,7 +328,6 @@ fn platform_header<'a>() -> impl Parser<'a, PlatformHeader<'a>, EHeader<'a>> {
|
||||||
packages: packages.entries,
|
packages: packages.entries,
|
||||||
imports,
|
imports,
|
||||||
provides,
|
provides,
|
||||||
effects,
|
|
||||||
before_header: &[] as &[_],
|
before_header: &[] as &[_],
|
||||||
after_platform_keyword,
|
after_platform_keyword,
|
||||||
before_requires,
|
before_requires,
|
||||||
|
@ -822,63 +817,6 @@ fn imports<'a>() -> impl Parser<
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn effects<'a>() -> impl Parser<'a, Effects<'a>, EEffects<'a>> {
|
|
||||||
move |arena, state| {
|
|
||||||
let min_indent = 1;
|
|
||||||
|
|
||||||
let (_, (spaces_before_effects_keyword, spaces_after_effects_keyword), state) =
|
|
||||||
spaces_around_keyword(
|
|
||||||
min_indent,
|
|
||||||
"effects",
|
|
||||||
EEffects::Effects,
|
|
||||||
EEffects::Space,
|
|
||||||
EEffects::IndentEffects,
|
|
||||||
EEffects::IndentListStart,
|
|
||||||
)
|
|
||||||
.parse(arena, state)?;
|
|
||||||
|
|
||||||
// e.g. `fx.`
|
|
||||||
let (_, type_shortname, state) = skip_second!(
|
|
||||||
specialize(|_, pos| EEffects::Shorthand(pos), lowercase_ident()),
|
|
||||||
word1(b'.', EEffects::ShorthandDot)
|
|
||||||
)
|
|
||||||
.parse(arena, state)?;
|
|
||||||
|
|
||||||
// the type name, e.g. Effects
|
|
||||||
let (_, (type_name, spaces_after_type_name), state) = and!(
|
|
||||||
specialize(|_, pos| EEffects::TypeName(pos), uppercase_ident()),
|
|
||||||
space0_e(min_indent, EEffects::Space, EEffects::IndentListStart)
|
|
||||||
)
|
|
||||||
.parse(arena, state)?;
|
|
||||||
let (_, entries, state) = collection_trailing_sep_e!(
|
|
||||||
word1(b'{', EEffects::ListStart),
|
|
||||||
specialize(EEffects::TypedIdent, loc!(typed_ident())),
|
|
||||||
word1(b',', EEffects::ListEnd),
|
|
||||||
word1(b'}', EEffects::ListEnd),
|
|
||||||
min_indent,
|
|
||||||
EEffects::Open,
|
|
||||||
EEffects::Space,
|
|
||||||
EEffects::IndentListEnd,
|
|
||||||
Spaced::SpaceBefore
|
|
||||||
)
|
|
||||||
.parse(arena, state)?;
|
|
||||||
|
|
||||||
Ok((
|
|
||||||
MadeProgress,
|
|
||||||
Effects {
|
|
||||||
spaces_before_effects_keyword,
|
|
||||||
spaces_after_effects_keyword,
|
|
||||||
spaces_after_type_name,
|
|
||||||
effect_shortname: type_shortname,
|
|
||||||
effect_type_name: type_name,
|
|
||||||
entries,
|
|
||||||
},
|
|
||||||
state,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn typed_ident<'a>() -> impl Parser<'a, Spaced<'a, TypedIdent<'a>>, ETypedIdent<'a>> {
|
fn typed_ident<'a>() -> impl Parser<'a, Spaced<'a, TypedIdent<'a>>, ETypedIdent<'a>> {
|
||||||
// e.g.
|
// e.g.
|
||||||
|
|
|
@ -71,7 +71,6 @@ pub enum EHeader<'a> {
|
||||||
Imports(EImports, Position),
|
Imports(EImports, Position),
|
||||||
Requires(ERequires<'a>, Position),
|
Requires(ERequires<'a>, Position),
|
||||||
Packages(EPackages<'a>, Position),
|
Packages(EPackages<'a>, Position),
|
||||||
Effects(EEffects<'a>, Position),
|
|
||||||
Generates(EGenerates, Position),
|
Generates(EGenerates, Position),
|
||||||
GeneratesWith(EGeneratesWith, Position),
|
GeneratesWith(EGeneratesWith, Position),
|
||||||
|
|
||||||
|
@ -167,22 +166,6 @@ pub enum EPackageEntry<'a> {
|
||||||
Space(BadInputError, Position),
|
Space(BadInputError, Position),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
||||||
pub enum EEffects<'a> {
|
|
||||||
Space(BadInputError, Position),
|
|
||||||
Effects(Position),
|
|
||||||
Open(Position),
|
|
||||||
IndentEffects(Position),
|
|
||||||
ListStart(Position),
|
|
||||||
ListEnd(Position),
|
|
||||||
IndentListStart(Position),
|
|
||||||
IndentListEnd(Position),
|
|
||||||
TypedIdent(ETypedIdent<'a>, Position),
|
|
||||||
ShorthandDot(Position),
|
|
||||||
Shorthand(Position),
|
|
||||||
TypeName(Position),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum EImports {
|
pub enum EImports {
|
||||||
Open(Position),
|
Open(Position),
|
||||||
|
|
|
@ -18,14 +18,6 @@ Platform {
|
||||||
packages: [],
|
packages: [],
|
||||||
imports: [],
|
imports: [],
|
||||||
provides: [],
|
provides: [],
|
||||||
effects: Effects {
|
|
||||||
spaces_before_effects_keyword: [],
|
|
||||||
spaces_after_effects_keyword: [],
|
|
||||||
spaces_after_type_name: [],
|
|
||||||
effect_shortname: "fx",
|
|
||||||
effect_type_name: "Blah",
|
|
||||||
entries: [],
|
|
||||||
},
|
|
||||||
before_header: [],
|
before_header: [],
|
||||||
after_platform_keyword: [],
|
after_platform_keyword: [],
|
||||||
before_requires: [],
|
before_requires: [],
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
platform "rtfeldman/blah" requires {} { main : {} } exposes [] packages {} imports [] provides [] effects fx.Blah {}
|
platform "rtfeldman/blah" requires {} { main : {} } exposes [] packages {} imports [] provides []
|
||||||
|
|
|
@ -43,105 +43,6 @@ Platform {
|
||||||
"mainForHost",
|
"mainForHost",
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
effects: Effects {
|
|
||||||
spaces_before_effects_keyword: [
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
spaces_after_effects_keyword: [],
|
|
||||||
spaces_after_type_name: [
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
effect_shortname: "fx",
|
|
||||||
effect_type_name: "Effect",
|
|
||||||
entries: [
|
|
||||||
@208-228 SpaceBefore(
|
|
||||||
TypedIdent {
|
|
||||||
ident: @208-215 "getLine",
|
|
||||||
spaces_before_colon: [],
|
|
||||||
ann: @218-228 Apply(
|
|
||||||
"",
|
|
||||||
"Effect",
|
|
||||||
[
|
|
||||||
@225-228 Apply(
|
|
||||||
"",
|
|
||||||
"Str",
|
|
||||||
[],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
},
|
|
||||||
[
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
@242-268 SpaceBefore(
|
|
||||||
TypedIdent {
|
|
||||||
ident: @242-249 "putLine",
|
|
||||||
spaces_before_colon: [],
|
|
||||||
ann: @259-268 Function(
|
|
||||||
[
|
|
||||||
@252-255 Apply(
|
|
||||||
"",
|
|
||||||
"Str",
|
|
||||||
[],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
@259-268 Apply(
|
|
||||||
"",
|
|
||||||
"Effect",
|
|
||||||
[
|
|
||||||
@266-268 Record {
|
|
||||||
fields: [],
|
|
||||||
ext: None,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
[
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
@282-318 SpaceBefore(
|
|
||||||
SpaceAfter(
|
|
||||||
TypedIdent {
|
|
||||||
ident: @282-294 "twoArguments",
|
|
||||||
spaces_before_colon: [],
|
|
||||||
ann: @309-318 Function(
|
|
||||||
[
|
|
||||||
@297-300 Apply(
|
|
||||||
"",
|
|
||||||
"Int",
|
|
||||||
[],
|
|
||||||
),
|
|
||||||
@302-305 Apply(
|
|
||||||
"",
|
|
||||||
"Int",
|
|
||||||
[],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
@309-318 Apply(
|
|
||||||
"",
|
|
||||||
"Effect",
|
|
||||||
[
|
|
||||||
@316-318 Record {
|
|
||||||
fields: [],
|
|
||||||
ext: None,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
[
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
[
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
before_header: [],
|
before_header: [],
|
||||||
after_platform_keyword: [],
|
after_platform_keyword: [],
|
||||||
before_requires: [
|
before_requires: [
|
||||||
|
|
|
@ -4,9 +4,3 @@ platform "examples/cli"
|
||||||
packages {}
|
packages {}
|
||||||
imports [ Task.{ Task } ]
|
imports [ Task.{ Task } ]
|
||||||
provides [ mainForHost ]
|
provides [ mainForHost ]
|
||||||
effects fx.Effect
|
|
||||||
{
|
|
||||||
getLine : Effect Str,
|
|
||||||
putLine : Str -> Effect {},
|
|
||||||
twoArguments : Int, Int -> Effect {}
|
|
||||||
}
|
|
||||||
|
|
|
@ -34,16 +34,6 @@ Platform {
|
||||||
"mainForHost",
|
"mainForHost",
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
effects: Effects {
|
|
||||||
spaces_before_effects_keyword: [
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
spaces_after_effects_keyword: [],
|
|
||||||
spaces_after_type_name: [],
|
|
||||||
effect_shortname: "fx",
|
|
||||||
effect_type_name: "Effect",
|
|
||||||
entries: [],
|
|
||||||
},
|
|
||||||
before_header: [],
|
before_header: [],
|
||||||
after_platform_keyword: [],
|
after_platform_keyword: [],
|
||||||
before_requires: [
|
before_requires: [
|
||||||
|
|
|
@ -4,4 +4,3 @@ platform "foo/barbaz"
|
||||||
packages { foo: "./foo" }
|
packages { foo: "./foo" }
|
||||||
imports []
|
imports []
|
||||||
provides [ mainForHost ]
|
provides [ mainForHost ]
|
||||||
effects fx.Effect {}
|
|
||||||
|
|
|
@ -0,0 +1,451 @@
|
||||||
|
Record(
|
||||||
|
Collection {
|
||||||
|
items: [
|
||||||
|
@4-15 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@4-6 "u8",
|
||||||
|
[],
|
||||||
|
@10-15 Num(
|
||||||
|
"123u8",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@19-31 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@19-22 "u16",
|
||||||
|
[],
|
||||||
|
@25-31 Num(
|
||||||
|
"123u16",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@35-47 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@35-38 "u32",
|
||||||
|
[],
|
||||||
|
@41-47 Num(
|
||||||
|
"123u32",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@51-63 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@51-54 "u64",
|
||||||
|
[],
|
||||||
|
@57-63 Num(
|
||||||
|
"123u64",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@67-80 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@67-71 "u128",
|
||||||
|
[],
|
||||||
|
@73-80 Num(
|
||||||
|
"123u128",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@84-95 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@84-86 "i8",
|
||||||
|
[],
|
||||||
|
@90-95 Num(
|
||||||
|
"123i8",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@99-111 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@99-102 "i16",
|
||||||
|
[],
|
||||||
|
@105-111 Num(
|
||||||
|
"123i16",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@115-127 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@115-118 "i32",
|
||||||
|
[],
|
||||||
|
@121-127 Num(
|
||||||
|
"123i32",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@131-143 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@131-134 "i64",
|
||||||
|
[],
|
||||||
|
@137-143 Num(
|
||||||
|
"123i64",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@147-160 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@147-151 "i128",
|
||||||
|
[],
|
||||||
|
@153-160 Num(
|
||||||
|
"123i128",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@164-176 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@164-167 "nat",
|
||||||
|
[],
|
||||||
|
@170-176 Num(
|
||||||
|
"123nat",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@180-192 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@180-183 "dec",
|
||||||
|
[],
|
||||||
|
@186-192 Num(
|
||||||
|
"123dec",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@196-211 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@196-201 "u8Neg",
|
||||||
|
[],
|
||||||
|
@205-211 Num(
|
||||||
|
"-123u8",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@215-231 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@215-221 "u16Neg",
|
||||||
|
[],
|
||||||
|
@224-231 Num(
|
||||||
|
"-123u16",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@235-251 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@235-241 "u32Neg",
|
||||||
|
[],
|
||||||
|
@244-251 Num(
|
||||||
|
"-123u32",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@255-271 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@255-261 "u64Neg",
|
||||||
|
[],
|
||||||
|
@264-271 Num(
|
||||||
|
"-123u64",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@275-292 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@275-282 "u128Neg",
|
||||||
|
[],
|
||||||
|
@284-292 Num(
|
||||||
|
"-123u128",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@296-311 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@296-301 "i8Neg",
|
||||||
|
[],
|
||||||
|
@305-311 Num(
|
||||||
|
"-123i8",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@315-331 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@315-321 "i16Neg",
|
||||||
|
[],
|
||||||
|
@324-331 Num(
|
||||||
|
"-123i16",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@335-351 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@335-341 "i32Neg",
|
||||||
|
[],
|
||||||
|
@344-351 Num(
|
||||||
|
"-123i32",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@355-371 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@355-361 "i64Neg",
|
||||||
|
[],
|
||||||
|
@364-371 Num(
|
||||||
|
"-123i64",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@375-392 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@375-382 "i128Neg",
|
||||||
|
[],
|
||||||
|
@384-392 Num(
|
||||||
|
"-123i128",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@396-412 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@396-402 "natNeg",
|
||||||
|
[],
|
||||||
|
@405-412 Num(
|
||||||
|
"-123nat",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@416-432 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@416-422 "decNeg",
|
||||||
|
[],
|
||||||
|
@425-432 Num(
|
||||||
|
"-123dec",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@436-452 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@436-441 "u8Bin",
|
||||||
|
[],
|
||||||
|
@445-452 NonBase10Int {
|
||||||
|
string: "101u8",
|
||||||
|
base: Binary,
|
||||||
|
is_negative: false,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@456-473 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@456-462 "u16Bin",
|
||||||
|
[],
|
||||||
|
@465-473 NonBase10Int {
|
||||||
|
string: "101u16",
|
||||||
|
base: Binary,
|
||||||
|
is_negative: false,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@477-494 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@477-483 "u32Bin",
|
||||||
|
[],
|
||||||
|
@486-494 NonBase10Int {
|
||||||
|
string: "101u32",
|
||||||
|
base: Binary,
|
||||||
|
is_negative: false,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@498-515 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@498-504 "u64Bin",
|
||||||
|
[],
|
||||||
|
@507-515 NonBase10Int {
|
||||||
|
string: "101u64",
|
||||||
|
base: Binary,
|
||||||
|
is_negative: false,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@519-537 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@519-526 "u128Bin",
|
||||||
|
[],
|
||||||
|
@528-537 NonBase10Int {
|
||||||
|
string: "101u128",
|
||||||
|
base: Binary,
|
||||||
|
is_negative: false,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@541-557 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@541-546 "i8Bin",
|
||||||
|
[],
|
||||||
|
@550-557 NonBase10Int {
|
||||||
|
string: "101i8",
|
||||||
|
base: Binary,
|
||||||
|
is_negative: false,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@561-578 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@561-567 "i16Bin",
|
||||||
|
[],
|
||||||
|
@570-578 NonBase10Int {
|
||||||
|
string: "101i16",
|
||||||
|
base: Binary,
|
||||||
|
is_negative: false,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@582-599 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@582-588 "i32Bin",
|
||||||
|
[],
|
||||||
|
@591-599 NonBase10Int {
|
||||||
|
string: "101i32",
|
||||||
|
base: Binary,
|
||||||
|
is_negative: false,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@603-620 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@603-609 "i64Bin",
|
||||||
|
[],
|
||||||
|
@612-620 NonBase10Int {
|
||||||
|
string: "101i64",
|
||||||
|
base: Binary,
|
||||||
|
is_negative: false,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@624-642 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@624-631 "i128Bin",
|
||||||
|
[],
|
||||||
|
@633-642 NonBase10Int {
|
||||||
|
string: "101i128",
|
||||||
|
base: Binary,
|
||||||
|
is_negative: false,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@646-663 SpaceBefore(
|
||||||
|
RequiredValue(
|
||||||
|
@646-652 "natBin",
|
||||||
|
[],
|
||||||
|
@655-663 NonBase10Int {
|
||||||
|
string: "101nat",
|
||||||
|
base: Binary,
|
||||||
|
is_negative: false,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
final_comments: [
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
)
|
|
@ -0,0 +1,37 @@
|
||||||
|
{
|
||||||
|
u8: 123u8,
|
||||||
|
u16: 123u16,
|
||||||
|
u32: 123u32,
|
||||||
|
u64: 123u64,
|
||||||
|
u128: 123u128,
|
||||||
|
i8: 123i8,
|
||||||
|
i16: 123i16,
|
||||||
|
i32: 123i32,
|
||||||
|
i64: 123i64,
|
||||||
|
i128: 123i128,
|
||||||
|
nat: 123nat,
|
||||||
|
dec: 123dec,
|
||||||
|
u8Neg: -123u8,
|
||||||
|
u16Neg: -123u16,
|
||||||
|
u32Neg: -123u32,
|
||||||
|
u64Neg: -123u64,
|
||||||
|
u128Neg: -123u128,
|
||||||
|
i8Neg: -123i8,
|
||||||
|
i16Neg: -123i16,
|
||||||
|
i32Neg: -123i32,
|
||||||
|
i64Neg: -123i64,
|
||||||
|
i128Neg: -123i128,
|
||||||
|
natNeg: -123nat,
|
||||||
|
decNeg: -123dec,
|
||||||
|
u8Bin: 0b101u8,
|
||||||
|
u16Bin: 0b101u16,
|
||||||
|
u32Bin: 0b101u32,
|
||||||
|
u64Bin: 0b101u64,
|
||||||
|
u128Bin: 0b101u128,
|
||||||
|
i8Bin: 0b101i8,
|
||||||
|
i16Bin: 0b101i16,
|
||||||
|
i32Bin: 0b101i32,
|
||||||
|
i64Bin: 0b101i64,
|
||||||
|
i128Bin: 0b101i128,
|
||||||
|
natBin: 0b101nat,
|
||||||
|
}
|
|
@ -41,16 +41,6 @@ Platform {
|
||||||
"mainForHost",
|
"mainForHost",
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
effects: Effects {
|
|
||||||
spaces_before_effects_keyword: [
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
spaces_after_effects_keyword: [],
|
|
||||||
spaces_after_type_name: [],
|
|
||||||
effect_shortname: "fx",
|
|
||||||
effect_type_name: "Effect",
|
|
||||||
entries: [],
|
|
||||||
},
|
|
||||||
before_header: [],
|
before_header: [],
|
||||||
after_platform_keyword: [],
|
after_platform_keyword: [],
|
||||||
before_requires: [
|
before_requires: [
|
||||||
|
|
|
@ -4,7 +4,6 @@ platform "test/types"
|
||||||
packages {}
|
packages {}
|
||||||
imports []
|
imports []
|
||||||
provides [ mainForHost ]
|
provides [ mainForHost ]
|
||||||
effects fx.Effect {}
|
|
||||||
|
|
||||||
mainForHost : App Flags Model
|
mainForHost : App Flags Model
|
||||||
mainForHost = main
|
mainForHost = main
|
||||||
|
|
|
@ -182,6 +182,7 @@ mod test_parse {
|
||||||
pass/newline_singleton_list.expr,
|
pass/newline_singleton_list.expr,
|
||||||
pass/nonempty_platform_header.header,
|
pass/nonempty_platform_header.header,
|
||||||
pass/not_docs.expr,
|
pass/not_docs.expr,
|
||||||
|
pass/number_literal_suffixes.expr,
|
||||||
pass/one_backpassing.expr,
|
pass/one_backpassing.expr,
|
||||||
pass/one_char_string.expr,
|
pass/one_char_string.expr,
|
||||||
pass/one_def.expr,
|
pass/one_def.expr,
|
||||||
|
|
|
@ -107,6 +107,18 @@ pub enum IntErrorKind {
|
||||||
Overflow,
|
Overflow,
|
||||||
/// Integer is too small to store in target integer type.
|
/// Integer is too small to store in target integer type.
|
||||||
Underflow,
|
Underflow,
|
||||||
|
/// This is an integer, but it has a float numeric suffix.
|
||||||
|
FloatSuffix,
|
||||||
|
/// The integer literal overflows the width of the suffix associated with it.
|
||||||
|
OverflowsSuffix {
|
||||||
|
suffix_type: &'static str,
|
||||||
|
max_value: u128,
|
||||||
|
},
|
||||||
|
/// The integer literal underflows the width of the suffix associated with it.
|
||||||
|
UnderflowsSuffix {
|
||||||
|
suffix_type: &'static str,
|
||||||
|
min_value: i128,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enum to store the various types of errors that can cause parsing a float to fail.
|
/// Enum to store the various types of errors that can cause parsing a float to fail.
|
||||||
|
@ -118,6 +130,8 @@ pub enum FloatErrorKind {
|
||||||
NegativeInfinity,
|
NegativeInfinity,
|
||||||
/// the literal is too large for f64
|
/// the literal is too large for f64
|
||||||
PositiveInfinity,
|
PositiveInfinity,
|
||||||
|
/// This is a float, but it has an integer numeric suffix.
|
||||||
|
IntSuffix,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
|
|
@ -5044,4 +5044,156 @@ mod solve_expr {
|
||||||
"[ Email Str ] -> Bool",
|
"[ Email Str ] -> Bool",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn numeric_literal_suffixes() {
|
||||||
|
infer_eq_without_problem(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
{
|
||||||
|
u8: 123u8,
|
||||||
|
u16: 123u16,
|
||||||
|
u32: 123u32,
|
||||||
|
u64: 123u64,
|
||||||
|
u128: 123u128,
|
||||||
|
|
||||||
|
i8: 123i8,
|
||||||
|
i16: 123i16,
|
||||||
|
i32: 123i32,
|
||||||
|
i64: 123i64,
|
||||||
|
i128: 123i128,
|
||||||
|
|
||||||
|
nat: 123nat,
|
||||||
|
|
||||||
|
bu8: 0b11u8,
|
||||||
|
bu16: 0b11u16,
|
||||||
|
bu32: 0b11u32,
|
||||||
|
bu64: 0b11u64,
|
||||||
|
bu128: 0b11u128,
|
||||||
|
|
||||||
|
bi8: 0b11i8,
|
||||||
|
bi16: 0b11i16,
|
||||||
|
bi32: 0b11i32,
|
||||||
|
bi64: 0b11i64,
|
||||||
|
bi128: 0b11i128,
|
||||||
|
|
||||||
|
bnat: 0b11nat,
|
||||||
|
|
||||||
|
dec: 123.0dec,
|
||||||
|
f32: 123.0f32,
|
||||||
|
f64: 123.0f64,
|
||||||
|
|
||||||
|
fdec: 123dec,
|
||||||
|
ff32: 123f32,
|
||||||
|
ff64: 123f64,
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
r#"{ bi128 : I128, bi16 : I16, bi32 : I32, bi64 : I64, bi8 : I8, bnat : Nat, bu128 : U128, bu16 : U16, bu32 : U32, bu64 : U64, bu8 : U8, dec : Dec, f32 : F32, f64 : F64, fdec : Dec, ff32 : F32, ff64 : F64, i128 : I128, i16 : I16, i32 : I32, i64 : I64, i8 : I8, nat : Nat, u128 : U128, u16 : U16, u32 : U32, u64 : U64, u8 : U8 }"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn numeric_literal_suffixes_in_pattern() {
|
||||||
|
infer_eq_without_problem(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
{
|
||||||
|
u8: (\n ->
|
||||||
|
when n is
|
||||||
|
123u8 -> n),
|
||||||
|
u16: (\n ->
|
||||||
|
when n is
|
||||||
|
123u16 -> n),
|
||||||
|
u32: (\n ->
|
||||||
|
when n is
|
||||||
|
123u32 -> n),
|
||||||
|
u64: (\n ->
|
||||||
|
when n is
|
||||||
|
123u64 -> n),
|
||||||
|
u128: (\n ->
|
||||||
|
when n is
|
||||||
|
123u128 -> n),
|
||||||
|
|
||||||
|
i8: (\n ->
|
||||||
|
when n is
|
||||||
|
123i8 -> n),
|
||||||
|
i16: (\n ->
|
||||||
|
when n is
|
||||||
|
123i16 -> n),
|
||||||
|
i32: (\n ->
|
||||||
|
when n is
|
||||||
|
123i32 -> n),
|
||||||
|
i64: (\n ->
|
||||||
|
when n is
|
||||||
|
123i64 -> n),
|
||||||
|
i128: (\n ->
|
||||||
|
when n is
|
||||||
|
123i128 -> n),
|
||||||
|
|
||||||
|
nat: (\n ->
|
||||||
|
when n is
|
||||||
|
123nat -> n),
|
||||||
|
|
||||||
|
bu8: (\n ->
|
||||||
|
when n is
|
||||||
|
0b11u8 -> n),
|
||||||
|
bu16: (\n ->
|
||||||
|
when n is
|
||||||
|
0b11u16 -> n),
|
||||||
|
bu32: (\n ->
|
||||||
|
when n is
|
||||||
|
0b11u32 -> n),
|
||||||
|
bu64: (\n ->
|
||||||
|
when n is
|
||||||
|
0b11u64 -> n),
|
||||||
|
bu128: (\n ->
|
||||||
|
when n is
|
||||||
|
0b11u128 -> n),
|
||||||
|
|
||||||
|
bi8: (\n ->
|
||||||
|
when n is
|
||||||
|
0b11i8 -> n),
|
||||||
|
bi16: (\n ->
|
||||||
|
when n is
|
||||||
|
0b11i16 -> n),
|
||||||
|
bi32: (\n ->
|
||||||
|
when n is
|
||||||
|
0b11i32 -> n),
|
||||||
|
bi64: (\n ->
|
||||||
|
when n is
|
||||||
|
0b11i64 -> n),
|
||||||
|
bi128: (\n ->
|
||||||
|
when n is
|
||||||
|
0b11i128 -> n),
|
||||||
|
|
||||||
|
bnat: (\n ->
|
||||||
|
when n is
|
||||||
|
0b11nat -> n),
|
||||||
|
|
||||||
|
dec: (\n ->
|
||||||
|
when n is
|
||||||
|
123.0dec -> n),
|
||||||
|
f32: (\n ->
|
||||||
|
when n is
|
||||||
|
123.0f32 -> n),
|
||||||
|
f64: (\n ->
|
||||||
|
when n is
|
||||||
|
123.0f64 -> n),
|
||||||
|
|
||||||
|
fdec: (\n ->
|
||||||
|
when n is
|
||||||
|
123dec -> n),
|
||||||
|
ff32: (\n ->
|
||||||
|
when n is
|
||||||
|
123f32 -> n),
|
||||||
|
ff64: (\n ->
|
||||||
|
when n is
|
||||||
|
123f64 -> n),
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
r#"{ bi128 : I128 -> I128, bi16 : I16 -> I16, bi32 : I32 -> I32, bi64 : I64 -> I64, bi8 : I8 -> I8, bnat : Nat -> Nat, bu128 : U128 -> U128, bu16 : U16 -> U16, bu32 : U32 -> U32, bu64 : U64 -> U64, bu8 : U8 -> U8, dec : Dec -> Dec, f32 : F32 -> F32, f64 : F64 -> F64, fdec : Dec -> Dec, ff32 : F32 -> F32, ff64 : F64 -> F64, i128 : I128 -> I128, i16 : I16 -> I16, i32 : I32 -> I32, i64 : I64 -> I64, i8 : I8 -> I8, nat : Nat -> Nat, u128 : U128 -> U128, u16 : U16 -> U16, u32 : U32 -> U32, u64 : U64 -> U64, u8 : U8 -> U8 }"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#[cfg(feature = "gen-llvm")]
|
#[cfg(feature = "gen-llvm")]
|
||||||
use crate::helpers::llvm::assert_evals_to;
|
use crate::helpers::llvm::assert_evals_to;
|
||||||
#[cfg(feature = "gen-llvm")]
|
#[cfg(feature = "gen-llvm")]
|
||||||
|
use crate::helpers::llvm::assert_expect_failed;
|
||||||
|
#[cfg(feature = "gen-llvm")]
|
||||||
use crate::helpers::llvm::assert_llvm_evals_to;
|
use crate::helpers::llvm::assert_llvm_evals_to;
|
||||||
#[cfg(feature = "gen-llvm")]
|
#[cfg(feature = "gen-llvm")]
|
||||||
use crate::helpers::llvm::assert_non_opt_evals_to;
|
use crate::helpers::llvm::assert_non_opt_evals_to;
|
||||||
|
@ -8,6 +10,8 @@ use crate::helpers::llvm::assert_non_opt_evals_to;
|
||||||
#[cfg(feature = "gen-dev")]
|
#[cfg(feature = "gen-dev")]
|
||||||
use crate::helpers::dev::assert_evals_to;
|
use crate::helpers::dev::assert_evals_to;
|
||||||
// #[cfg(feature = "gen-dev")]
|
// #[cfg(feature = "gen-dev")]
|
||||||
|
// use crate::helpers::dev::assert_expect_failed;
|
||||||
|
// #[cfg(feature = "gen-dev")]
|
||||||
// use crate::helpers::dev::assert_evals_to as assert_llvm_evals_to;
|
// use crate::helpers::dev::assert_evals_to as assert_llvm_evals_to;
|
||||||
// #[cfg(feature = "gen-dev")]
|
// #[cfg(feature = "gen-dev")]
|
||||||
// use crate::helpers::dev::assert_evals_to as assert_non_opt_evals_to;
|
// use crate::helpers::dev::assert_evals_to as assert_non_opt_evals_to;
|
||||||
|
@ -15,6 +19,8 @@ use crate::helpers::dev::assert_evals_to;
|
||||||
#[cfg(feature = "gen-wasm")]
|
#[cfg(feature = "gen-wasm")]
|
||||||
use crate::helpers::wasm::assert_evals_to;
|
use crate::helpers::wasm::assert_evals_to;
|
||||||
// #[cfg(feature = "gen-wasm")]
|
// #[cfg(feature = "gen-wasm")]
|
||||||
|
// use crate::helpers::dev::assert_expect_failed;
|
||||||
|
// #[cfg(feature = "gen-wasm")]
|
||||||
// use crate::helpers::wasm::assert_evals_to as assert_llvm_evals_to;
|
// use crate::helpers::wasm::assert_evals_to as assert_llvm_evals_to;
|
||||||
// #[cfg(feature = "gen-wasm")]
|
// #[cfg(feature = "gen-wasm")]
|
||||||
// use crate::helpers::wasm::assert_evals_to as assert_non_opt_evals_to;
|
// use crate::helpers::wasm::assert_evals_to as assert_non_opt_evals_to;
|
||||||
|
@ -2485,9 +2491,9 @@ fn call_invalid_layout() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
#[should_panic(expected = "An expectation failed!")]
|
#[should_panic(expected = "Failed with 1 failures. Failures: ")]
|
||||||
fn expect_fail() {
|
fn expect_fail() {
|
||||||
assert_evals_to!(
|
assert_expect_failed!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
expect 1 == 2
|
expect 1 == 2
|
||||||
|
|
|
@ -257,5 +257,25 @@ macro_rules! assert_evals_to {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused_macros)]
|
||||||
|
macro_rules! assert_expect_failed {
|
||||||
|
($src:expr, $expected:expr, $ty:ty, $failures:expr) => {{
|
||||||
|
use bumpalo::Bump;
|
||||||
|
use roc_gen_dev::run_jit_function_raw;
|
||||||
|
let stdlib = roc_builtins::std::standard_stdlib();
|
||||||
|
|
||||||
|
let arena = Bump::new();
|
||||||
|
let (main_fn_name, errors, lib) =
|
||||||
|
$crate::helpers::dev::helper(&arena, $src, stdlib, true, true);
|
||||||
|
|
||||||
|
let transform = |success| {
|
||||||
|
let expected = $expected;
|
||||||
|
assert_eq!(&success, &expected);
|
||||||
|
};
|
||||||
|
run_jit_function_raw!(lib, main_fn_name, $ty, transform, errors);
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
pub(crate) use assert_evals_to;
|
pub(crate) use assert_evals_to;
|
||||||
|
pub(crate) use assert_expect_failed;
|
||||||
|
|
|
@ -192,8 +192,12 @@ fn create_llvm_module<'a>(
|
||||||
for function in FunctionIterator::from_module(module) {
|
for function in FunctionIterator::from_module(module) {
|
||||||
let name = function.get_name().to_str().unwrap();
|
let name = function.get_name().to_str().unwrap();
|
||||||
if name.starts_with("roc_builtins") {
|
if name.starts_with("roc_builtins") {
|
||||||
|
if name.starts_with("roc_builtins.expect") {
|
||||||
|
function.set_linkage(Linkage::External);
|
||||||
|
} else {
|
||||||
function.set_linkage(Linkage::Internal);
|
function.set_linkage(Linkage::Internal);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if name.starts_with("roc_builtins.dict") {
|
if name.starts_with("roc_builtins.dict") {
|
||||||
function.add_attribute(AttributeLoc::Function, attr);
|
function.add_attribute(AttributeLoc::Function, attr);
|
||||||
|
@ -601,6 +605,46 @@ macro_rules! assert_evals_to {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused_macros)]
|
||||||
|
macro_rules! assert_expect_failed {
|
||||||
|
($src:expr, $expected:expr, $ty:ty) => {
|
||||||
|
use bumpalo::Bump;
|
||||||
|
use inkwell::context::Context;
|
||||||
|
use roc_gen_llvm::run_jit_function;
|
||||||
|
|
||||||
|
let arena = Bump::new();
|
||||||
|
let context = Context::create();
|
||||||
|
|
||||||
|
// NOTE the stdlib must be in the arena; just taking a reference will segfault
|
||||||
|
let stdlib = arena.alloc(roc_builtins::std::standard_stdlib());
|
||||||
|
|
||||||
|
let is_gen_test = true;
|
||||||
|
let (main_fn_name, errors, lib) =
|
||||||
|
$crate::helpers::llvm::helper(&arena, $src, stdlib, is_gen_test, false, &context);
|
||||||
|
|
||||||
|
let transform = |success| {
|
||||||
|
let expected = $expected;
|
||||||
|
assert_eq!(&success, &expected, "LLVM test failed");
|
||||||
|
};
|
||||||
|
|
||||||
|
run_jit_function!(lib, main_fn_name, $ty, transform, errors)
|
||||||
|
};
|
||||||
|
|
||||||
|
($src:expr, $expected:expr, $ty:ty) => {
|
||||||
|
$crate::helpers::llvm::assert_llvm_evals_to!(
|
||||||
|
$src,
|
||||||
|
$expected,
|
||||||
|
$ty,
|
||||||
|
$crate::helpers::llvm::identity,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
($src:expr, $expected:expr, $ty:ty, $transform:expr) => {
|
||||||
|
$crate::helpers::llvm::assert_llvm_evals_to!($src, $expected, $ty, $transform, false);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! expect_runtime_error_panic {
|
macro_rules! expect_runtime_error_panic {
|
||||||
($src:expr) => {{
|
($src:expr) => {{
|
||||||
#[cfg(feature = "wasm-cli-run")]
|
#[cfg(feature = "wasm-cli-run")]
|
||||||
|
@ -651,6 +695,8 @@ macro_rules! assert_non_opt_evals_to {
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
pub(crate) use assert_evals_to;
|
pub(crate) use assert_evals_to;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
|
pub(crate) use assert_expect_failed;
|
||||||
|
#[allow(unused_imports)]
|
||||||
pub(crate) use assert_llvm_evals_to;
|
pub(crate) use assert_llvm_evals_to;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
pub(crate) use assert_non_opt_evals_to;
|
pub(crate) use assert_non_opt_evals_to;
|
||||||
|
|
|
@ -24,6 +24,11 @@ pub unsafe fn roc_alloc(size: usize, _alignment: u32) -> *mut c_void {
|
||||||
libc::malloc(size)
|
libc::malloc(size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn roc_memcpy(dest: *mut c_void, src: *const c_void, bytes: usize) -> *mut c_void {
|
||||||
|
libc::memcpy(dest, src, bytes)
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe fn roc_realloc(
|
pub unsafe fn roc_realloc(
|
||||||
c_ptr: *mut c_void,
|
c_ptr: *mut c_void,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::subs::{Content, FlatType, GetSubsSlice, Subs, UnionTags, Variable};
|
use crate::subs::{AliasVariables, Content, FlatType, GetSubsSlice, Subs, UnionTags, Variable};
|
||||||
use crate::types::{name_type_var, RecordField};
|
use crate::types::{name_type_var, RecordField};
|
||||||
use roc_collections::all::{MutMap, MutSet};
|
use roc_collections::all::{MutMap, MutSet};
|
||||||
use roc_module::ident::{Lowercase, TagName};
|
use roc_module::ident::{Lowercase, TagName};
|
||||||
|
@ -289,6 +289,17 @@ pub fn content_to_string(
|
||||||
buf
|
buf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_single_arg<'a>(subs: &'a Subs, args: &'a AliasVariables) -> &'a Content {
|
||||||
|
debug_assert_eq!(args.len(), 1);
|
||||||
|
|
||||||
|
let arg_var_index = args
|
||||||
|
.into_iter()
|
||||||
|
.next()
|
||||||
|
.expect("Num was not applied to a type argument!");
|
||||||
|
let arg_var = subs[arg_var_index];
|
||||||
|
subs.get_content_without_compacting(arg_var)
|
||||||
|
}
|
||||||
|
|
||||||
fn write_content(env: &Env, content: &Content, subs: &Subs, buf: &mut String, parens: Parens) {
|
fn write_content(env: &Env, content: &Content, subs: &Subs, buf: &mut String, parens: Parens) {
|
||||||
use crate::subs::Content::*;
|
use crate::subs::Content::*;
|
||||||
|
|
||||||
|
@ -306,18 +317,19 @@ fn write_content(env: &Env, content: &Content, subs: &Subs, buf: &mut String, pa
|
||||||
|
|
||||||
match *symbol {
|
match *symbol {
|
||||||
Symbol::NUM_NUM => {
|
Symbol::NUM_NUM => {
|
||||||
debug_assert_eq!(args.len(), 1);
|
let content = get_single_arg(subs, args);
|
||||||
|
match *content {
|
||||||
let arg_var_index = args
|
Alias(nested, args, _actual) => match nested {
|
||||||
.into_iter()
|
Symbol::NUM_INTEGER => {
|
||||||
.next()
|
write_integer(
|
||||||
.expect("Num was not applied to a type argument!");
|
env,
|
||||||
let arg_var = subs[arg_var_index];
|
get_single_arg(subs, &args),
|
||||||
let content = subs.get_content_without_compacting(arg_var);
|
subs,
|
||||||
|
buf,
|
||||||
match &content {
|
parens,
|
||||||
Alias(nested, _, _) => match *nested {
|
false,
|
||||||
Symbol::NUM_INTEGER => buf.push_str("I64"),
|
);
|
||||||
|
}
|
||||||
Symbol::NUM_FLOATINGPOINT => buf.push_str("F64"),
|
Symbol::NUM_FLOATINGPOINT => buf.push_str("F64"),
|
||||||
|
|
||||||
_ => write_parens!(write_parens, buf, {
|
_ => write_parens!(write_parens, buf, {
|
||||||
|
@ -333,6 +345,33 @@ fn write_content(env: &Env, content: &Content, subs: &Subs, buf: &mut String, pa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Symbol::NUM_INT => {
|
||||||
|
let content = get_single_arg(subs, args);
|
||||||
|
|
||||||
|
write_integer(env, content, subs, buf, parens, write_parens)
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol::NUM_FLOAT => {
|
||||||
|
debug_assert_eq!(args.len(), 1);
|
||||||
|
|
||||||
|
let arg_var_index = args
|
||||||
|
.into_iter()
|
||||||
|
.next()
|
||||||
|
.expect("Num was not applied to a type argument!");
|
||||||
|
let arg_var = subs[arg_var_index];
|
||||||
|
let content = subs.get_content_without_compacting(arg_var);
|
||||||
|
|
||||||
|
match content {
|
||||||
|
Alias(Symbol::NUM_BINARY32, _, _) => buf.push_str("F32"),
|
||||||
|
Alias(Symbol::NUM_BINARY64, _, _) => buf.push_str("F64"),
|
||||||
|
Alias(Symbol::NUM_DECIMAL, _, _) => buf.push_str("Dec"),
|
||||||
|
_ => write_parens!(write_parens, buf, {
|
||||||
|
buf.push_str("Float ");
|
||||||
|
write_content(env, content, subs, buf, parens);
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_ => write_parens!(write_parens, buf, {
|
_ => write_parens!(write_parens, buf, {
|
||||||
write_symbol(env, *symbol, buf);
|
write_symbol(env, *symbol, buf);
|
||||||
|
|
||||||
|
@ -362,6 +401,51 @@ fn write_content(env: &Env, content: &Content, subs: &Subs, buf: &mut String, pa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_integer(
|
||||||
|
env: &Env,
|
||||||
|
content: &Content,
|
||||||
|
subs: &Subs,
|
||||||
|
buf: &mut String,
|
||||||
|
parens: Parens,
|
||||||
|
write_parens: bool,
|
||||||
|
) {
|
||||||
|
use crate::subs::Content::*;
|
||||||
|
|
||||||
|
macro_rules! derive_num_writes {
|
||||||
|
($($lit:expr, $tag:path)*) => {
|
||||||
|
write_parens!(
|
||||||
|
write_parens,
|
||||||
|
buf,
|
||||||
|
match content {
|
||||||
|
$(
|
||||||
|
&Alias($tag, _, _) => {
|
||||||
|
buf.push_str($lit)
|
||||||
|
},
|
||||||
|
)*
|
||||||
|
actual => {
|
||||||
|
buf.push_str("Int ");
|
||||||
|
write_content(env, actual, subs, buf, parens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
derive_num_writes! {
|
||||||
|
"U8", Symbol::NUM_UNSIGNED8
|
||||||
|
"U16", Symbol::NUM_UNSIGNED16
|
||||||
|
"U32", Symbol::NUM_UNSIGNED32
|
||||||
|
"U64", Symbol::NUM_UNSIGNED64
|
||||||
|
"U128", Symbol::NUM_UNSIGNED128
|
||||||
|
"I8", Symbol::NUM_SIGNED8
|
||||||
|
"I16", Symbol::NUM_SIGNED16
|
||||||
|
"I32", Symbol::NUM_SIGNED32
|
||||||
|
"I64", Symbol::NUM_SIGNED64
|
||||||
|
"I128", Symbol::NUM_SIGNED128
|
||||||
|
"Nat", Symbol::NUM_NATURAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum ExtContent<'a> {
|
enum ExtContent<'a> {
|
||||||
Empty,
|
Empty,
|
||||||
Content(Variable, &'a Content),
|
Content(Variable, &'a Content),
|
||||||
|
|
|
@ -1626,6 +1626,25 @@ pub enum FlatType {
|
||||||
EmptyTagUnion,
|
EmptyTagUnion,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FlatType {
|
||||||
|
pub fn get_singleton_tag_union<'a>(&'a self, subs: &'a Subs) -> Option<&'a TagName> {
|
||||||
|
match self {
|
||||||
|
Self::TagUnion(tags, ext) => {
|
||||||
|
let tags = tags.unsorted_tags_and_ext(subs, *ext).0.tags;
|
||||||
|
if tags.len() != 1 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let (tag_name, vars) = tags[0];
|
||||||
|
if !vars.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(tag_name)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
|
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
|
||||||
pub enum Builtin {
|
pub enum Builtin {
|
||||||
Str,
|
Str,
|
||||||
|
|
|
@ -1186,6 +1186,7 @@ pub enum Reason {
|
||||||
RecordUpdateValue(Lowercase),
|
RecordUpdateValue(Lowercase),
|
||||||
RecordUpdateKeys(Symbol, SendMap<Lowercase, Region>),
|
RecordUpdateKeys(Symbol, SendMap<Lowercase, Region>),
|
||||||
RecordDefaultField(Lowercase),
|
RecordDefaultField(Lowercase),
|
||||||
|
NumericLiteralSuffix,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Clone)]
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
|
|
|
@ -33,7 +33,6 @@ platform "test-platform"
|
||||||
packages {}
|
packages {}
|
||||||
imports []
|
imports []
|
||||||
provides [ mainForHost ]
|
provides [ mainForHost ]
|
||||||
effects fx.Effect {}
|
|
||||||
|
|
||||||
mainForHost : Str
|
mainForHost : Str
|
||||||
mainForHost = main
|
mainForHost = main
|
||||||
|
|
10
examples/benchmarks/platform/Effect.roc
Normal file
10
examples/benchmarks/platform/Effect.roc
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
hosted Effect
|
||||||
|
exposes [ Effect, after, map, always, forever, loop, putLine, putInt, getInt ]
|
||||||
|
imports []
|
||||||
|
generates Effect with [ after, map, always, forever, loop ]
|
||||||
|
|
||||||
|
putLine : Str -> Effect {}
|
||||||
|
|
||||||
|
putInt : I64 -> Effect {}
|
||||||
|
|
||||||
|
getInt : Effect { value : I64, errorCode : [ A, B ], isError : Bool }
|
|
@ -4,12 +4,6 @@ platform "folkertdev/foo"
|
||||||
packages {}
|
packages {}
|
||||||
imports [ Task.{ Task } ]
|
imports [ Task.{ Task } ]
|
||||||
provides [ mainForHost ]
|
provides [ mainForHost ]
|
||||||
effects fx.Effect
|
|
||||||
{
|
|
||||||
putLine : Str -> Effect {},
|
|
||||||
putInt : I64 -> Effect {},
|
|
||||||
getInt : Effect { value : I64, errorCode : [ A, B ], isError : Bool },
|
|
||||||
}
|
|
||||||
|
|
||||||
mainForHost : Task {} [] as Fx
|
mainForHost : Task {} [] as Fx
|
||||||
mainForHost = main
|
mainForHost = main
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
interface Task
|
interface Task
|
||||||
exposes [ Task, succeed, fail, after, map, putLine, putInt, getInt, forever, loop ]
|
exposes [ Task, succeed, fail, after, map, putLine, putInt, getInt, forever, loop ]
|
||||||
imports [ fx.Effect ]
|
imports [ pf.Effect ]
|
||||||
|
|
||||||
Task ok err : Effect.Effect (Result ok err)
|
Task ok err : Effect.Effect (Result ok err)
|
||||||
|
|
||||||
|
|
8
examples/cli/platform/Effect.roc
Normal file
8
examples/cli/platform/Effect.roc
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
hosted Effect
|
||||||
|
exposes [ Effect, after, map, always, forever, loop, putLine, getLine ]
|
||||||
|
imports []
|
||||||
|
generates Effect with [ after, map, always, forever, loop ]
|
||||||
|
|
||||||
|
putLine : Str -> Effect {}
|
||||||
|
|
||||||
|
getLine : Effect Str
|
|
@ -4,7 +4,6 @@ platform "examples/cli"
|
||||||
packages {}
|
packages {}
|
||||||
imports [ Task.{ Task } ]
|
imports [ Task.{ Task } ]
|
||||||
provides [ mainForHost ]
|
provides [ mainForHost ]
|
||||||
effects fx.Effect { putLine : Str -> Effect {}, getLine : Effect Str }
|
|
||||||
|
|
||||||
mainForHost : Task {} [] as Fx
|
mainForHost : Task {} [] as Fx
|
||||||
mainForHost = main
|
mainForHost = main
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
interface Stdin
|
interface Stdin
|
||||||
exposes [ line ]
|
exposes [ line ]
|
||||||
imports [ fx.Effect, Task ]
|
imports [ pf.Effect, Task ]
|
||||||
|
|
||||||
line : Task.Task Str *
|
line : Task.Task Str *
|
||||||
line = Effect.after Effect.getLine Task.succeed# TODO FIXME Effect.getLine should suffice
|
line = Effect.after Effect.getLine Task.succeed# TODO FIXME Effect.getLine should suffice
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
interface Stdout
|
interface Stdout
|
||||||
exposes [ line ]
|
exposes [ line ]
|
||||||
imports [ fx.Effect, Task.{ Task } ]
|
imports [ pf.Effect, Task.{ Task } ]
|
||||||
|
|
||||||
# line : Str -> Task.Task {} *
|
# line : Str -> Task.Task {} *
|
||||||
# line = \line -> Effect.map (Effect.putLine line) (\_ -> Ok {})
|
# line = \line -> Effect.map (Effect.putLine line) (\_ -> Ok {})
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
interface Task
|
interface Task
|
||||||
exposes [ Task, succeed, fail, await, map, onFail, attempt, forever, loop ]
|
exposes [ Task, succeed, fail, await, map, onFail, attempt, forever, loop ]
|
||||||
imports [ fx.Effect ]
|
imports [ pf.Effect ]
|
||||||
|
|
||||||
Task ok err : Effect.Effect (Result ok err)
|
Task ok err : Effect.Effect (Result ok err)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
app "effect-example"
|
app "effect-example"
|
||||||
packages { pf: "thing/platform-dir" }
|
packages { pf: "thing/platform-dir" }
|
||||||
imports [ fx.Effect ]
|
imports [ pf.Effect ]
|
||||||
provides [ main ] to pf
|
provides [ main ] to pf
|
||||||
|
|
||||||
main : Effect.Effect {}
|
main : Effect.Effect {}
|
||||||
|
|
8
examples/effect/thing/platform-dir/Effect.roc
Normal file
8
examples/effect/thing/platform-dir/Effect.roc
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
hosted Effect
|
||||||
|
exposes [ Effect, after, map, always, forever, putLine, getLine ]
|
||||||
|
imports []
|
||||||
|
generates Effect with [ after, map, always, forever ]
|
||||||
|
|
||||||
|
putLine : Str -> Effect {}
|
||||||
|
|
||||||
|
getLine : Effect Str
|
|
@ -2,13 +2,8 @@ platform "roc-examples/cli"
|
||||||
requires {} { main : Effect {} }
|
requires {} { main : Effect {} }
|
||||||
exposes []
|
exposes []
|
||||||
packages {}
|
packages {}
|
||||||
imports [ fx.Effect ]
|
imports [ pf.Effect ]
|
||||||
provides [ mainForHost ]
|
provides [ mainForHost ]
|
||||||
effects fx.Effect
|
|
||||||
{
|
|
||||||
putLine : Str -> Effect {},
|
|
||||||
getLine : Effect Str,
|
|
||||||
}
|
|
||||||
|
|
||||||
mainForHost : Effect.Effect {} as Fx
|
mainForHost : Effect.Effect {} as Fx
|
||||||
mainForHost = main
|
mainForHost = main
|
||||||
|
|
22
examples/false-interpreter/platform/Effect.roc
Normal file
22
examples/false-interpreter/platform/Effect.roc
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
hosted Effect
|
||||||
|
exposes [ Effect, after, map, always, forever, loop, openFile, closeFile, withFileOpen, getFileLine, getFileBytes, putLine, putRaw, getLine, getChar ]
|
||||||
|
imports []
|
||||||
|
generates Effect with [ after, map, always, forever, loop ]
|
||||||
|
|
||||||
|
openFile : Str -> Effect U64
|
||||||
|
|
||||||
|
closeFile : U64 -> Effect {}
|
||||||
|
|
||||||
|
withFileOpen : Str, (U64 -> Effect (Result ok err)) -> Effect {}
|
||||||
|
|
||||||
|
getFileLine : U64 -> Effect Str
|
||||||
|
|
||||||
|
getFileBytes : U64 -> Effect (List U8)
|
||||||
|
|
||||||
|
putLine : Str -> Effect {}
|
||||||
|
|
||||||
|
putRaw : Str -> Effect {}
|
||||||
|
|
||||||
|
getLine : Effect Str
|
||||||
|
|
||||||
|
getChar : Effect U8
|
|
@ -1,6 +1,6 @@
|
||||||
interface File
|
interface File
|
||||||
exposes [ line, Handle, withOpen, chunk ]
|
exposes [ line, Handle, withOpen, chunk ]
|
||||||
imports [ fx.Effect, Task.{ Task } ]
|
imports [ pf.Effect, Task.{ Task } ]
|
||||||
|
|
||||||
Handle : [ @Handle U64 ]
|
Handle : [ @Handle U64 ]
|
||||||
|
|
||||||
|
|
|
@ -4,19 +4,6 @@ platform "examples/cli"
|
||||||
packages {}
|
packages {}
|
||||||
imports [ Task.{ Task } ]
|
imports [ Task.{ Task } ]
|
||||||
provides [ mainForHost ]
|
provides [ mainForHost ]
|
||||||
effects fx.Effect
|
|
||||||
{
|
|
||||||
openFile : Str -> Effect U64,
|
|
||||||
closeFile : U64 -> Effect {},
|
|
||||||
withFileOpen : Str, (U64 -> Effect (Result ok err)) -> Effect {},
|
|
||||||
getFileLine : U64 -> Effect Str,
|
|
||||||
getFileBytes : U64 -> Effect (List U8),
|
|
||||||
putLine : Str -> Effect {},
|
|
||||||
putRaw : Str -> Effect {},
|
|
||||||
# Is there a limit to the number of effect, uncomment the next line and it crashes
|
|
||||||
# getLine : Effect Str,
|
|
||||||
getChar : Effect U8,
|
|
||||||
}
|
|
||||||
|
|
||||||
mainForHost : Str -> Task {} [] as Fx
|
mainForHost : Str -> Task {} [] as Fx
|
||||||
mainForHost = \file -> main file
|
mainForHost = \file -> main file
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
interface Stdin
|
interface Stdin
|
||||||
exposes [ char ]
|
exposes [ char ]
|
||||||
imports [ fx.Effect, Task ]
|
imports [ pf.Effect, Task ]
|
||||||
|
|
||||||
# line : Task.Task Str *
|
# line : Task.Task Str *
|
||||||
# line = Effect.after Effect.getLine Task.succeed # TODO FIXME Effect.getLine should suffice
|
# line = Effect.after Effect.getLine Task.succeed # TODO FIXME Effect.getLine should suffice
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
interface Stdout
|
interface Stdout
|
||||||
exposes [ line, raw ]
|
exposes [ line, raw ]
|
||||||
imports [ fx.Effect, Task.{ Task } ]
|
imports [ pf.Effect, Task.{ Task } ]
|
||||||
|
|
||||||
line : Str -> Task {} *
|
line : Str -> Task {} *
|
||||||
line = \str -> Effect.map (Effect.putLine str) (\_ -> Ok {})
|
line = \str -> Effect.map (Effect.putLine str) (\_ -> Ok {})
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
interface Task
|
interface Task
|
||||||
exposes [ Task, succeed, fail, await, map, onFail, attempt, fromResult, loop ]
|
exposes [ Task, succeed, fail, await, map, onFail, attempt, fromResult, loop ]
|
||||||
imports [ fx.Effect ]
|
imports [ pf.Effect ]
|
||||||
|
|
||||||
Task ok err : Effect.Effect (Result ok err)
|
Task ok err : Effect.Effect (Result ok err)
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ platform "examples/add"
|
||||||
packages {}
|
packages {}
|
||||||
imports []
|
imports []
|
||||||
provides [ mainForHost ]
|
provides [ mainForHost ]
|
||||||
effects fx.Effect {}
|
|
||||||
|
|
||||||
mainForHost : I64 -> I64
|
mainForHost : I64 -> I64
|
||||||
mainForHost = \a -> main a
|
mainForHost = \a -> main a
|
||||||
|
|
|
@ -4,7 +4,6 @@ platform "examples/hello-world"
|
||||||
packages {}
|
packages {}
|
||||||
imports []
|
imports []
|
||||||
provides [ mainForHost ]
|
provides [ mainForHost ]
|
||||||
effects fx.Effect {}
|
|
||||||
|
|
||||||
mainForHost : Str
|
mainForHost : Str
|
||||||
mainForHost = main
|
mainForHost = main
|
||||||
|
|
|
@ -4,7 +4,6 @@ platform "examples/hello-swift"
|
||||||
packages {}
|
packages {}
|
||||||
imports []
|
imports []
|
||||||
provides [ mainForHost ]
|
provides [ mainForHost ]
|
||||||
effects fx.Effect {}
|
|
||||||
|
|
||||||
mainForHost : Str
|
mainForHost : Str
|
||||||
mainForHost = main
|
mainForHost = main
|
||||||
|
|
|
@ -4,7 +4,6 @@ platform "examples/hello-world"
|
||||||
packages {}
|
packages {}
|
||||||
imports []
|
imports []
|
||||||
provides [ mainForHost ]
|
provides [ mainForHost ]
|
||||||
effects fx.Effect {}
|
|
||||||
|
|
||||||
mainForHost : Str
|
mainForHost : Str
|
||||||
mainForHost = main
|
mainForHost = main
|
||||||
|
|
|
@ -4,7 +4,6 @@ platform "examples/hello-world"
|
||||||
packages {}
|
packages {}
|
||||||
imports []
|
imports []
|
||||||
provides [ mainForHost ]
|
provides [ mainForHost ]
|
||||||
effects fx.Effect {}
|
|
||||||
|
|
||||||
mainForHost : Str
|
mainForHost : Str
|
||||||
mainForHost = main
|
mainForHost = main
|
||||||
|
|
|
@ -4,7 +4,6 @@ platform "examples/hello-world"
|
||||||
packages {}
|
packages {}
|
||||||
imports []
|
imports []
|
||||||
provides [ mainForHost ]
|
provides [ mainForHost ]
|
||||||
effects fx.Effect {}
|
|
||||||
|
|
||||||
mainForHost : Str
|
mainForHost : Str
|
||||||
mainForHost = main
|
mainForHost = main
|
||||||
|
|
|
@ -4,7 +4,6 @@ platform "examples/quicksort"
|
||||||
packages {}
|
packages {}
|
||||||
imports []
|
imports []
|
||||||
provides [ mainForHost ]
|
provides [ mainForHost ]
|
||||||
effects fx.Effect {}
|
|
||||||
|
|
||||||
mainForHost : List I64 -> List I64
|
mainForHost : List I64 -> List I64
|
||||||
mainForHost = \list -> quicksort list
|
mainForHost = \list -> quicksort list
|
||||||
|
|
|
@ -4,7 +4,6 @@ platform "folkertdev/foo"
|
||||||
packages {}
|
packages {}
|
||||||
imports []
|
imports []
|
||||||
provides [ mainForHost ]
|
provides [ mainForHost ]
|
||||||
effects fx.Effect {}
|
|
||||||
|
|
||||||
mainForHost : { init : ({} -> Model) as Init, update : (Model, Str -> Model) as Update, view : (Model -> Str) as View }
|
mainForHost : { init : ({} -> Model) as Init, update : (Model, Str -> Model) as Update, view : (Model -> Str) as View }
|
||||||
mainForHost = main
|
mainForHost = main
|
||||||
|
|
|
@ -8,18 +8,22 @@ version = "0.1.0"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bumpalo = {version = "3.8.0", features = ["collections"]}
|
bumpalo = {version = "3.8.0", features = ["collections"]}
|
||||||
const_format = "0.2.22"
|
const_format = "0.2.22"
|
||||||
|
inkwell = {path = "../vendor/inkwell"}
|
||||||
|
libloading = {version = "0.7.1"}
|
||||||
rustyline = {git = "https://github.com/rtfeldman/rustyline", tag = "v9.1.1"}
|
rustyline = {git = "https://github.com/rtfeldman/rustyline", tag = "v9.1.1"}
|
||||||
rustyline-derive = {git = "https://github.com/rtfeldman/rustyline", tag = "v9.1.1"}
|
rustyline-derive = {git = "https://github.com/rtfeldman/rustyline", tag = "v9.1.1"}
|
||||||
target-lexicon = "0.12.2"
|
target-lexicon = "0.12.2"
|
||||||
|
|
||||||
|
roc_build = {path = "../compiler/build"}
|
||||||
|
roc_collections = {path = "../compiler/collections"}
|
||||||
|
roc_gen_llvm = {path = "../compiler/gen_llvm"}
|
||||||
|
roc_load = {path = "../compiler/load"}
|
||||||
roc_mono = {path = "../compiler/mono"}
|
roc_mono = {path = "../compiler/mono"}
|
||||||
roc_parse = {path = "../compiler/parse"}
|
roc_parse = {path = "../compiler/parse"}
|
||||||
roc_repl_eval = {path = "../repl_eval"}
|
roc_repl_eval = {path = "../repl_eval"}
|
||||||
|
roc_target = {path = "../compiler/roc_target"}
|
||||||
[dev-dependencies]
|
roc_types = {path = "../compiler/types"}
|
||||||
indoc = "1.0.3"
|
roc_builtins = {path = "../compiler/builtins"}
|
||||||
roc_test_utils = {path = "../test_utils"}
|
|
||||||
strip-ansi-escapes = "0.1.1"
|
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "roc_repl_cli"
|
name = "roc_repl_cli"
|
||||||
|
|
|
@ -1,15 +1,27 @@
|
||||||
|
use bumpalo::Bump;
|
||||||
use const_format::concatcp;
|
use const_format::concatcp;
|
||||||
|
use inkwell::context::Context;
|
||||||
|
use libloading::Library;
|
||||||
use rustyline::highlight::{Highlighter, PromptInfo};
|
use rustyline::highlight::{Highlighter, PromptInfo};
|
||||||
use rustyline::validate::{self, ValidationContext, ValidationResult, Validator};
|
use rustyline::validate::{self, ValidationContext, ValidationResult, Validator};
|
||||||
use rustyline_derive::{Completer, Helper, Hinter};
|
use rustyline_derive::{Completer, Helper, Hinter};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use target_lexicon::Triple;
|
||||||
|
|
||||||
|
use roc_build::link::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::file::MonomorphizedModule;
|
||||||
|
use roc_mono::ir::OptLevel;
|
||||||
|
use roc_parse::ast::Expr;
|
||||||
use roc_parse::parser::{EExpr, ELambda, SyntaxError};
|
use roc_parse::parser::{EExpr, ELambda, SyntaxError};
|
||||||
use roc_repl_eval::gen::{gen_and_eval, ReplOutput};
|
use roc_repl_eval::eval::jit_to_ast;
|
||||||
|
use roc_repl_eval::gen::{compile_to_mono, format_answer, ReplOutput};
|
||||||
#[cfg(test)]
|
use roc_repl_eval::ReplApp;
|
||||||
mod tests;
|
use roc_target::TargetInfo;
|
||||||
|
use roc_types::pretty_print::{content_to_string, name_all_type_vars};
|
||||||
|
|
||||||
const BLUE: &str = "\u{001b}[36m";
|
const BLUE: &str = "\u{001b}[36m";
|
||||||
const PINK: &str = "\u{001b}[35m";
|
const PINK: &str = "\u{001b}[35m";
|
||||||
|
@ -105,6 +117,210 @@ impl Validator for InputValidator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct CliReplApp {
|
||||||
|
lib: Library,
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! deref_number {
|
||||||
|
($name: ident, $t: ty) => {
|
||||||
|
fn $name(&self, addr: usize) -> $t {
|
||||||
|
let ptr = addr as *const _;
|
||||||
|
unsafe { *ptr }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReplApp for CliReplApp {
|
||||||
|
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 {
|
||||||
|
unsafe { *(addr as *const &'static str) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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<'a, T: Sized, F: Fn(T) -> Expr<'a>>(
|
||||||
|
&self,
|
||||||
|
main_fn_name: &str,
|
||||||
|
transform: F,
|
||||||
|
) -> Expr<'a> {
|
||||||
|
run_jit_function!(self.lib, main_fn_name, T, transform)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run user code that returns a struct or union, whose size is provided as an argument
|
||||||
|
fn call_function_dynamic_size<T: Sized, F: Fn(usize) -> T>(
|
||||||
|
&self,
|
||||||
|
main_fn_name: &str,
|
||||||
|
bytes: usize,
|
||||||
|
transform: F,
|
||||||
|
) -> T {
|
||||||
|
run_jit_function_dynamic_type!(self.lib, main_fn_name, bytes, transform)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_and_eval_llvm<'a>(
|
||||||
|
src: &str,
|
||||||
|
target: Triple,
|
||||||
|
opt_level: OptLevel,
|
||||||
|
) -> Result<ReplOutput, SyntaxError<'a>> {
|
||||||
|
let arena = Bump::new();
|
||||||
|
let target_info = TargetInfo::from(&target);
|
||||||
|
|
||||||
|
let loaded = match compile_to_mono(&arena, src, target_info) {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(prob_strings) => {
|
||||||
|
return Ok(ReplOutput::Problems(prob_strings));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let MonomorphizedModule {
|
||||||
|
procedures,
|
||||||
|
entry_point,
|
||||||
|
interns,
|
||||||
|
exposed_to_host,
|
||||||
|
mut subs,
|
||||||
|
module_id: home,
|
||||||
|
..
|
||||||
|
} = loaded;
|
||||||
|
|
||||||
|
let context = Context::create();
|
||||||
|
let builder = context.create_builder();
|
||||||
|
let module = arena.alloc(roc_gen_llvm::llvm::build::module_from_builtins(
|
||||||
|
&target, &context, "",
|
||||||
|
));
|
||||||
|
|
||||||
|
debug_assert_eq!(exposed_to_host.values.len(), 1);
|
||||||
|
let (main_fn_symbol, main_fn_var) = exposed_to_host.values.iter().next().unwrap();
|
||||||
|
let main_fn_symbol = *main_fn_symbol;
|
||||||
|
let main_fn_var = *main_fn_var;
|
||||||
|
|
||||||
|
// pretty-print the expr type string for later.
|
||||||
|
name_all_type_vars(main_fn_var, &mut subs);
|
||||||
|
let content = subs.get_content_without_compacting(main_fn_var);
|
||||||
|
let expr_type_str = content_to_string(content, &subs, home, &interns);
|
||||||
|
|
||||||
|
let (_, main_fn_layout) = match procedures.keys().find(|(s, _)| *s == main_fn_symbol) {
|
||||||
|
Some(layout) => *layout,
|
||||||
|
None => {
|
||||||
|
return Ok(ReplOutput::NoProblems {
|
||||||
|
expr: "<function>".to_string(),
|
||||||
|
expr_type: expr_type_str,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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: &arena,
|
||||||
|
builder: &builder,
|
||||||
|
dibuilder: &dibuilder,
|
||||||
|
compile_unit: &compile_unit,
|
||||||
|
context: &context,
|
||||||
|
interns,
|
||||||
|
module,
|
||||||
|
target_info,
|
||||||
|
is_gen_test: true, // 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 (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()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let lib = module_to_dylib(env.module, &target, opt_level)
|
||||||
|
.expect("Error loading compiled dylib for test");
|
||||||
|
|
||||||
|
let app = CliReplApp { lib };
|
||||||
|
|
||||||
|
let res_answer = jit_to_ast(
|
||||||
|
&arena,
|
||||||
|
&app,
|
||||||
|
main_fn_name,
|
||||||
|
main_fn_layout,
|
||||||
|
content,
|
||||||
|
&env.interns,
|
||||||
|
home,
|
||||||
|
&subs,
|
||||||
|
target_info,
|
||||||
|
);
|
||||||
|
|
||||||
|
let formatted = format_answer(&arena, res_answer, expr_type_str);
|
||||||
|
Ok(formatted)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_and_format<'a>(src: &str) -> Result<String, SyntaxError<'a>> {
|
||||||
|
let format_output = |output| match output {
|
||||||
|
ReplOutput::NoProblems { expr, expr_type } => {
|
||||||
|
format!("\n{} {}:{} {}", expr, PINK, END_COL, expr_type)
|
||||||
|
}
|
||||||
|
ReplOutput::Problems(lines) => format!("\n{}\n", lines.join("\n\n")),
|
||||||
|
};
|
||||||
|
|
||||||
|
gen_and_eval_llvm(src, Triple::host(), OptLevel::Normal).map(format_output)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn report_parse_error(fail: SyntaxError) {
|
||||||
|
println!("TODO Gracefully report parse error in repl: {:?}", fail);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn main() -> io::Result<()> {
|
pub fn main() -> io::Result<()> {
|
||||||
use rustyline::error::ReadlineError;
|
use rustyline::error::ReadlineError;
|
||||||
use rustyline::Editor;
|
use rustyline::Editor;
|
||||||
|
@ -222,19 +438,3 @@ pub fn main() -> io::Result<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_parse_error(fail: SyntaxError) {
|
|
||||||
println!("TODO Gracefully report parse error in repl: {:?}", fail);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval_and_format<'a>(src: &str) -> Result<String, SyntaxError<'a>> {
|
|
||||||
use roc_mono::ir::OptLevel;
|
|
||||||
use target_lexicon::Triple;
|
|
||||||
|
|
||||||
gen_and_eval(src.as_bytes(), Triple::host(), OptLevel::Normal).map(|output| match output {
|
|
||||||
ReplOutput::NoProblems { expr, expr_type } => {
|
|
||||||
format!("\n{} {}:{} {}", expr, PINK, END_COL, expr_type)
|
|
||||||
}
|
|
||||||
ReplOutput::Problems(lines) => format!("\n{}\n", lines.join("\n\n")),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,22 +5,13 @@ version = "0.1.0"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["llvm"]
|
|
||||||
llvm = ["inkwell", "libloading", "roc_gen_llvm", "roc_build/llvm"]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bumpalo = {version = "3.8.0", features = ["collections"]}
|
bumpalo = {version = "3.8.0", features = ["collections"]}
|
||||||
inkwell = {path = "../vendor/inkwell", optional = true}
|
|
||||||
libloading = {version = "0.7.1", optional = true}
|
|
||||||
target-lexicon = "0.12.2"
|
|
||||||
|
|
||||||
roc_build = {path = "../compiler/build", default-features = false}
|
|
||||||
roc_builtins = {path = "../compiler/builtins"}
|
roc_builtins = {path = "../compiler/builtins"}
|
||||||
roc_can = {path = "../compiler/can"}
|
roc_can = {path = "../compiler/can"}
|
||||||
roc_collections = {path = "../compiler/collections"}
|
roc_collections = {path = "../compiler/collections"}
|
||||||
roc_fmt = {path = "../compiler/fmt"}
|
roc_fmt = {path = "../compiler/fmt"}
|
||||||
roc_gen_llvm = {path = "../compiler/gen_llvm", optional = true}
|
|
||||||
roc_load = {path = "../compiler/load"}
|
roc_load = {path = "../compiler/load"}
|
||||||
roc_module = {path = "../compiler/module"}
|
roc_module = {path = "../compiler/module"}
|
||||||
roc_mono = {path = "../compiler/mono"}
|
roc_mono = {path = "../compiler/mono"}
|
||||||
|
|
|
@ -1,159 +0,0 @@
|
||||||
use std::mem::size_of;
|
|
||||||
|
|
||||||
pub trait AppMemory {
|
|
||||||
fn deref_bool(&self, addr: usize) -> bool;
|
|
||||||
|
|
||||||
fn deref_u8(&self, addr: usize) -> u8;
|
|
||||||
fn deref_u16(&self, addr: usize) -> u16;
|
|
||||||
fn deref_u32(&self, addr: usize) -> u32;
|
|
||||||
fn deref_u64(&self, addr: usize) -> u64;
|
|
||||||
fn deref_u128(&self, addr: usize) -> u128;
|
|
||||||
fn deref_usize(&self, addr: usize) -> usize;
|
|
||||||
|
|
||||||
fn deref_i8(&self, addr: usize) -> i8;
|
|
||||||
fn deref_i16(&self, addr: usize) -> i16;
|
|
||||||
fn deref_i32(&self, addr: usize) -> i32;
|
|
||||||
fn deref_i64(&self, addr: usize) -> i64;
|
|
||||||
fn deref_i128(&self, addr: usize) -> i128;
|
|
||||||
fn deref_isize(&self, addr: usize) -> isize;
|
|
||||||
|
|
||||||
fn deref_f32(&self, addr: usize) -> f32;
|
|
||||||
fn deref_f64(&self, addr: usize) -> f64;
|
|
||||||
|
|
||||||
fn deref_str(&self, addr: usize) -> &str;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A block of app memory in the same address space as the compiler
|
|
||||||
pub struct AppMemoryInternal;
|
|
||||||
|
|
||||||
macro_rules! internal_number_type {
|
|
||||||
($name: ident, $t: ty) => {
|
|
||||||
fn $name(&self, addr: usize) -> $t {
|
|
||||||
let ptr = addr as *const _;
|
|
||||||
unsafe { *ptr }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AppMemory for AppMemoryInternal {
|
|
||||||
internal_number_type!(deref_bool, bool);
|
|
||||||
|
|
||||||
internal_number_type!(deref_u8, u8);
|
|
||||||
internal_number_type!(deref_u16, u16);
|
|
||||||
internal_number_type!(deref_u32, u32);
|
|
||||||
internal_number_type!(deref_u64, u64);
|
|
||||||
internal_number_type!(deref_u128, u128);
|
|
||||||
internal_number_type!(deref_usize, usize);
|
|
||||||
|
|
||||||
internal_number_type!(deref_i8, i8);
|
|
||||||
internal_number_type!(deref_i16, i16);
|
|
||||||
internal_number_type!(deref_i32, i32);
|
|
||||||
internal_number_type!(deref_i64, i64);
|
|
||||||
internal_number_type!(deref_i128, i128);
|
|
||||||
internal_number_type!(deref_isize, isize);
|
|
||||||
|
|
||||||
internal_number_type!(deref_f32, f32);
|
|
||||||
internal_number_type!(deref_f64, f64);
|
|
||||||
|
|
||||||
fn deref_str(&self, addr: usize) -> &str {
|
|
||||||
unsafe { *(addr as *const &'static str) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A block of app memory copied from an exteral address space outside the compiler
|
|
||||||
/// (e.g. compiler and app are in separate Wasm modules)
|
|
||||||
pub struct AppMemoryExternal<'a> {
|
|
||||||
bytes: &'a [u8],
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! external_number_type {
|
|
||||||
($name: ident, $t: ty) => {
|
|
||||||
fn $name(&self, address: usize) -> $t {
|
|
||||||
const N: usize = size_of::<$t>();
|
|
||||||
let mut array = [0; N];
|
|
||||||
array.copy_from_slice(&self.bytes[address..][..N]);
|
|
||||||
<$t>::from_le_bytes(array)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> AppMemory for AppMemoryExternal<'a> {
|
|
||||||
fn deref_bool(&self, address: usize) -> bool {
|
|
||||||
self.bytes[address] != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
external_number_type!(deref_u8, u8);
|
|
||||||
external_number_type!(deref_u16, u16);
|
|
||||||
external_number_type!(deref_u32, u32);
|
|
||||||
external_number_type!(deref_u64, u64);
|
|
||||||
external_number_type!(deref_u128, u128);
|
|
||||||
external_number_type!(deref_usize, usize);
|
|
||||||
|
|
||||||
external_number_type!(deref_i8, i8);
|
|
||||||
external_number_type!(deref_i16, i16);
|
|
||||||
external_number_type!(deref_i32, i32);
|
|
||||||
external_number_type!(deref_i64, i64);
|
|
||||||
external_number_type!(deref_i128, i128);
|
|
||||||
external_number_type!(deref_isize, isize);
|
|
||||||
|
|
||||||
external_number_type!(deref_f32, f32);
|
|
||||||
external_number_type!(deref_f64, f64);
|
|
||||||
|
|
||||||
fn deref_str(&self, addr: usize) -> &str {
|
|
||||||
let elems_addr = self.deref_usize(addr);
|
|
||||||
let len = self.deref_usize(addr + size_of::<usize>());
|
|
||||||
let bytes = &self.bytes[elems_addr..][..len];
|
|
||||||
std::str::from_utf8(bytes).unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn internal_u8() {
|
|
||||||
let value: u8 = 123;
|
|
||||||
let ptr = &value as *const u8;
|
|
||||||
let addr = ptr as usize;
|
|
||||||
let memory = AppMemoryInternal;
|
|
||||||
let recovered: u8 = memory.deref_u8(addr);
|
|
||||||
assert_eq!(value, recovered);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn external_u8() {
|
|
||||||
let value: u8 = 123;
|
|
||||||
let memory = AppMemoryExternal {
|
|
||||||
bytes: &[0, 0, value, 0, 0],
|
|
||||||
};
|
|
||||||
let addr = 2;
|
|
||||||
let recovered: u8 = memory.deref_u8(addr);
|
|
||||||
assert_eq!(value, recovered);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn internal_i64() {
|
|
||||||
let value: i64 = -123 << 33;
|
|
||||||
let ptr = &value as *const i64;
|
|
||||||
let addr = ptr as usize;
|
|
||||||
let memory = AppMemoryInternal;
|
|
||||||
let recovered: i64 = memory.deref_i64(addr);
|
|
||||||
assert_eq!(value, recovered);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn external_i64() {
|
|
||||||
let value: i64 = -1 << 33;
|
|
||||||
let memory = AppMemoryExternal {
|
|
||||||
bytes: &[
|
|
||||||
0, 0, //
|
|
||||||
0, 0, 0, 0, 0xfe, 0xff, 0xff, 0xff, //
|
|
||||||
0, 0,
|
|
||||||
],
|
|
||||||
};
|
|
||||||
let addr = 2;
|
|
||||||
let recovered: i64 = memory.deref_i64(addr);
|
|
||||||
assert_eq!(value, recovered);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -16,18 +16,12 @@ use roc_region::all::{Loc, Region};
|
||||||
use roc_target::TargetInfo;
|
use roc_target::TargetInfo;
|
||||||
use roc_types::subs::{Content, FlatType, GetSubsSlice, RecordFields, Subs, UnionTags, Variable};
|
use roc_types::subs::{Content, FlatType, GetSubsSlice, RecordFields, Subs, UnionTags, Variable};
|
||||||
|
|
||||||
#[cfg(feature = "llvm")]
|
use crate::ReplApp;
|
||||||
use roc_gen_llvm::{run_jit_function, run_jit_function_dynamic_type};
|
|
||||||
|
|
||||||
#[cfg(feature = "llvm")]
|
struct Env<'a, 'env, A> {
|
||||||
type AppExecutable = libloading::Library;
|
|
||||||
|
|
||||||
use super::app_memory::AppMemory;
|
|
||||||
|
|
||||||
struct Env<'a, 'env, M> {
|
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
subs: &'env Subs,
|
subs: &'env Subs,
|
||||||
app_memory: &'a M,
|
app: &'a A,
|
||||||
target_info: TargetInfo,
|
target_info: TargetInfo,
|
||||||
interns: &'env Interns,
|
interns: &'env Interns,
|
||||||
home: ModuleId,
|
home: ModuleId,
|
||||||
|
@ -46,9 +40,9 @@ pub enum ToAstProblem {
|
||||||
/// we get to a struct or tag, we know what the labels are and can turn them
|
/// we get to a struct or tag, we know what the labels are and can turn them
|
||||||
/// back into the appropriate user-facing literals.
|
/// back into the appropriate user-facing literals.
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub unsafe fn jit_to_ast<'a, M: AppMemory>(
|
pub fn jit_to_ast<'a, A: ReplApp>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
app: AppExecutable,
|
app: &'a A,
|
||||||
main_fn_name: &str,
|
main_fn_name: &str,
|
||||||
layout: ProcLayout<'a>,
|
layout: ProcLayout<'a>,
|
||||||
content: &'a Content,
|
content: &'a Content,
|
||||||
|
@ -56,12 +50,11 @@ pub unsafe fn jit_to_ast<'a, M: AppMemory>(
|
||||||
home: ModuleId,
|
home: ModuleId,
|
||||||
subs: &'a Subs,
|
subs: &'a Subs,
|
||||||
target_info: TargetInfo,
|
target_info: TargetInfo,
|
||||||
app_memory: &'a M,
|
|
||||||
) -> Result<Expr<'a>, ToAstProblem> {
|
) -> Result<Expr<'a>, ToAstProblem> {
|
||||||
let env = Env {
|
let env = Env {
|
||||||
arena,
|
arena,
|
||||||
subs,
|
subs,
|
||||||
app_memory,
|
app,
|
||||||
target_info,
|
target_info,
|
||||||
interns,
|
interns,
|
||||||
home,
|
home,
|
||||||
|
@ -73,7 +66,7 @@ pub unsafe fn jit_to_ast<'a, M: AppMemory>(
|
||||||
result,
|
result,
|
||||||
} => {
|
} => {
|
||||||
// this is a thunk
|
// this is a thunk
|
||||||
jit_to_ast_help(&env, app, main_fn_name, &result, content)
|
jit_to_ast_help(&env, main_fn_name, &result, content)
|
||||||
}
|
}
|
||||||
_ => Err(ToAstProblem::FunctionLayout),
|
_ => Err(ToAstProblem::FunctionLayout),
|
||||||
}
|
}
|
||||||
|
@ -93,8 +86,8 @@ enum NewtypeKind<'a> {
|
||||||
///
|
///
|
||||||
/// The returned list of newtype containers is ordered by increasing depth. As an example,
|
/// The returned list of newtype containers is ordered by increasing depth. As an example,
|
||||||
/// `A ({b : C 123})` will have the unrolled list `[Tag(A), RecordField(b), Tag(C)]`.
|
/// `A ({b : C 123})` will have the unrolled list `[Tag(A), RecordField(b), Tag(C)]`.
|
||||||
fn unroll_newtypes<'a, M: AppMemory>(
|
fn unroll_newtypes<'a, A: ReplApp>(
|
||||||
env: &Env<'a, 'a, M>,
|
env: &Env<'a, 'a, A>,
|
||||||
mut content: &'a Content,
|
mut content: &'a Content,
|
||||||
) -> (Vec<'a, NewtypeKind<'a>>, &'a Content) {
|
) -> (Vec<'a, NewtypeKind<'a>>, &'a Content) {
|
||||||
let mut newtype_containers = Vec::with_capacity_in(1, env.arena);
|
let mut newtype_containers = Vec::with_capacity_in(1, env.arena);
|
||||||
|
@ -127,8 +120,8 @@ fn unroll_newtypes<'a, M: AppMemory>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_newtypes<'a, M: AppMemory>(
|
fn apply_newtypes<'a, A: ReplApp>(
|
||||||
env: &Env<'a, '_, M>,
|
env: &Env<'a, '_, A>,
|
||||||
newtype_containers: Vec<'a, NewtypeKind<'a>>,
|
newtype_containers: Vec<'a, NewtypeKind<'a>>,
|
||||||
mut expr: Expr<'a>,
|
mut expr: Expr<'a>,
|
||||||
) -> Expr<'a> {
|
) -> Expr<'a> {
|
||||||
|
@ -155,15 +148,15 @@ fn apply_newtypes<'a, M: AppMemory>(
|
||||||
expr
|
expr
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unroll_aliases<'a, M: AppMemory>(env: &Env<'a, 'a, M>, mut content: &'a Content) -> &'a Content {
|
fn unroll_aliases<'a, A: ReplApp>(env: &Env<'a, 'a, A>, mut content: &'a Content) -> &'a Content {
|
||||||
while let Content::Alias(_, _, real) = content {
|
while let Content::Alias(_, _, real) = content {
|
||||||
content = env.subs.get_content_without_compacting(*real);
|
content = env.subs.get_content_without_compacting(*real);
|
||||||
}
|
}
|
||||||
content
|
content
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unroll_recursion_var<'a, M: AppMemory>(
|
fn unroll_recursion_var<'a, A: ReplApp>(
|
||||||
env: &Env<'a, 'a, M>,
|
env: &Env<'a, 'a, A>,
|
||||||
mut content: &'a Content,
|
mut content: &'a Content,
|
||||||
) -> &'a Content {
|
) -> &'a Content {
|
||||||
while let Content::RecursionVar { structure, .. } = content {
|
while let Content::RecursionVar { structure, .. } = content {
|
||||||
|
@ -172,8 +165,8 @@ fn unroll_recursion_var<'a, M: AppMemory>(
|
||||||
content
|
content
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_tags_vars_and_variant<'a, M: AppMemory>(
|
fn get_tags_vars_and_variant<'a, A: ReplApp>(
|
||||||
env: &Env<'a, '_, M>,
|
env: &Env<'a, '_, A>,
|
||||||
tags: &UnionTags,
|
tags: &UnionTags,
|
||||||
opt_rec_var: Option<Variable>,
|
opt_rec_var: Option<Variable>,
|
||||||
) -> (MutMap<TagName, std::vec::Vec<Variable>>, UnionVariant<'a>) {
|
) -> (MutMap<TagName, std::vec::Vec<Variable>>, UnionVariant<'a>) {
|
||||||
|
@ -190,8 +183,8 @@ fn get_tags_vars_and_variant<'a, M: AppMemory>(
|
||||||
(vars_of_tag, union_variant)
|
(vars_of_tag, union_variant)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expr_of_tag<'a, M: AppMemory>(
|
fn expr_of_tag<'a, A: ReplApp>(
|
||||||
env: &Env<'a, 'a, M>,
|
env: &Env<'a, 'a, A>,
|
||||||
data_addr: usize,
|
data_addr: usize,
|
||||||
tag_name: &TagName,
|
tag_name: &TagName,
|
||||||
arg_layouts: &'a [Layout<'a>],
|
arg_layouts: &'a [Layout<'a>],
|
||||||
|
@ -213,8 +206,8 @@ fn expr_of_tag<'a, M: AppMemory>(
|
||||||
|
|
||||||
/// Gets the tag ID of a union variant, assuming that the tag ID is stored alongside (after) the
|
/// Gets the tag ID of a union variant, assuming that the tag ID is stored alongside (after) the
|
||||||
/// tag data. The caller is expected to check that the tag ID is indeed stored this way.
|
/// tag data. The caller is expected to check that the tag ID is indeed stored this way.
|
||||||
fn tag_id_from_data<'a, M: AppMemory>(
|
fn tag_id_from_data<'a, A: ReplApp>(
|
||||||
env: &Env<'a, 'a, M>,
|
env: &Env<'a, 'a, A>,
|
||||||
union_layout: UnionLayout,
|
union_layout: UnionLayout,
|
||||||
data_addr: usize,
|
data_addr: usize,
|
||||||
) -> i64 {
|
) -> i64 {
|
||||||
|
@ -224,13 +217,13 @@ fn tag_id_from_data<'a, M: AppMemory>(
|
||||||
let tag_id_addr = data_addr + offset as usize;
|
let tag_id_addr = data_addr + offset as usize;
|
||||||
|
|
||||||
match union_layout.tag_id_builtin() {
|
match union_layout.tag_id_builtin() {
|
||||||
Builtin::Bool => env.app_memory.deref_bool(tag_id_addr) as i64,
|
Builtin::Bool => env.app.deref_bool(tag_id_addr) as i64,
|
||||||
Builtin::Int(IntWidth::U8) => env.app_memory.deref_u8(tag_id_addr) as i64,
|
Builtin::Int(IntWidth::U8) => env.app.deref_u8(tag_id_addr) as i64,
|
||||||
Builtin::Int(IntWidth::U16) => env.app_memory.deref_u16(tag_id_addr) as i64,
|
Builtin::Int(IntWidth::U16) => env.app.deref_u16(tag_id_addr) as i64,
|
||||||
Builtin::Int(IntWidth::U64) => {
|
Builtin::Int(IntWidth::U64) => {
|
||||||
// used by non-recursive unions at the
|
// used by non-recursive unions at the
|
||||||
// moment, remove if that is no longer the case
|
// moment, remove if that is no longer the case
|
||||||
env.app_memory.deref_i64(tag_id_addr)
|
env.app.deref_i64(tag_id_addr)
|
||||||
}
|
}
|
||||||
_ => unreachable!("invalid tag id layout"),
|
_ => unreachable!("invalid tag id layout"),
|
||||||
}
|
}
|
||||||
|
@ -240,13 +233,13 @@ fn tag_id_from_data<'a, M: AppMemory>(
|
||||||
/// pointer to the data of the union variant). Returns
|
/// pointer to the data of the union variant). Returns
|
||||||
/// - the tag ID
|
/// - the tag ID
|
||||||
/// - the address of the data of the union variant, unmasked if the pointer held the tag ID
|
/// - the address of the data of the union variant, unmasked if the pointer held the tag ID
|
||||||
fn tag_id_from_recursive_ptr<'a, M: AppMemory>(
|
fn tag_id_from_recursive_ptr<'a, A: ReplApp>(
|
||||||
env: &Env<'a, 'a, M>,
|
env: &Env<'a, 'a, A>,
|
||||||
union_layout: UnionLayout,
|
union_layout: UnionLayout,
|
||||||
rec_addr: usize,
|
rec_addr: usize,
|
||||||
) -> (i64, usize) {
|
) -> (i64, usize) {
|
||||||
let tag_in_ptr = union_layout.stores_tag_id_in_pointer(env.target_info);
|
let tag_in_ptr = union_layout.stores_tag_id_in_pointer(env.target_info);
|
||||||
let addr_with_id = env.app_memory.deref_usize(rec_addr);
|
let addr_with_id = env.app.deref_usize(rec_addr);
|
||||||
|
|
||||||
if tag_in_ptr {
|
if tag_in_ptr {
|
||||||
let (_, tag_id_mask) = UnionLayout::tag_id_pointer_bits_and_mask(env.target_info);
|
let (_, tag_id_mask) = UnionLayout::tag_id_pointer_bits_and_mask(env.target_info);
|
||||||
|
@ -264,9 +257,8 @@ const OPAQUE_FUNCTION: Expr = Expr::Var {
|
||||||
ident: "<function>",
|
ident: "<function>",
|
||||||
};
|
};
|
||||||
|
|
||||||
fn jit_to_ast_help<'a, M: AppMemory>(
|
fn jit_to_ast_help<'a, A: ReplApp>(
|
||||||
env: &Env<'a, 'a, M>,
|
env: &Env<'a, 'a, A>,
|
||||||
app: AppExecutable,
|
|
||||||
main_fn_name: &str,
|
main_fn_name: &str,
|
||||||
layout: &Layout<'a>,
|
layout: &Layout<'a>,
|
||||||
content: &'a Content,
|
content: &'a Content,
|
||||||
|
@ -274,26 +266,25 @@ fn jit_to_ast_help<'a, M: AppMemory>(
|
||||||
let (newtype_containers, content) = unroll_newtypes(env, content);
|
let (newtype_containers, content) = unroll_newtypes(env, content);
|
||||||
let content = unroll_aliases(env, content);
|
let content = unroll_aliases(env, content);
|
||||||
let result = match layout {
|
let result = match layout {
|
||||||
Layout::Builtin(Builtin::Bool) => Ok(run_jit_function!(app, main_fn_name, bool, |num| {
|
Layout::Builtin(Builtin::Bool) => Ok(env
|
||||||
bool_to_ast(env, num, content)
|
.app
|
||||||
})),
|
.call_function(main_fn_name, |num: bool| bool_to_ast(env, num, content))),
|
||||||
Layout::Builtin(Builtin::Int(int_width)) => {
|
Layout::Builtin(Builtin::Int(int_width)) => {
|
||||||
use IntWidth::*;
|
use IntWidth::*;
|
||||||
|
|
||||||
macro_rules! helper {
|
macro_rules! helper {
|
||||||
($ty:ty) => {
|
($ty:ty) => {
|
||||||
run_jit_function!(app, main_fn_name, $ty, |num| num_to_ast(
|
env.app.call_function(main_fn_name, |num: $ty| {
|
||||||
env,
|
num_to_ast(env, number_literal_to_ast(env.arena, num), content)
|
||||||
number_literal_to_ast(env.arena, num),
|
})
|
||||||
content
|
|
||||||
))
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = match int_width {
|
let result = match int_width {
|
||||||
U8 | I8 => {
|
U8 | I8 => {
|
||||||
// NOTE: this is does not handle 8-bit numbers yet
|
// NOTE: `helper!` does not handle 8-bit numbers yet
|
||||||
run_jit_function!(app, main_fn_name, u8, |num| byte_to_ast(env, num, content))
|
env.app
|
||||||
|
.call_function(main_fn_name, |num: u8| byte_to_ast(env, num, content))
|
||||||
}
|
}
|
||||||
U16 => helper!(u16),
|
U16 => helper!(u16),
|
||||||
U32 => helper!(u32),
|
U32 => helper!(u32),
|
||||||
|
@ -312,11 +303,9 @@ fn jit_to_ast_help<'a, M: AppMemory>(
|
||||||
|
|
||||||
macro_rules! helper {
|
macro_rules! helper {
|
||||||
($ty:ty) => {
|
($ty:ty) => {
|
||||||
run_jit_function!(app, main_fn_name, $ty, |num| num_to_ast(
|
env.app.call_function(main_fn_name, |num: $ty| {
|
||||||
env,
|
num_to_ast(env, number_literal_to_ast(env.arena, num), content)
|
||||||
number_literal_to_ast(env.arena, num),
|
})
|
||||||
content
|
|
||||||
))
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,18 +317,16 @@ fn jit_to_ast_help<'a, M: AppMemory>(
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
Layout::Builtin(Builtin::Str) => Ok(run_jit_function!(
|
Layout::Builtin(Builtin::Str) => {
|
||||||
app,
|
Ok(env.app.call_function(main_fn_name, |string: &'static str| {
|
||||||
main_fn_name,
|
str_to_ast(env.arena, env.arena.alloc(string))
|
||||||
&'static str,
|
}))
|
||||||
|string: &'static str| { str_to_ast(env.arena, env.arena.alloc(string)) }
|
}
|
||||||
)),
|
Layout::Builtin(Builtin::List(elem_layout)) => Ok(env
|
||||||
Layout::Builtin(Builtin::List(elem_layout)) => Ok(run_jit_function!(
|
.app
|
||||||
app,
|
.call_function(main_fn_name, |(addr, len): (usize, usize)| {
|
||||||
main_fn_name,
|
list_to_ast(env, addr, len, elem_layout, content)
|
||||||
(usize, usize),
|
})),
|
||||||
|(addr, len): (usize, usize)| { list_to_ast(env, addr, len, elem_layout, content) }
|
|
||||||
)),
|
|
||||||
Layout::Builtin(other) => {
|
Layout::Builtin(other) => {
|
||||||
todo!("add support for rendering builtin {:?} to the REPL", other)
|
todo!("add support for rendering builtin {:?} to the REPL", other)
|
||||||
}
|
}
|
||||||
|
@ -395,37 +382,30 @@ fn jit_to_ast_help<'a, M: AppMemory>(
|
||||||
|
|
||||||
let result_stack_size = layout.stack_size(env.target_info);
|
let result_stack_size = layout.stack_size(env.target_info);
|
||||||
|
|
||||||
run_jit_function_dynamic_type!(
|
env.app.call_function_dynamic_size(
|
||||||
app,
|
|
||||||
main_fn_name,
|
main_fn_name,
|
||||||
result_stack_size as usize,
|
result_stack_size as usize,
|
||||||
|bytes_addr: usize| { struct_addr_to_ast(bytes_addr as usize) }
|
struct_addr_to_ast,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Layout::Union(UnionLayout::NonRecursive(_)) => {
|
Layout::Union(UnionLayout::NonRecursive(_)) => {
|
||||||
let size = layout.stack_size(env.target_info);
|
let size = layout.stack_size(env.target_info);
|
||||||
Ok(run_jit_function_dynamic_type!(
|
Ok(env
|
||||||
app,
|
.app
|
||||||
main_fn_name,
|
.call_function_dynamic_size(main_fn_name, size as usize, |addr: usize| {
|
||||||
size as usize,
|
|
||||||
|addr: usize| {
|
|
||||||
addr_to_ast(env, addr, layout, WhenRecursive::Unreachable, content)
|
addr_to_ast(env, addr, layout, WhenRecursive::Unreachable, content)
|
||||||
}
|
}))
|
||||||
))
|
|
||||||
}
|
}
|
||||||
Layout::Union(UnionLayout::Recursive(_))
|
Layout::Union(UnionLayout::Recursive(_))
|
||||||
| Layout::Union(UnionLayout::NonNullableUnwrapped(_))
|
| Layout::Union(UnionLayout::NonNullableUnwrapped(_))
|
||||||
| Layout::Union(UnionLayout::NullableUnwrapped { .. })
|
| Layout::Union(UnionLayout::NullableUnwrapped { .. })
|
||||||
| Layout::Union(UnionLayout::NullableWrapped { .. }) => {
|
| Layout::Union(UnionLayout::NullableWrapped { .. }) => {
|
||||||
let size = layout.stack_size(env.target_info);
|
let size = layout.stack_size(env.target_info);
|
||||||
Ok(run_jit_function_dynamic_type!(
|
Ok(env
|
||||||
app,
|
.app
|
||||||
main_fn_name,
|
.call_function_dynamic_size(main_fn_name, size as usize, |addr: usize| {
|
||||||
size as usize,
|
|
||||||
|addr: usize| {
|
|
||||||
addr_to_ast(env, addr, layout, WhenRecursive::Loop(*layout), content)
|
addr_to_ast(env, addr, layout, WhenRecursive::Loop(*layout), content)
|
||||||
}
|
}))
|
||||||
))
|
|
||||||
}
|
}
|
||||||
Layout::RecursivePointer => {
|
Layout::RecursivePointer => {
|
||||||
unreachable!("RecursivePointers can only be inside structures")
|
unreachable!("RecursivePointers can only be inside structures")
|
||||||
|
@ -435,7 +415,7 @@ fn jit_to_ast_help<'a, M: AppMemory>(
|
||||||
result.map(|e| apply_newtypes(env, newtype_containers, e))
|
result.map(|e| apply_newtypes(env, newtype_containers, e))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tag_name_to_expr<'a, M: AppMemory>(env: &Env<'a, '_, M>, tag_name: &TagName) -> Expr<'a> {
|
fn tag_name_to_expr<'a, A: ReplApp>(env: &Env<'a, '_, A>, tag_name: &TagName) -> Expr<'a> {
|
||||||
match tag_name {
|
match tag_name {
|
||||||
TagName::Global(_) => Expr::GlobalTag(
|
TagName::Global(_) => Expr::GlobalTag(
|
||||||
env.arena
|
env.arena
|
||||||
|
@ -457,8 +437,8 @@ enum WhenRecursive<'a> {
|
||||||
Loop(Layout<'a>),
|
Loop(Layout<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn addr_to_ast<'a, M: AppMemory>(
|
fn addr_to_ast<'a, A: ReplApp>(
|
||||||
env: &Env<'a, 'a, M>,
|
env: &Env<'a, 'a, A>,
|
||||||
addr: usize,
|
addr: usize,
|
||||||
layout: &Layout<'a>,
|
layout: &Layout<'a>,
|
||||||
when_recursive: WhenRecursive<'a>,
|
when_recursive: WhenRecursive<'a>,
|
||||||
|
@ -466,7 +446,7 @@ fn addr_to_ast<'a, M: AppMemory>(
|
||||||
) -> Expr<'a> {
|
) -> Expr<'a> {
|
||||||
macro_rules! helper {
|
macro_rules! helper {
|
||||||
($method: ident, $ty: ty) => {{
|
($method: ident, $ty: ty) => {{
|
||||||
let num: $ty = env.app_memory.$method(addr);
|
let num: $ty = env.app.$method(addr);
|
||||||
|
|
||||||
num_to_ast(env, number_literal_to_ast(env.arena, num), content)
|
num_to_ast(env, number_literal_to_ast(env.arena, num), content)
|
||||||
}};
|
}};
|
||||||
|
@ -480,7 +460,7 @@ fn addr_to_ast<'a, M: AppMemory>(
|
||||||
(_, Layout::Builtin(Builtin::Bool)) => {
|
(_, Layout::Builtin(Builtin::Bool)) => {
|
||||||
// TODO: bits are not as expected here.
|
// TODO: bits are not as expected here.
|
||||||
// num is always false at the moment.
|
// num is always false at the moment.
|
||||||
let num: bool = env.app_memory.deref_bool(addr);
|
let num: bool = env.app.deref_bool(addr);
|
||||||
|
|
||||||
bool_to_ast(env, num, content)
|
bool_to_ast(env, num, content)
|
||||||
}
|
}
|
||||||
|
@ -510,13 +490,13 @@ fn addr_to_ast<'a, M: AppMemory>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(_, Layout::Builtin(Builtin::List(elem_layout))) => {
|
(_, Layout::Builtin(Builtin::List(elem_layout))) => {
|
||||||
let elem_addr = env.app_memory.deref_usize(addr);
|
let elem_addr = env.app.deref_usize(addr);
|
||||||
let len = env.app_memory.deref_usize(addr + env.target_info.ptr_width() as usize);
|
let len = env.app.deref_usize(addr + env.target_info.ptr_width() as usize);
|
||||||
|
|
||||||
list_to_ast(env, elem_addr, len, elem_layout, content)
|
list_to_ast(env, elem_addr, len, elem_layout, content)
|
||||||
}
|
}
|
||||||
(_, Layout::Builtin(Builtin::Str)) => {
|
(_, Layout::Builtin(Builtin::Str)) => {
|
||||||
let arena_str = env.app_memory.deref_str(addr);
|
let arena_str = env.app.deref_str(addr);
|
||||||
|
|
||||||
str_to_ast(env.arena, arena_str)
|
str_to_ast(env.arena, arena_str)
|
||||||
}
|
}
|
||||||
|
@ -636,7 +616,7 @@ fn addr_to_ast<'a, M: AppMemory>(
|
||||||
_ => unreachable!("any other variant would have a different layout"),
|
_ => unreachable!("any other variant would have a different layout"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let data_addr = env.app_memory.deref_usize(addr);
|
let data_addr = env.app.deref_usize(addr);
|
||||||
|
|
||||||
expr_of_tag(
|
expr_of_tag(
|
||||||
env,
|
env,
|
||||||
|
@ -666,7 +646,7 @@ fn addr_to_ast<'a, M: AppMemory>(
|
||||||
_ => unreachable!("any other variant would have a different layout"),
|
_ => unreachable!("any other variant would have a different layout"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let data_addr = env.app_memory.deref_usize(addr);
|
let data_addr = env.app.deref_usize(addr);
|
||||||
if data_addr == 0 {
|
if data_addr == 0 {
|
||||||
tag_name_to_expr(env, &nullable_name)
|
tag_name_to_expr(env, &nullable_name)
|
||||||
} else {
|
} else {
|
||||||
|
@ -697,7 +677,7 @@ fn addr_to_ast<'a, M: AppMemory>(
|
||||||
_ => unreachable!("any other variant would have a different layout"),
|
_ => unreachable!("any other variant would have a different layout"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let data_addr = env.app_memory.deref_usize(addr);
|
let data_addr = env.app.deref_usize(addr);
|
||||||
if data_addr == 0 {
|
if data_addr == 0 {
|
||||||
tag_name_to_expr(env, &nullable_name)
|
tag_name_to_expr(env, &nullable_name)
|
||||||
} else {
|
} else {
|
||||||
|
@ -726,8 +706,8 @@ fn addr_to_ast<'a, M: AppMemory>(
|
||||||
apply_newtypes(env, newtype_containers, expr)
|
apply_newtypes(env, newtype_containers, expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_to_ast<'a, M: AppMemory>(
|
fn list_to_ast<'a, A: ReplApp>(
|
||||||
env: &Env<'a, 'a, M>,
|
env: &Env<'a, 'a, A>,
|
||||||
addr: usize,
|
addr: usize,
|
||||||
len: usize,
|
len: usize,
|
||||||
elem_layout: &Layout<'a>,
|
elem_layout: &Layout<'a>,
|
||||||
|
@ -775,8 +755,8 @@ fn list_to_ast<'a, M: AppMemory>(
|
||||||
Expr::List(Collection::with_items(output))
|
Expr::List(Collection::with_items(output))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn single_tag_union_to_ast<'a, M: AppMemory>(
|
fn single_tag_union_to_ast<'a, A: ReplApp>(
|
||||||
env: &Env<'a, 'a, M>,
|
env: &Env<'a, 'a, A>,
|
||||||
addr: usize,
|
addr: usize,
|
||||||
field_layouts: &'a [Layout<'a>],
|
field_layouts: &'a [Layout<'a>],
|
||||||
tag_name: &TagName,
|
tag_name: &TagName,
|
||||||
|
@ -801,8 +781,8 @@ fn single_tag_union_to_ast<'a, M: AppMemory>(
|
||||||
Expr::Apply(loc_tag_expr, output, CalledVia::Space)
|
Expr::Apply(loc_tag_expr, output, CalledVia::Space)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sequence_of_expr<'a, I, M: AppMemory>(
|
fn sequence_of_expr<'a, I, A: ReplApp>(
|
||||||
env: &Env<'a, 'a, M>,
|
env: &Env<'a, 'a, A>,
|
||||||
addr: usize,
|
addr: usize,
|
||||||
sequence: I,
|
sequence: I,
|
||||||
when_recursive: WhenRecursive<'a>,
|
when_recursive: WhenRecursive<'a>,
|
||||||
|
@ -832,8 +812,8 @@ where
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
fn struct_to_ast<'a, M: AppMemory>(
|
fn struct_to_ast<'a, A: ReplApp>(
|
||||||
env: &Env<'a, 'a, M>,
|
env: &Env<'a, 'a, A>,
|
||||||
addr: usize,
|
addr: usize,
|
||||||
field_layouts: &'a [Layout<'a>],
|
field_layouts: &'a [Layout<'a>],
|
||||||
record_fields: RecordFields,
|
record_fields: RecordFields,
|
||||||
|
@ -949,7 +929,7 @@ fn unpack_two_element_tag_union(
|
||||||
(tag_name1, payload_vars1, tag_name2, payload_vars2)
|
(tag_name1, payload_vars1, tag_name2, payload_vars2)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bool_to_ast<'a, M: AppMemory>(env: &Env<'a, '_, M>, value: bool, content: &Content) -> Expr<'a> {
|
fn bool_to_ast<'a, A: ReplApp>(env: &Env<'a, '_, A>, value: bool, content: &Content) -> Expr<'a> {
|
||||||
use Content::*;
|
use Content::*;
|
||||||
|
|
||||||
let arena = env.arena;
|
let arena = env.arena;
|
||||||
|
@ -1027,7 +1007,7 @@ fn bool_to_ast<'a, M: AppMemory>(env: &Env<'a, '_, M>, value: bool, content: &Co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn byte_to_ast<'a, M: AppMemory>(env: &Env<'a, '_, M>, value: u8, content: &Content) -> Expr<'a> {
|
fn byte_to_ast<'a, A: ReplApp>(env: &Env<'a, '_, A>, value: u8, content: &Content) -> Expr<'a> {
|
||||||
use Content::*;
|
use Content::*;
|
||||||
|
|
||||||
let arena = env.arena;
|
let arena = env.arena;
|
||||||
|
@ -1119,8 +1099,8 @@ fn byte_to_ast<'a, M: AppMemory>(env: &Env<'a, '_, M>, value: u8, content: &Cont
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn num_to_ast<'a, M: AppMemory>(
|
fn num_to_ast<'a, A: ReplApp>(
|
||||||
env: &Env<'a, '_, M>,
|
env: &Env<'a, '_, A>,
|
||||||
num_expr: Expr<'a>,
|
num_expr: Expr<'a>,
|
||||||
content: &Content,
|
content: &Content,
|
||||||
) -> Expr<'a> {
|
) -> Expr<'a> {
|
||||||
|
@ -1199,15 +1179,15 @@ fn number_literal_to_ast<T: std::fmt::Display>(arena: &Bump, num: T) -> Expr<'_>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_endian = "little")]
|
#[cfg(target_endian = "little")]
|
||||||
#[cfg(target_pointer_width = "64")]
|
/// NOTE: As of this writing, we don't have big-endian small strings implemented yet!
|
||||||
/// TODO implement this for 32-bit and big-endian targets. NOTE: As of this writing,
|
|
||||||
/// we don't have big-endian small strings implemented yet!
|
|
||||||
fn str_to_ast<'a>(arena: &'a Bump, string: &'a str) -> Expr<'a> {
|
fn str_to_ast<'a>(arena: &'a Bump, string: &'a str) -> Expr<'a> {
|
||||||
let bytes: [u8; 16] = unsafe { std::mem::transmute::<&'a str, [u8; 16]>(string) };
|
const STR_SIZE: usize = 2 * std::mem::size_of::<usize>();
|
||||||
let is_small = (bytes[15] & 0b1000_0000) != 0;
|
|
||||||
|
let bytes: [u8; STR_SIZE] = unsafe { std::mem::transmute(string) };
|
||||||
|
let is_small = (bytes[STR_SIZE - 1] & 0b1000_0000) != 0;
|
||||||
|
|
||||||
if is_small {
|
if is_small {
|
||||||
let len = (bytes[15] & 0b0111_1111) as usize;
|
let len = (bytes[STR_SIZE - 1] & 0b0111_1111) as usize;
|
||||||
let mut string = bumpalo::collections::String::with_capacity_in(len, arena);
|
let mut string = bumpalo::collections::String::with_capacity_in(len, arena);
|
||||||
|
|
||||||
for byte in bytes.iter().take(len) {
|
for byte in bytes.iter().take(len) {
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue