mirror of
https://github.com/roc-lang/roc.git
synced 2025-07-07 22:55:00 +00:00
Prefer and
and or
for boolean operators
This commit is contained in:
parent
d9d3fc74fc
commit
a292e070d4
35 changed files with 189 additions and 282 deletions
|
@ -148,19 +148,19 @@ is_valid_char = \c ->
|
|||
|
||||
is_alpha_num : U8 -> Bool
|
||||
is_alpha_num = \key ->
|
||||
(key >= 48 && key <= 57) || (key >= 64 && key <= 90) || (key >= 97 && key <= 122)
|
||||
(key >= 48 and key <= 57) or (key >= 64 and key <= 90) or (key >= 97 and key <= 122)
|
||||
|
||||
# Convert a base64 character/digit to its index
|
||||
# See also [Wikipedia](https://en.wikipedia.org/wiki/Base64#Base64_table)
|
||||
unsafe_convert_char : U8 -> U8
|
||||
unsafe_convert_char = \key ->
|
||||
if key >= 65 && key <= 90 then
|
||||
if key >= 65 and key <= 90 then
|
||||
# A-Z
|
||||
key - 65
|
||||
else if key >= 97 && key <= 122 then
|
||||
else if key >= 97 and key <= 122 then
|
||||
# a-z
|
||||
(key - 97) + 26
|
||||
else if key >= 48 && key <= 57 then
|
||||
else if key >= 48 and key <= 57 then
|
||||
# 0-9
|
||||
(key - 48) + 26 + 26
|
||||
else
|
||||
|
|
|
@ -50,7 +50,7 @@ safe = \queen, diagonal, xs ->
|
|||
when xs is
|
||||
Nil -> Bool.true
|
||||
Cons(q, t) ->
|
||||
if queen != q && queen != q + diagonal && queen != q - diagonal then
|
||||
if queen != q and queen != q + diagonal and queen != q - diagonal then
|
||||
safe(queen, (diagonal + 1), t)
|
||||
else
|
||||
Bool.false
|
||||
|
|
|
@ -19,10 +19,8 @@ to_str = \@Variable(char) ->
|
|||
from_utf8 : U8 -> Result Variable [InvalidVariableUtf8]
|
||||
from_utf8 = \char ->
|
||||
if
|
||||
char
|
||||
>= 0x61 # "a"
|
||||
&& char
|
||||
<= 0x7A # "z"
|
||||
char >= 0x61 # "a"
|
||||
and char <= 0x7A # "z"
|
||||
then
|
||||
Ok(@Variable(char))
|
||||
else
|
||||
|
|
|
@ -457,21 +457,15 @@ pop_variable = \ctx ->
|
|||
|
||||
is_digit : U8 -> Bool
|
||||
is_digit = \char ->
|
||||
char
|
||||
>= 0x30 # `0`
|
||||
&& char
|
||||
<= 0x39 # `0`
|
||||
char >= 0x30 # `0`
|
||||
and char <= 0x39 # `0`
|
||||
|
||||
is_whitespace : U8 -> Bool
|
||||
is_whitespace = \char ->
|
||||
char
|
||||
== 0xA # new line
|
||||
|| char
|
||||
== 0xD # carriage return
|
||||
|| char
|
||||
== 0x20 # space
|
||||
|| char
|
||||
== 0x9 # tab
|
||||
char == 0xA # new line
|
||||
or char == 0xD # carriage return
|
||||
or char == 0x20 # space
|
||||
or char == 0x9 # tab
|
||||
|
||||
end_unexpected = \err ->
|
||||
when err is
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
module [Bool, Eq, true, false, and, or, not, is_eq, is_not_eq]
|
||||
module [Bool, Eq, true, false, not, is_eq, is_not_eq]
|
||||
|
||||
## Defines a type that can be compared for total equality.
|
||||
##
|
||||
|
@ -44,55 +44,6 @@ true = @Bool(True)
|
|||
false : Bool
|
||||
false = @Bool(False)
|
||||
|
||||
## Returns `Bool.true` when both inputs are `Bool.true`. This is equivalent to
|
||||
## the logic [AND](https://en.wikipedia.org/wiki/Logical_conjunction)
|
||||
## gate. The infix operator `&&` can also be used as shorthand for
|
||||
## `Bool.and`.
|
||||
##
|
||||
## ```roc
|
||||
## expect Bool.and(Bool.true, Bool.true) == Bool.true
|
||||
## expect (Bool.true && Bool.true) == Bool.true
|
||||
## expect (Bool.false && Bool.true) == Bool.false
|
||||
## expect (Bool.true && Bool.false) == Bool.false
|
||||
## expect (Bool.false && Bool.false) == Bool.false
|
||||
## ```
|
||||
##
|
||||
## ## Performance Details
|
||||
##
|
||||
## In Roc the `&&` and `||` work the same way as any
|
||||
## other function. However, in some languages `&&` and `||` are special-cased.
|
||||
## In these languages the compiler will skip evaluating the expression after the
|
||||
## first operator under certain circumstances. For example an expression like
|
||||
## `enable_pets && likes_dogs(user)` would compile to.
|
||||
## ```roc
|
||||
## if enable_pets then
|
||||
## likes_dogs(user)
|
||||
## else
|
||||
## Bool.false
|
||||
## ```
|
||||
## Roc does not do this because conditionals like `if` and `when` have a
|
||||
## performance cost. Calling a function can sometimes be faster across the board
|
||||
## than doing an `if` to decide whether to skip calling it.
|
||||
and : Bool, Bool -> Bool
|
||||
|
||||
## Returns `Bool.true` when either input is a `Bool.true`. This is equivalent to
|
||||
## the logic [OR](https://en.wikipedia.org/wiki/Logical_disjunction) gate.
|
||||
## The infix operator `||` can also be used as shorthand for `Bool.or`.
|
||||
## ```roc
|
||||
## expect Bool.or(Bool.false, Bool.true) == Bool.true
|
||||
## expect (Bool.true || Bool.true) == Bool.true
|
||||
## expect (Bool.false || Bool.true) == Bool.true
|
||||
## expect (Bool.true || Bool.false) == Bool.true
|
||||
## expect (Bool.false || Bool.false) == Bool.false
|
||||
## ```
|
||||
##
|
||||
## ## Performance Details
|
||||
##
|
||||
## In Roc the `&&` and `||` work the same way as any
|
||||
## other functions. However, in some languages `&&` and `||` are special-cased.
|
||||
## Refer to the note in `Bool.and` for more detail.
|
||||
or : Bool, Bool -> Bool
|
||||
|
||||
## Returns `Bool.false` when given `Bool.true`, and vice versa. This is
|
||||
## equivalent to the logic [NOT](https://en.wikipedia.org/wiki/Negation)
|
||||
## gate. The operator `!` can also be used as shorthand for `Bool.not`.
|
||||
|
|
|
@ -170,7 +170,7 @@ reserve = |@Dict({ buckets, data, max_bucket_capacity: original_max_bucket_capac
|
|||
size = Num.min(requested_size, max_size)
|
||||
|
||||
requested_shifts = calc_shifts_for_size(size, max_load_factor)
|
||||
if List.is_empty(buckets) || requested_shifts > shifts then
|
||||
if List.is_empty(buckets) or requested_shifts > shifts then
|
||||
(buckets0, max_bucket_capacity) = alloc_buckets_from_shift(requested_shifts, max_load_factor)
|
||||
buckets1 = fill_buckets_from_data(buckets0, data, requested_shifts)
|
||||
@Dict(
|
||||
|
@ -915,7 +915,7 @@ calc_shifts_for_size_helper = |shifts, size, max_load_factor|
|
|||
|> Num.to_f32
|
||||
|> Num.mul(max_load_factor)
|
||||
|> Num.floor
|
||||
if shifts > 0 && max_bucket_capacity < size then
|
||||
if shifts > 0 and max_bucket_capacity < size then
|
||||
calc_shifts_for_size_helper(Num.sub_wrap(shifts, 1), size, max_load_factor)
|
||||
else
|
||||
shifts
|
||||
|
@ -1087,7 +1087,7 @@ expect
|
|||
|> insert("bar", {})
|
||||
|> insert("baz", {})
|
||||
|
||||
contains(dict, "baz") && !(contains(dict, "other"))
|
||||
contains(dict, "baz") and !(contains(dict, "other"))
|
||||
|
||||
expect
|
||||
dict =
|
||||
|
@ -1145,17 +1145,17 @@ expect
|
|||
|> insert("l", 11)
|
||||
|
||||
(get(dict, "a") == Ok(0))
|
||||
&& (get(dict, "b") == Ok(1))
|
||||
&& (get(dict, "c") == Ok(2))
|
||||
&& (get(dict, "d") == Ok(3))
|
||||
&& (get(dict, "e") == Ok(4))
|
||||
&& (get(dict, "f") == Ok(5))
|
||||
&& (get(dict, "g") == Ok(6))
|
||||
&& (get(dict, "h") == Ok(7))
|
||||
&& (get(dict, "i") == Ok(8))
|
||||
&& (get(dict, "j") == Ok(9))
|
||||
&& (get(dict, "k") == Ok(10))
|
||||
&& (get(dict, "l") == Ok(11))
|
||||
and (get(dict, "b") == Ok(1))
|
||||
and (get(dict, "c") == Ok(2))
|
||||
and (get(dict, "d") == Ok(3))
|
||||
and (get(dict, "e") == Ok(4))
|
||||
and (get(dict, "f") == Ok(5))
|
||||
and (get(dict, "g") == Ok(6))
|
||||
and (get(dict, "h") == Ok(7))
|
||||
and (get(dict, "i") == Ok(8))
|
||||
and (get(dict, "j") == Ok(9))
|
||||
and (get(dict, "k") == Ok(10))
|
||||
and (get(dict, "l") == Ok(11))
|
||||
|
||||
# Force rehash.
|
||||
expect
|
||||
|
@ -1197,18 +1197,18 @@ expect
|
|||
|> insert("m", 12)
|
||||
|
||||
(get(dict, "a") == Ok(0))
|
||||
&& (get(dict, "b") == Ok(1))
|
||||
&& (get(dict, "c") == Ok(2))
|
||||
&& (get(dict, "d") == Ok(3))
|
||||
&& (get(dict, "e") == Ok(4))
|
||||
&& (get(dict, "f") == Ok(5))
|
||||
&& (get(dict, "g") == Ok(6))
|
||||
&& (get(dict, "h") == Ok(7))
|
||||
&& (get(dict, "i") == Ok(8))
|
||||
&& (get(dict, "j") == Ok(9))
|
||||
&& (get(dict, "k") == Ok(10))
|
||||
&& (get(dict, "l") == Ok(11))
|
||||
&& (get(dict, "m") == Ok(12))
|
||||
and (get(dict, "b") == Ok(1))
|
||||
and (get(dict, "c") == Ok(2))
|
||||
and (get(dict, "d") == Ok(3))
|
||||
and (get(dict, "e") == Ok(4))
|
||||
and (get(dict, "f") == Ok(5))
|
||||
and (get(dict, "g") == Ok(6))
|
||||
and (get(dict, "h") == Ok(7))
|
||||
and (get(dict, "i") == Ok(8))
|
||||
and (get(dict, "j") == Ok(9))
|
||||
and (get(dict, "k") == Ok(10))
|
||||
and (get(dict, "l") == Ok(11))
|
||||
and (get(dict, "m") == Ok(12))
|
||||
|
||||
expect
|
||||
empty({})
|
||||
|
@ -1266,7 +1266,7 @@ expect
|
|||
bad_keys,
|
||||
Bool.true,
|
||||
|acc, k|
|
||||
acc && Dict.contains(dict, k),
|
||||
acc and Dict.contains(dict, k),
|
||||
)
|
||||
|
||||
all_inserted_correctly
|
||||
|
|
|
@ -1361,7 +1361,7 @@ split_last = |list, delimiter|
|
|||
## result is an empty list.
|
||||
chunks_of : List a, U64 -> List (List a)
|
||||
chunks_of = |list, chunk_size|
|
||||
if chunk_size == 0 || List.is_empty(list) then
|
||||
if chunk_size == 0 or List.is_empty(list) then
|
||||
[]
|
||||
else
|
||||
chunk_capacity = Num.div_ceil(List.len(list), chunk_size)
|
||||
|
|
|
@ -619,9 +619,9 @@ is_gte : Num a, Num a -> Bool
|
|||
## is [defined to be unordered](https://en.wikipedia.org/wiki/NaN#Comparison_with_NaN).)
|
||||
is_approx_eq : Frac a, Frac a, { rtol ?? Frac a, atol ?? Frac a } -> Bool
|
||||
is_approx_eq = |x, y, { rtol ?? 0.00001, atol ?? 0.00000001 }|
|
||||
eq = x <= y && x >= y
|
||||
eq = x <= y and x >= y
|
||||
meets_tolerance = Num.abs_diff(x, y) <= Num.max(atol, (rtol * Num.max(Num.abs(x), Num.abs(y))))
|
||||
eq || meets_tolerance
|
||||
eq or meets_tolerance
|
||||
|
||||
## Returns `Bool.true` if the number is `0`, and `Bool.false` otherwise.
|
||||
is_zero : Num a -> Bool
|
||||
|
|
|
@ -972,7 +972,7 @@ matches_at_help = |state|
|
|||
},
|
||||
)
|
||||
|
||||
does_this_match && does_rest_match
|
||||
does_this_match and does_rest_match
|
||||
|
||||
## Walks over the `UTF-8` bytes of the given [Str] and calls a function to update
|
||||
## state for each byte. The index for that byte in the string is provided
|
||||
|
|
|
@ -212,8 +212,6 @@ map_symbol_to_lowlevel_and_arity! {
|
|||
|
||||
Eq; BOOL_STRUCTURAL_EQ; 2,
|
||||
NotEq; BOOL_STRUCTURAL_NOT_EQ; 2,
|
||||
And; BOOL_AND; 2,
|
||||
Or; BOOL_OR; 2,
|
||||
Not; BOOL_NOT; 1,
|
||||
BoxExpr; BOX_BOX_FUNCTION; 1,
|
||||
UnboxExpr; BOX_UNBOX; 1,
|
||||
|
|
|
@ -4,7 +4,6 @@ use crate::env::Env;
|
|||
use crate::scope::Scope;
|
||||
use bumpalo::collections::Vec;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::called_via::BinOp::{DoubleQuestion, Pizza, SingleQuestion};
|
||||
use roc_module::called_via::{BinOp, CalledVia};
|
||||
use roc_module::ident::ModuleName;
|
||||
use roc_parse::ast::Expr::{self, *};
|
||||
|
@ -36,7 +35,7 @@ fn new_op_call_expr<'a>(
|
|||
|
||||
let value = match loc_op.value {
|
||||
// Rewrite the Pizza operator into an Apply
|
||||
Pizza => {
|
||||
BinOp::Pizza => {
|
||||
// Allow `left |> try (optional)` to desugar to `try left (optional)`
|
||||
let right_without_spaces = without_spaces(&right.value);
|
||||
match right_without_spaces {
|
||||
|
@ -190,7 +189,7 @@ fn new_op_call_expr<'a>(
|
|||
|
||||
let args = args.into_bump_slice();
|
||||
|
||||
Apply(function, args, CalledVia::BinOp(Pizza))
|
||||
Apply(function, args, CalledVia::BinOp(BinOp::Pizza))
|
||||
}
|
||||
PncApply(function, arguments) => {
|
||||
let mut args = Vec::with_capacity_in(1 + arguments.len(), env.arena);
|
||||
|
@ -200,16 +199,20 @@ fn new_op_call_expr<'a>(
|
|||
|
||||
let args = args.into_bump_slice();
|
||||
|
||||
Apply(function, args, CalledVia::BinOp(Pizza))
|
||||
Apply(function, args, CalledVia::BinOp(BinOp::Pizza))
|
||||
}
|
||||
Dbg => *desugar_dbg_expr(env, scope, left, region),
|
||||
_ => {
|
||||
// e.g. `1 |> (if b then (\a -> a) else (\c -> c))`
|
||||
Apply(right, env.arena.alloc([left]), CalledVia::BinOp(Pizza))
|
||||
Apply(
|
||||
right,
|
||||
env.arena.alloc([left]),
|
||||
CalledVia::BinOp(BinOp::Pizza),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
DoubleQuestion => {
|
||||
BinOp::DoubleQuestion => {
|
||||
let left = desugar_expr(env, scope, left);
|
||||
let right = desugar_expr(env, scope, right);
|
||||
|
||||
|
@ -259,7 +262,7 @@ fn new_op_call_expr<'a>(
|
|||
|
||||
When(left, &*env.arena.alloc([ok_branch, err_branch]))
|
||||
}
|
||||
SingleQuestion => {
|
||||
BinOp::SingleQuestion => {
|
||||
let left = desugar_expr(env, scope, left);
|
||||
let right = desugar_expr(env, scope, right);
|
||||
|
||||
|
@ -340,6 +343,41 @@ fn new_op_call_expr<'a>(
|
|||
|
||||
When(left, &*env.arena.alloc([ok_branch, err_branch]))
|
||||
}
|
||||
BinOp::And => {
|
||||
let left = desugar_expr(env, scope, left);
|
||||
let right = desugar_expr(env, scope, right);
|
||||
|
||||
Expr::If {
|
||||
if_thens: env.arena.alloc([(*left, *right)]),
|
||||
final_else: env.arena.alloc(Loc::at(
|
||||
right.region,
|
||||
Expr::Var {
|
||||
module_name: ModuleName::BOOL,
|
||||
ident: "false",
|
||||
},
|
||||
)),
|
||||
indented_else: false,
|
||||
}
|
||||
}
|
||||
BinOp::Or => {
|
||||
let left = desugar_expr(env, scope, left);
|
||||
let right = desugar_expr(env, scope, right);
|
||||
|
||||
Expr::If {
|
||||
if_thens: env.arena.alloc([(
|
||||
*left,
|
||||
Loc::at(
|
||||
right.region,
|
||||
Expr::Var {
|
||||
module_name: ModuleName::BOOL,
|
||||
ident: "true",
|
||||
},
|
||||
),
|
||||
)]),
|
||||
final_else: right,
|
||||
indented_else: false,
|
||||
}
|
||||
}
|
||||
binop => {
|
||||
let left = desugar_expr(env, scope, left);
|
||||
let right = desugar_expr(env, scope, right);
|
||||
|
@ -1641,8 +1679,8 @@ fn binop_to_function(binop: BinOp) -> (&'static str, &'static str) {
|
|||
GreaterThan => (ModuleName::NUM, "is_gt"),
|
||||
LessThanOrEq => (ModuleName::NUM, "is_lte"),
|
||||
GreaterThanOrEq => (ModuleName::NUM, "is_gte"),
|
||||
And => (ModuleName::BOOL, "and"),
|
||||
Or => (ModuleName::BOOL, "or"),
|
||||
And => unreachable!("Cannot desugar the `and` operator"),
|
||||
Or => unreachable!("Cannot desugar the `or` operator"),
|
||||
Pizza => unreachable!("Cannot desugar the |> operator"),
|
||||
DoubleQuestion => unreachable!("Cannot desugar the ?? operator"),
|
||||
SingleQuestion => unreachable!("Cannot desugar the ? operator"),
|
||||
|
|
|
@ -959,8 +959,8 @@ fn push_op(buf: &mut Buf, op: BinOp) {
|
|||
called_via::BinOp::GreaterThan => buf.push('>'),
|
||||
called_via::BinOp::LessThanOrEq => buf.push_str("<="),
|
||||
called_via::BinOp::GreaterThanOrEq => buf.push_str(">="),
|
||||
called_via::BinOp::And => buf.push_str("&&"),
|
||||
called_via::BinOp::Or => buf.push_str("||"),
|
||||
called_via::BinOp::Or => buf.push_str("or"),
|
||||
called_via::BinOp::And => buf.push_str("and"),
|
||||
called_via::BinOp::Pizza => buf.push_str("|>"),
|
||||
called_via::BinOp::DoubleQuestion => buf.push_str("??"),
|
||||
called_via::BinOp::SingleQuestion => buf.push_str("?"),
|
||||
|
|
|
@ -1268,20 +1268,6 @@ trait Backend<'a> {
|
|||
internal_error!("bitwise xor on a non-integer")
|
||||
}
|
||||
}
|
||||
LowLevel::And => {
|
||||
if let LayoutRepr::Builtin(Builtin::Bool) = self.interner().get_repr(*ret_layout) {
|
||||
self.build_int_bitwise_and(sym, &args[0], &args[1], IntWidth::U8)
|
||||
} else {
|
||||
internal_error!("bitwise and on a non-integer")
|
||||
}
|
||||
}
|
||||
LowLevel::Or => {
|
||||
if let LayoutRepr::Builtin(Builtin::Bool) = self.interner().get_repr(*ret_layout) {
|
||||
self.build_int_bitwise_or(sym, &args[0], &args[1], IntWidth::U8)
|
||||
} else {
|
||||
internal_error!("bitwise or on a non-integer")
|
||||
}
|
||||
}
|
||||
LowLevel::NumShiftLeftBy => {
|
||||
if let LayoutRepr::Builtin(Builtin::Int(int_width)) =
|
||||
self.interner().get_repr(*ret_layout)
|
||||
|
|
|
@ -1284,30 +1284,6 @@ pub(crate) fn run_low_level<'a, 'ctx>(
|
|||
rhs_layout,
|
||||
)
|
||||
}
|
||||
And => {
|
||||
// The (&&) operator
|
||||
arguments!(lhs_arg, rhs_arg);
|
||||
|
||||
let bool_val = env.builder.new_build_and(
|
||||
lhs_arg.into_int_value(),
|
||||
rhs_arg.into_int_value(),
|
||||
"bool_and",
|
||||
);
|
||||
|
||||
BasicValueEnum::IntValue(bool_val)
|
||||
}
|
||||
Or => {
|
||||
// The (||) operator
|
||||
arguments!(lhs_arg, rhs_arg);
|
||||
|
||||
let bool_val = env.builder.new_build_or(
|
||||
lhs_arg.into_int_value(),
|
||||
rhs_arg.into_int_value(),
|
||||
"bool_or",
|
||||
);
|
||||
|
||||
BasicValueEnum::IntValue(bool_val)
|
||||
}
|
||||
Not => {
|
||||
// The (!) operator
|
||||
arguments!(arg);
|
||||
|
|
|
@ -2163,14 +2163,6 @@ impl<'a> LowLevelCall<'a> {
|
|||
NumF64ToParts => self.load_args_and_call_zig(backend, bitcode::NUM_F64_TO_PARTS),
|
||||
NumF32FromParts => self.load_args_and_call_zig(backend, bitcode::NUM_F32_FROM_PARTS),
|
||||
NumF64FromParts => self.load_args_and_call_zig(backend, bitcode::NUM_F64_FROM_PARTS),
|
||||
And => {
|
||||
self.load_args(backend);
|
||||
backend.code_builder.i32_and();
|
||||
}
|
||||
Or => {
|
||||
self.load_args(backend);
|
||||
backend.code_builder.i32_or();
|
||||
}
|
||||
Not => {
|
||||
self.load_args(backend);
|
||||
backend.code_builder.i32_eqz();
|
||||
|
|
|
@ -6036,7 +6036,7 @@ All branches in an `if` must have the same type!
|
|||
double_binop,
|
||||
indoc!(
|
||||
r"
|
||||
key >= 97 && <= 122
|
||||
key >= 97 and <= 122
|
||||
"
|
||||
),
|
||||
@r"
|
||||
|
|
|
@ -62,8 +62,8 @@ const DISPLAY_STRINGS: [(BinOp, &str); 18] = [
|
|||
(GreaterThan, ">"),
|
||||
(LessThanOrEq, "<="),
|
||||
(GreaterThanOrEq, ">="),
|
||||
(And, "&&"),
|
||||
(Or, "||"),
|
||||
(And, "and"),
|
||||
(Or, "or"),
|
||||
];
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
|
@ -199,7 +199,7 @@ pub enum Associativity {
|
|||
/// right-associative operators:
|
||||
///
|
||||
/// exponentiation: ^
|
||||
/// boolean: && ||
|
||||
/// boolean: and or
|
||||
/// application: <|
|
||||
RightAssociative,
|
||||
|
||||
|
|
|
@ -109,8 +109,6 @@ pub enum LowLevel {
|
|||
NumF64FromParts,
|
||||
Eq,
|
||||
NotEq,
|
||||
And,
|
||||
Or,
|
||||
Not,
|
||||
Hash,
|
||||
PtrCast,
|
||||
|
@ -343,8 +341,6 @@ map_symbol_to_lowlevel! {
|
|||
NumF64FromParts <= NUM_F64_FROM_PARTS;
|
||||
Eq <= BOOL_STRUCTURAL_EQ;
|
||||
NotEq <= BOOL_STRUCTURAL_NOT_EQ;
|
||||
And <= BOOL_AND;
|
||||
Or <= BOOL_OR;
|
||||
Not <= BOOL_NOT;
|
||||
Unreachable <= LIST_UNREACHABLE;
|
||||
DictPseudoSeed <= DICT_PSEUDO_SEED;
|
||||
|
|
|
@ -1355,16 +1355,14 @@ define_builtins! {
|
|||
0 BOOL_BOOL: "Bool" exposed_type=true // the Bool.Bool type alias
|
||||
1 BOOL_FALSE: "false"
|
||||
2 BOOL_TRUE: "true"
|
||||
3 BOOL_AND: "and"
|
||||
4 BOOL_OR: "or"
|
||||
5 BOOL_NOT: "not"
|
||||
6 BOOL_XOR: "xor"
|
||||
7 BOOL_NEQ: "is_not_eq"
|
||||
8 BOOL_EQ: "Eq" exposed_type=true
|
||||
9 BOOL_IS_EQ: "is_eq"
|
||||
10 BOOL_IS_EQ_IMPL: "bool_is_eq"
|
||||
unexposed 11 BOOL_STRUCTURAL_EQ: "structural_eq"
|
||||
unexposed 12 BOOL_STRUCTURAL_NOT_EQ: "structural_not_eq"
|
||||
3 BOOL_NOT: "not"
|
||||
4 BOOL_XOR: "xor"
|
||||
5 BOOL_NEQ: "is_not_eq"
|
||||
6 BOOL_EQ: "Eq" exposed_type=true
|
||||
7 BOOL_IS_EQ: "is_eq"
|
||||
8 BOOL_IS_EQ_IMPL: "bool_is_eq"
|
||||
unexposed 9 BOOL_STRUCTURAL_EQ: "structural_eq"
|
||||
unexposed 10 BOOL_STRUCTURAL_NOT_EQ: "structural_not_eq"
|
||||
}
|
||||
5 STR: "Str" => {
|
||||
0 STR_STR: "Str" exposed_apply_type=true // the Str.Str type alias
|
||||
|
|
|
@ -1562,7 +1562,7 @@ fn low_level_no_rc(lowlevel: &LowLevel) -> RC {
|
|||
|
||||
Eq | NotEq => RC::NoRc,
|
||||
|
||||
And | Or | NumAdd | NumAddWrap | NumAddChecked | NumAddSaturated | NumSub | NumSubWrap
|
||||
NumAdd | NumAddWrap | NumAddChecked | NumAddSaturated | NumSub | NumSubWrap
|
||||
| NumSubChecked | NumSubSaturated | NumMul | NumMulWrap | NumMulSaturated
|
||||
| NumMulChecked | NumGt | NumGte | NumLt | NumLte | NumCompare | NumDivFrac
|
||||
| NumDivTruncUnchecked | NumDivCeilUnchecked | NumRemUnchecked | NumIsMultipleOf
|
||||
|
|
|
@ -1261,7 +1261,7 @@ pub(crate) fn lowlevel_borrow_signature(op: LowLevel) -> &'static [Ownership] {
|
|||
|
||||
Eq | NotEq => &[BORROWED, BORROWED],
|
||||
|
||||
And | Or | NumAdd | NumAddWrap | NumAddChecked | NumAddSaturated | NumSub | NumSubWrap
|
||||
NumAdd | NumAddWrap | NumAddChecked | NumAddSaturated | NumSub | NumSubWrap
|
||||
| NumSubChecked | NumSubSaturated | NumMul | NumMulWrap | NumMulSaturated
|
||||
| NumMulChecked | NumGt | NumGte | NumLt | NumLte | NumCompare | NumDivFrac
|
||||
| NumDivTruncUnchecked | NumDivCeilUnchecked | NumRemUnchecked | NumIsMultipleOf
|
||||
|
|
|
@ -738,7 +738,7 @@ fn parse_stmt_operator_chain<'a>(
|
|||
| Expr::Apply(
|
||||
Loc {
|
||||
region: _,
|
||||
value: Expr::Tag(..)
|
||||
value: Expr::Tag(_)
|
||||
},
|
||||
&[],
|
||||
_
|
||||
|
@ -752,7 +752,7 @@ fn parse_stmt_operator_chain<'a>(
|
|||
// try an operator
|
||||
return parse_stmt_after_apply(
|
||||
arena,
|
||||
state.clone(),
|
||||
state,
|
||||
min_indent,
|
||||
call_min_indent,
|
||||
expr_state,
|
||||
|
@ -1934,43 +1934,6 @@ fn parse_stmt_after_apply<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
// #[allow(clippy::too_many_arguments)]
|
||||
// fn parse_expr_after_apply<'a>(
|
||||
// arena: &'a Bump,
|
||||
// state: State<'a>,
|
||||
// min_indent: u32,
|
||||
// call_min_indent: u32,
|
||||
// check_for_arrow: CheckForArrow,
|
||||
// check_for_defs: bool,
|
||||
// mut expr_state: ExprState<'a>,
|
||||
// before_op: State<'a>,
|
||||
// initial_state: State<'a>,
|
||||
// ) -> Result<(Progress, Expr<'a>, State<'a>), (Progress, EExpr<'a>)> {
|
||||
// match loc(bin_op(check_for_defs)).parse(arena, state.clone(), call_min_indent) {
|
||||
// Err((MadeProgress, f)) => Err((MadeProgress, f)),
|
||||
// Ok((_, loc_op, state)) => {
|
||||
// expr_state.consume_spaces(arena);
|
||||
// let initial_state = before_op;
|
||||
// parse_expr_operator(
|
||||
// arena,
|
||||
// state,
|
||||
// min_indent,
|
||||
// call_min_indent,
|
||||
// options,
|
||||
// check_for_defs,
|
||||
// expr_state,
|
||||
// loc_op,
|
||||
// initial_state,
|
||||
// )
|
||||
// }
|
||||
// Err((NoProgress, _)) => {
|
||||
// let expr = parse_expr_final(expr_state, arena);
|
||||
// // roll back space parsing
|
||||
// Ok((MadeProgress, expr, initial_state))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn parse_apply_arg<'a>(
|
||||
arena: &'a Bump,
|
||||
|
@ -4069,6 +4032,24 @@ where
|
|||
G: Fn(&'a str, Position) -> E,
|
||||
E: 'a,
|
||||
{
|
||||
match state.bytes() {
|
||||
&[b'o', b'r', ..] => {
|
||||
return Ok((
|
||||
MadeProgress,
|
||||
OperatorOrDef::BinOp(BinOp::Or),
|
||||
state.advance(2),
|
||||
))
|
||||
}
|
||||
&[b'a', b'n', b'd', ..] => {
|
||||
return Ok((
|
||||
MadeProgress,
|
||||
OperatorOrDef::BinOp(BinOp::And),
|
||||
state.advance(3),
|
||||
))
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let chomped = chomp_ops(state.bytes());
|
||||
|
||||
macro_rules! good {
|
||||
|
|
|
@ -10,6 +10,8 @@ pub const IMPORT: &str = "import";
|
|||
pub const EXPECT: &str = "expect";
|
||||
pub const RETURN: &str = "return";
|
||||
pub const CRASH: &str = "crash";
|
||||
pub const AND: &str = "and";
|
||||
pub const OR: &str = "or";
|
||||
|
||||
// These keywords are valid in imports
|
||||
pub const EXPOSING: &str = "exposing";
|
||||
|
@ -21,8 +23,8 @@ pub const WHERE: &str = "where";
|
|||
// These keywords are valid in headers
|
||||
pub const PLATFORM: &str = "platform";
|
||||
|
||||
pub const KEYWORDS: [&str; 11] = [
|
||||
IF, THEN, ELSE, WHEN, AS, IS, DBG, IMPORT, EXPECT, RETURN, CRASH,
|
||||
pub const KEYWORDS: [&str; 13] = [
|
||||
IF, THEN, ELSE, WHEN, AS, IS, DBG, IMPORT, EXPECT, RETURN, CRASH, AND, OR,
|
||||
];
|
||||
|
||||
pub fn is_allowed_identifier(mut ident: &str) -> bool {
|
||||
|
|
|
@ -2095,13 +2095,13 @@ mod eq {
|
|||
|
||||
LyingEq := U8 implements [Eq {is_eq}]
|
||||
|
||||
is_eq = \@LyingEq m, @LyingEq n -> m != n
|
||||
is_eq = \@LyingEq(m), @LyingEq(n) -> m != n
|
||||
|
||||
main =
|
||||
a = @LyingEq 10
|
||||
b = @LyingEq 5
|
||||
c = @LyingEq 5
|
||||
if Bool.is_eq a b && !(Bool.is_eq b c) then
|
||||
a = @LyingEq(10)
|
||||
b = @LyingEq(5)
|
||||
c = @LyingEq(5)
|
||||
if Bool.is_eq(a, b) and !(Bool.is_eq(b, c)) then
|
||||
"okay"
|
||||
else
|
||||
"fail"
|
||||
|
|
|
@ -121,7 +121,7 @@ fn bool_logic() {
|
|||
bool2 = Bool.false
|
||||
bool3 = !bool1
|
||||
|
||||
(bool1 && bool2) || bool2 && bool3
|
||||
(bool1 and bool2) or bool2 and bool3
|
||||
"#
|
||||
),
|
||||
false,
|
||||
|
@ -132,19 +132,19 @@ fn bool_logic() {
|
|||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn and_bool() {
|
||||
assert_evals_to!("Bool.true && Bool.true", true, bool);
|
||||
assert_evals_to!("Bool.true && Bool.false", false, bool);
|
||||
assert_evals_to!("Bool.false && Bool.true", false, bool);
|
||||
assert_evals_to!("Bool.false && Bool.false", false, bool);
|
||||
assert_evals_to!("Bool.true and Bool.true", true, bool);
|
||||
assert_evals_to!("Bool.true and Bool.false", false, bool);
|
||||
assert_evals_to!("Bool.false and Bool.true", false, bool);
|
||||
assert_evals_to!("Bool.false and Bool.false", false, bool);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn or_bool() {
|
||||
assert_evals_to!("Bool.true || Bool.true", true, bool);
|
||||
assert_evals_to!("Bool.true || Bool.false", true, bool);
|
||||
assert_evals_to!("Bool.false || Bool.true", true, bool);
|
||||
assert_evals_to!("Bool.false || Bool.false", false, bool);
|
||||
assert_evals_to!("Bool.true or Bool.true", true, bool);
|
||||
assert_evals_to!("Bool.true or Bool.false", true, bool);
|
||||
assert_evals_to!("Bool.false or Bool.true", true, bool);
|
||||
assert_evals_to!("Bool.false or Bool.false", false, bool);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -544,7 +544,7 @@ fn eq_different_rosetrees() {
|
|||
|
||||
cd = c2 == d2
|
||||
|
||||
ab && cd
|
||||
ab and cd
|
||||
"#
|
||||
),
|
||||
true,
|
||||
|
|
|
@ -158,19 +158,19 @@ fn even_odd() {
|
|||
assert_evals_to!(
|
||||
indoc!(
|
||||
r"
|
||||
even = \n ->
|
||||
even = |n|
|
||||
when n is
|
||||
0 -> Bool.true
|
||||
1 -> Bool.false
|
||||
_ -> odd (n - 1)
|
||||
_ -> odd(n - 1)
|
||||
|
||||
odd = \n ->
|
||||
odd = |n|
|
||||
when n is
|
||||
0 -> Bool.false
|
||||
1 -> Bool.true
|
||||
_ -> even (n - 1)
|
||||
_ -> even(n - 1)
|
||||
|
||||
odd 5 && even 42
|
||||
odd(5) and even(42)
|
||||
"
|
||||
),
|
||||
true,
|
||||
|
@ -2315,12 +2315,12 @@ fn recursive_tag_id_in_allocation_eq() {
|
|||
]
|
||||
|
||||
x : Value
|
||||
x = G 42
|
||||
x = G(42)
|
||||
|
||||
y : Value
|
||||
y = H 42
|
||||
y = H(42)
|
||||
|
||||
main = (x == x) && (x != y) && (y == y)
|
||||
main = x == x and x != y and y == y
|
||||
"#
|
||||
),
|
||||
true,
|
||||
|
|
|
@ -2460,7 +2460,7 @@ fn issue_4557() {
|
|||
app "test" provides [main] to "./platform"
|
||||
|
||||
is_eq_q = \q1, q2 -> when T q1 q2 is
|
||||
T (U f1) (U f2) -> Bool.or (is_eq_q (U f2) (U f1)) (f1 {} == f2 {})
|
||||
T (U f1) (U f2) -> (is_eq_q (U f2) (U f1)) or (f1 {} == f2 {})
|
||||
|
||||
main = is_eq_q (U \{} -> "a") (U \{} -> "a")
|
||||
"#
|
||||
|
|
|
@ -2,11 +2,11 @@ app "test" provides [main] to "./platform"
|
|||
|
||||
main =
|
||||
s1 : Set U8
|
||||
s1 = Set.empty {}
|
||||
s1 = Set.empty({})
|
||||
|
||||
s2 : Set Str
|
||||
s2 = Set.empty {}
|
||||
s2 = Set.empty({})
|
||||
|
||||
Bool.is_eq s1 s1 && Bool.is_eq s2 s2
|
||||
# ^^^^^^^^^^ Set#Bool.is_eq(31): Set Str, Set Str -[[Set.is_eq(31)]]-> Bool
|
||||
Bool.is_eq(s1, s1) and Bool.is_eq(s2, s2)
|
||||
# ^^^^^^^^^^ Set#Bool.is_eq(31): Set Str, Set Str -[[Set.is_eq(31)]]-> Bool
|
||||
# ^^^^^^^^^^ Set#Bool.is_eq(31): Set U8, Set U8 -[[Set.is_eq(31)]]-> Bool
|
||||
|
|
|
@ -1797,7 +1797,7 @@ generate_derive_str = \buf, types, type, include_debug ->
|
|||
|
||||
can_support_eq_hash_ord : Types, Shape -> Bool
|
||||
can_support_eq_hash_ord = \types, type ->
|
||||
!(has_float(types, type)) && (can_support_partial_eq_ord(types, type))
|
||||
!(has_float(types, type)) and (can_support_partial_eq_ord(types, type))
|
||||
|
||||
can_support_partial_eq_ord : Types, Shape -> Bool
|
||||
can_support_partial_eq_ord = \types, type ->
|
||||
|
@ -1817,7 +1817,7 @@ can_support_partial_eq_ord = \types, type ->
|
|||
k_type = Types.shape(types, k)
|
||||
v_type = Types.shape(types, v)
|
||||
|
||||
can_support_partial_eq_ord(types, k_type) && can_support_partial_eq_ord(types, v_type)
|
||||
can_support_partial_eq_ord(types, k_type) and can_support_partial_eq_ord(types, v_type)
|
||||
|
||||
TagUnion(Recursive({ tags })) ->
|
||||
List.all(tags, \{ payload } ->
|
||||
|
@ -1854,7 +1854,7 @@ can_support_partial_eq_ord = \types, type ->
|
|||
ok_shape = Types.shape(types, ok_id)
|
||||
err_shape = Types.shape(types, err_id)
|
||||
|
||||
can_support_partial_eq_ord(types, ok_shape) && can_support_partial_eq_ord(types, err_shape)
|
||||
can_support_partial_eq_ord(types, ok_shape) and can_support_partial_eq_ord(types, err_shape)
|
||||
|
||||
Struct({ fields: HasNoClosure(fields) }) | TagUnionPayload({ fields: HasNoClosure(fields) }) ->
|
||||
List.all(fields, \{ id } -> can_support_partial_eq_ord(types, Types.shape(types, id)))
|
||||
|
@ -1891,7 +1891,7 @@ can_derive_copy = \types, type ->
|
|||
|
||||
RocResult(ok_id, err_id) ->
|
||||
can_derive_copy(types, Types.shape(types, ok_id))
|
||||
&& can_derive_copy(types, Types.shape(types, err_id))
|
||||
and can_derive_copy(types, Types.shape(types, err_id))
|
||||
|
||||
Struct({ fields: HasNoClosure(fields) }) | TagUnionPayload({ fields: HasNoClosure(fields) }) ->
|
||||
List.all(fields, \{ id } -> can_derive_copy(types, Types.shape(types, id)))
|
||||
|
@ -1909,7 +1909,7 @@ cannot_support_default = \types, type ->
|
|||
TagUnionPayload({ fields: HasClosure(_) }) -> Bool.true
|
||||
RocDict(key_id, val_id) ->
|
||||
cannot_support_copy(types, Types.shape(types, key_id))
|
||||
|| cannot_support_copy(types, Types.shape(types, val_id))
|
||||
or cannot_support_copy(types, Types.shape(types, val_id))
|
||||
|
||||
Struct({ fields: HasClosure(_) }) -> Bool.true
|
||||
Struct({ fields: HasNoClosure(fields) }) | TagUnionPayload({ fields: HasNoClosure(fields) }) ->
|
||||
|
@ -1934,7 +1934,7 @@ has_float_help = \types, type, do_not_recurse ->
|
|||
|
||||
RocDict(id0, id1) | RocResult(id0, id1) ->
|
||||
has_float_help(types, Types.shape(types, id0), do_not_recurse)
|
||||
|| has_float_help(types, Types.shape(types, id1), do_not_recurse)
|
||||
or has_float_help(types, Types.shape(types, id1), do_not_recurse)
|
||||
|
||||
Struct({ fields: HasNoClosure(fields) }) | TagUnionPayload({ fields: HasNoClosure(fields) }) ->
|
||||
List.any(fields, \{ id } -> has_float_help(types, Types.shape(types, id), do_not_recurse))
|
||||
|
@ -2160,7 +2160,7 @@ contains_refcounted_help = \types, type, do_not_recurse ->
|
|||
|
||||
RocResult(id0, id1) ->
|
||||
contains_refcounted_help(types, Types.shape(types, id0), do_not_recurse)
|
||||
|| contains_refcounted_help(types, Types.shape(types, id1), do_not_recurse)
|
||||
or contains_refcounted_help(types, Types.shape(types, id1), do_not_recurse)
|
||||
|
||||
Struct({ fields: HasNoClosure(fields) }) | TagUnionPayload({ fields: HasNoClosure(fields) }) ->
|
||||
List.any(fields, \{ id } -> contains_refcounted_help(types, Types.shape(types, id), do_not_recurse))
|
||||
|
|
|
@ -247,8 +247,6 @@ fn to_expr_report<'a>(
|
|||
let suggestion = match *op {
|
||||
"|" => vec![
|
||||
alloc.reflow("Maybe you want "),
|
||||
alloc.parser_suggestion("||"),
|
||||
alloc.reflow(" or "),
|
||||
alloc.parser_suggestion("|>"),
|
||||
alloc.reflow(" instead?"),
|
||||
],
|
||||
|
|
|
@ -73,7 +73,7 @@ tokens_to_str : List Token -> Str
|
|||
tokens_to_str = \tokens ->
|
||||
List.walk(tokens, "", \buf, token ->
|
||||
buf_with_space =
|
||||
if Str.is_empty(buf) || token == Literal(",") then
|
||||
if Str.is_empty(buf) or token == Literal(",") then
|
||||
buf
|
||||
else
|
||||
Str.concat(buf, " ")
|
||||
|
|
|
@ -242,14 +242,14 @@ fromU8 = \r, g, b, a -> @Color (RgbaU8 r g b a)
|
|||
|
||||
fromI16 : I16, I16, I16, I16 -> Result Color [OutOfRange]
|
||||
fromI16 = \r, g, b, a ->
|
||||
if r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255 || a < 0 || a > 255 then
|
||||
if r < 0 or r > 255 or g < 0 or g > 255 or b < 0 or b > 255 or a < 0 or a > 255 then
|
||||
Err OutOfRange
|
||||
else
|
||||
Ok (@Color (RgbaU8 (Num.toU8 r) (Num.toU8 g) (Num.toU8 b) (Num.toU8 a)))
|
||||
|
||||
fromF32 : F32, F32, F32, F32 -> Result Color [OutOfRange]
|
||||
fromF32 = \r, g, b, a ->
|
||||
if r < 0.0 || r > 1.0 || g < 0.0 || g > 1.0 || b < 0.0 || b > 1.0 || a < 0.0 || a > 1.0 then
|
||||
if r < 0.0 or r > 1.0 or g < 0.0 or g > 1.0 or b < 0.0 or b > 1.0 or a < 0.0 or a > 1.0 then
|
||||
Err OutOfRange
|
||||
else
|
||||
Ok (@Color (RgbaF32 r g b a))
|
||||
|
|
|
@ -359,8 +359,8 @@ As a historical note, these stylistic benefits (of `|> Num.sub 1` working as exp
|
|||
### [Currying and learning curve](#curried-learning-curve) {#curried-learning-curve}
|
||||
|
||||
Currying leads to function signatures that look surprising to beginners. For example, in Roc, the
|
||||
[`Bool.and`](https://www.roc-lang.org/builtins/Bool#and) function has the type `Bool, Bool -> Bool`. If Roc were a
|
||||
curried language, this function would instead have the type `Bool -> Bool -> Bool`. Since no mainstream programming
|
||||
[`Str.concat`](https://www.roc-lang.org/builtins/Str#concat) function has the type `Str, Str -> Str`. If Roc were a
|
||||
curried language, this function would instead have the type `Str -> Str -> Str`. Since no mainstream programming
|
||||
languages today are curried, anyone who knows a mainstream language and is learning their first curried language will
|
||||
require additional explanation about why function types look this way.
|
||||
|
||||
|
|
|
@ -640,7 +640,7 @@ We refer to whatever comes before a `->` in a `when` expression as a _pattern_
|
|||
|
||||
In many programming languages, `true` and `false` are special language keywords that refer to the two [boolean](https://en.wikipedia.org/wiki/Boolean_data_type) values. In Roc, booleans do not get special keywords; instead, they are exposed as the ordinary values `Bool.true` and `Bool.false`.
|
||||
|
||||
This design is partly to keep the number of special keywords in the language smaller, but mainly to suggest how booleans are intended to be used in Roc: for [_boolean logic_](https://en.wikipedia.org/wiki/Boolean_algebra) (`&&`, `||`, and so on) as opposed to for data modeling. Tags are the preferred choice for data modeling, and having tag values be more concise than boolean values helps make this preference clear.
|
||||
This design is partly to keep the number of special keywords in the language smaller, but mainly to suggest how booleans are intended to be used in Roc: for [_boolean logic_](https://en.wikipedia.org/wiki/Boolean_algebra) (`and`, `or`, and so on) as opposed to for data modeling. Tags are the preferred choice for data modeling, and having tag values be more concise than boolean values helps make this preference clear.
|
||||
|
||||
As an example of why tags are encouraged for data modeling, in many languages it would be common to write a record like `{ name: "Richard", isAdmin: Bool.true }`, but in Roc it would be preferable to write something like `{ name: "Richard", role: Admin }`. At first, the `role` field might only ever be set to `Admin` or `Normal`, but because the data has been modeled using tags instead of booleans, it's much easier to add other alternatives in the future, like `Guest` or `Moderator` - some of which might also want payloads.
|
||||
|
||||
|
@ -2369,22 +2369,21 @@ Here are various Roc expressions involving operators, and what they desugar to.
|
|||
|
||||
| Expression | Desugars To |
|
||||
| ---------------------------- | ---------------------------------------------------------------------------- |
|
||||
| `a + b` | `Num.add a b` |
|
||||
| `a - b` | `Num.sub a b` |
|
||||
| `a * b` | `Num.mul a b` |
|
||||
| `a / b` | `Num.div a b` |
|
||||
| `a // b` | `Num.divTrunc a b` |
|
||||
| `a ^ b` | `Num.pow a b` |
|
||||
| `a % b` | `Num.rem a b` |
|
||||
| `-a` | `Num.neg a` |
|
||||
| `a == b` | `Bool.isEq a b` |
|
||||
| `a != b` | `Bool.isNotEq a b` |
|
||||
| `a && b` | `Bool.and a b` |
|
||||
| <code>a \|\| b</code> | `Bool.or a b` |
|
||||
| `!a` | `Bool.not a` |
|
||||
| <code>a \|> f</code> | `f a` |
|
||||
| <code>f a b \|> g x y</code> | `g (f a b) x y` |
|
||||
| `f!` | [see example](https://www.roc-lang.org/examples/DesugaringAwait/README.html) |
|
||||
| `a + b` | `Num.add(a, b)` |
|
||||
| `a - b` | `Num.sub(a, b)` |
|
||||
| `a * b` | `Num.mul(a, b)` |
|
||||
| `a / b` | `Num.div(a, b)` |
|
||||
| `a // b` | `Num.div_trunc(a, b)` |
|
||||
| `a ^ b` | `Num.pow(a, b)` |
|
||||
| `a % b` | `Num.rem(a, b)` |
|
||||
| `-a` | `Num.neg(a)` |
|
||||
| `a == b` | `Bool.is_eq(a, b)` |
|
||||
| `a != b` | `Bool.is_not_eq(a, b)` |
|
||||
| `a and b` | `if a then b else Bool.false` |
|
||||
| `a or b` | `if a then Bool.true else b` |
|
||||
| `!a` | `Bool.not(a)` |
|
||||
| <code>a \|> f</code> | `f(a)` |
|
||||
| <code>f a b \|> g x y</code> | `g(f(a, b), x, y)` |
|
||||
| `f?` | [see example](https://www.roc-lang.org/examples/DesugaringTry/README.html) |
|
||||
|
||||
### [Additional Resources](#additional-resources) {#additional-resources}
|
||||
|
|
|
@ -111,7 +111,7 @@ view = \page_path_str, html_content ->
|
|||
"/index.html" -> [id("homepage-main")]
|
||||
"/tutorial.html" -> [id("tutorial-main"), class("article-layout")]
|
||||
_ ->
|
||||
if Str.starts_with(page_path_str, "/examples/") && page_path_str != "/examples/index.html" then
|
||||
if Str.starts_with(page_path_str, "/examples/") and page_path_str != "/examples/index.html" then
|
||||
# Individual examples should render wider than articles.
|
||||
# Otherwise the width is unreasonably low for the code blocks,
|
||||
# and those pages don't tend to have big paragraphs anyway.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue