mirror of
https://github.com/roc-lang/roc.git
synced 2025-11-02 22:01:20 +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
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue