Lift operators so that they can be used on options and results

This commit is contained in:
Mark Spanbroek 2021-03-07 08:56:35 +01:00
parent dfe4e3cc4b
commit 1b47843012
4 changed files with 143 additions and 0 deletions

View File

@ -31,3 +31,44 @@ template `=?`*[T](name: untyped{nkIdent}, option: ?T): bool =
template name: T {.used.} = option.unsafeGet()
option.isSome
template liftPrefix(_: type Option, operator: untyped) =
template `operator`*(a: ?typed): ?typed =
type T = type(`operator`(a.unsafeGet))
if x =? a:
`operator`(x).some
else:
T.none
template liftInfix(_: type Option, operator: untyped) =
template `operator`*(a: ?typed, b: ?typed): ?typed =
type T = type(`operator`(a.unsafeGet, b.unsafeGet))
if x =? a and y =? b:
`operator`(x, y).some
else:
T.none
template `operator`*(a: ?typed, b: typed): ?typed =
type T = type(`operator`(a.unsafeGet, b))
if x =? a:
`operator`(x, b).some
else:
T.none
Option.liftPrefix(`-`)
Option.liftPrefix(`+`)
Option.liftPrefix(`@`)
Option.liftInfix(`*`)
Option.liftInfix(`/`)
Option.liftInfix(`div`)
Option.liftInfix(`mod`)
Option.liftInfix(`shl`)
Option.liftInfix(`shr`)
Option.liftInfix(`+`)
Option.liftInfix(`-`)
Option.liftInfix(`&`)
Option.liftInfix(`<=`)
Option.liftInfix(`<`)
Option.liftInfix(`>=`)
Option.liftInfix(`>`)

View File

@ -33,3 +33,47 @@ template `|?`*[T](value: ?!T, fallback: T): T =
template `=?`*[T](name: untyped{nkIdent}, value: ?!T): bool =
template name: T {.used.} = value.unsafeGet()
value.isOk
template liftPrefix(_: type Result, operator: untyped) =
template `operator`*(a: ?!typed): ?!typed =
type T = type(`operator`(a.unsafeGet))
if x =? a:
`operator`(x).success
else:
T.failure(a.error)
template liftInfix(_: type Result, operator: untyped) =
template `operator`*(a: ?!typed, b: ?!typed): ?!typed =
type T = type(`operator`(a.unsafeGet, b.unsafeGet))
if x =? a and y =? b:
`operator`(x, y).success
elif a.isErr:
T.failure(a.error)
else:
T.failure(b.error)
template `operator`*(a: ?!typed, b: typed): ?!typed =
type T = type(`operator`(a.unsafeGet, b))
if x =? a:
`operator`(x, b).success
else:
T.failure(a.error)
Result.liftPrefix(`-`)
Result.liftPrefix(`+`)
Result.liftPrefix(`@`)
Result.liftInfix(`*`)
Result.liftInfix(`/`)
Result.liftInfix(`div`)
Result.liftInfix(`mod`)
Result.liftInfix(`shl`)
Result.liftInfix(`shr`)
Result.liftInfix(`+`)
Result.liftInfix(`-`)
Result.liftInfix(`&`)
Result.liftInfix(`<=`)
Result.liftInfix(`<`)
Result.liftInfix(`>=`)
Result.liftInfix(`>`)

View File

@ -56,3 +56,32 @@ suite "optionals":
let a = 42.some
if a =? a:
check a == 42
test "unary operator `-` works for options":
check -(-42.some) == 42.some
check -(int.none) == int.none
test "other unary operators work for options":
check +(42.some) == 42.some
check @([1, 2].some) == (@[1, 2]).some
test "binary operator `+` works for options":
check 40.some + 2.some == 42.some
check 40.some + 2 == 42.some
check int.none + 2 == int.none
check 40.some + int.none == int.none
check int.none + int.none == int.none
test "other binary operators work for options":
check 21.some * 2 == 42.some
check 84'f.some / 2'f == 42'f.some
check 84.some div 2 == 42.some
check 85.some mod 43 == 42.some
check 0b00110011.some shl 1 == 0b01100110.some
check 0b00110011.some shr 1 == 0b00011001.some
check 44.some - 2 == 42.some
check "f".some & "oo" == "foo".some
check 40.some <= 42 == true.some
check 40.some < 42 == true.some
check 40.some >= 42 == false.some
check 40.some > 42 == false.some

View File

@ -63,3 +63,32 @@ suite "result":
test "catch can be used to convert exceptions to results":
check parseInt("42").catch == 42.success
check parseInt("foo").catch.error of ValueError
test "unary operator `-` works for results":
check -(-42.success) == 42.success
check -(int.failure(error)) == int.failure(error)
test "other unary operators work for results":
check +(42.success) == 42.success
check @([1, 2].success) == (@[1, 2]).success
test "binary operator `+` works for results":
check 40.success + 2.success == 42.success
check 40.success + 2 == 42.success
check int.failure(error) + 2 == int.failure(error)
check 40.success + int.failure(error) == int.failure(error)
check int.failure(error) + int.failure(error) == int.failure(error)
test "other binary operators work for results":
check (21.success * 2 == 42.success)
check (84'f.success / 2'f == 42'f.success)
check (84.success div 2 == 42.success)
check (85.success mod 43 == 42.success)
check (0b00110011.success shl 1 == 0b01100110.success)
check (0b00110011.success shr 1 == 0b00011001.success)
check (44.success - 2 == 42.success)
check ("f".success & "oo" == "foo".success)
check (40.success <= 42 == true.success)
check (40.success < 42 == true.success)
check (40.success >= 42 == false.success)
check (40.success > 42 == false.success)