Skip to content

Commit

Permalink
Merge branch 'main' into lib--option/outcome,-change-panic-messages
Browse files Browse the repository at this point in the history
  • Loading branch information
michaellilltokiwa committed Sep 9, 2024
2 parents f7e7598 + 7a42682 commit 66a8a67
Show file tree
Hide file tree
Showing 9 changed files with 158 additions and 182 deletions.
56 changes: 1 addition & 55 deletions lib/num_option.fz
Original file line number Diff line number Diff line change
Expand Up @@ -30,55 +30,10 @@
# numeric result or false for a boolean result.
#
public num_option(public T type : numeric)
: choice T nil,
: switch T nil,
monad T (num_option T)
is

# Does this option contain a value of type T?
#
public exists => (num_option.this ? T => true
| nil => false)


# short-hand postfix operator for 'exists'
#
public postfix ?? => exists


# Does this option contain no value of type T?
#
public is_nil => !exists


# short-hand postfix operator for 'is_nil'
#
public postfix !! => is_nil


# short-hand prefix operator for 'is_nil'
#
public prefix ! => is_nil


# value of an option that is known to contain a value
#
# this can only be called in cases where it is known for sure that this option
# is not nil. A runtime error will be created otherwise.
#
public val T
pre
safety: num_option.this??
=>
num_option.this ? v T => v
| nil => fuzion.std.panic "num_option.val called on nil. Enable `safety` to obtain a precondition failure for debugging."


# unwrap value or get default
#
public get (default Lazy T) =>
num_option.this ? v T => v
| nil => default


# monadic operator
public redef infix >>= (f T -> num_option T) => num_option.this.bind T f
Expand Down Expand Up @@ -138,15 +93,6 @@ is
num_option.this >>= v -> if v.sign ≥ 0 v else -?v


# converts num_option into a list of either a single element in case
# num_option.this.exists or `nil`otherwise
#
public as_list list T
=>
num_option.this ? v T => v : nil
| nil => nil


public redef as_string String =>
num_option.this ? v T => v.as_string
| nil => "--no value--"
Expand Down
63 changes: 2 additions & 61 deletions lib/option.fz
Original file line number Diff line number Diff line change
Expand Up @@ -28,51 +28,17 @@
# option represents an optional value of type T
#
public option(public T type)
: choice T nil,
monad T (option T),
Sequence T,
auto_unwrap T (try (option T)) /* NYI: BUG #3355: auto_unwrap T (try option.this) */
: switch T nil,
monad T (option T)
is

# Does this option contain a value of type T?
#
public exists => (option.this ? T => true
| nil => false)


# short-hand postfix operator for 'exists'
#
public postfix ?? => exists


# Does this option contain no value of type T?
#
public is_nil => !exists


# short-hand postfix operator for 'is_nil'
#
public postfix !! => is_nil


# short-hand prefix operator for 'is_nil'
#
public prefix ! => is_nil


# value of an option that is known to contain a value
#
# this can only be called in cases where it is known for sure that this option
# is not nil. A runtime error will be created otherwise.
#
public val T
pre
safety: option.this??
=>
option.this ? v T => v
| nil => fuzion.std.panic "option.val called on nil. Enable `safety` to obtain a precondition failure for debugging."


# monadic operator
#
# This is handy to implement functions on optional values. As an example,
Expand Down Expand Up @@ -124,18 +90,6 @@ is
| nil => $nil


# unwraps an option that is known to contain a value
#
# this can only be called in cases where it is known for sure that this option
# is not nil. A runtime error will be created otherwise.
#
public get
pre
safety: option.this??
=>
option.this ? v T => v
| nil => fuzion.std.panic "option.get called on nil. Enable `safety` to obtain a precondition failure for debugging."


# unwraps an option if it exists, returns default value otherwise.
#
Expand All @@ -145,21 +99,8 @@ is
| nil => default


# converts option into a list of either a single element in case
# option.this.exists or `nil`otherwise
#
public redef as_list list T
=>
option.this ? v T => v : nil
| nil => nil


# unwrap this option
#
public redef unwrap ! try option.this =>
option.this ? v T => v
| nil => (try option.this).env.raise (error "error unwrapping option: {option.this}")


# return function
#
Expand Down
55 changes: 2 additions & 53 deletions lib/outcome.fz
Original file line number Diff line number Diff line change
Expand Up @@ -49,59 +49,15 @@
# compatible to 'outcome data IO_Error Permission_Error', so everything
# is fine.
#
public outcome(public T type) :
choice T error, /* ... NYI: this should be open generic! */
monad T (outcome T),
auto_unwrap T (try (outcome T)) /* NYI: BUG #3355: auto_unwrap T (try outcome.this) */
public outcome(public T type) : switch T error,
monad T (outcome T)
is

# Does this outcome contain a value of type T?
#
public ok => (outcome.this ? T => true
| error => false)


# short-hand postfix operator for 'ok'
#
public postfix ?? => ok


# Does this outcome contain an error
#
public is_error => !ok


# short-hand postfix operator for 'is_error'
#
public postfix !! => is_error


# short-hand prefix operator for 'is_error'
#
public prefix ! => is_error


# value of an outcome that is known to contain a value
#
# This can only be called in cases where it is known for sure that this
# outcomee is not an error. A runtime error will be created otherwise.
#
public val T
pre
safety: outcome.this??
=>
outcome.this ? v T => v
| error => panic "outcome.val called on nil. Enable `safety` to obtain a precondition failure for debugging."


# value of an outcome or default if outcome contains err
#
public val(default T) T
=>
outcome.this ? v T => v
| error => default


# error of an outcome that is known to contain an error
#
# This can only be called in cases where it is known for sure that this
Expand Down Expand Up @@ -181,13 +137,6 @@ is
| e error => e


# unwrap this outcome
#
redef unwrap ! try outcome.this =>
outcome.this ? v T => v
| e error => (try outcome.this).env.raise e


# return function
#
public fixed redef type.return (a T) => outcome a
Expand Down
127 changes: 127 additions & 0 deletions lib/switch.fz
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# This file is part of the Fuzion language implementation.
#
# The Fuzion language implementation is free software: you can redistribute it
# and/or modify it under the terms of the GNU General Public License as published
# by the Free Software Foundation, version 3 of the License.
#
# The Fuzion language implementation is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License along with The
# Fuzion language implementation. If not, see <https://www.gnu.org/licenses/>.


# -----------------------------------------------------------------------
#
# Tokiwa Software GmbH, Germany
#
# Source code of Fuzion standard library feature switch
#
# -----------------------------------------------------------------------

# switch is the parent feature of all choices
# that encode success and failure,
# e.g. option (something/nil)
# or outcome (something/error)
#
public switch(A type, B type /* NYI: B should be open generic */) :
choice A B,
# monad A (switch A B) NYI: does not work,
auto_unwrap A (try (switch A B)), /* NYI: BUG #3355: auto_unwrap T (try switch.this) */
Sequence A
is

# NYI: CLEANUP: decide name: exists/ok, get/val?

# Does this switch contain a value of type A?
#
public exists => (switch.this ? A => true
| B => false)


# Does this switch contain a value of type A?
#
public ok => exists


# short-hand postfix operator for 'exists'
#
public postfix ?? => exists


# short-hand postfix operator for '!exists'
#
public postfix !! => !exists


# short-hand prefix operator for '!exists'
#
public prefix ! => !exists


# unwraps a switch that is known to contain a value
#
# this can only be called in cases where it is known for sure that this switch
# is not nil. A runtime error will be created otherwise.
#
public get
pre
safety: (switch.this??) # NYI: REGRESSION: parantheses currently necessary, due to PR #2572
=>
switch.this ? a A => a
| B => fuzion.std.panic "switch.get called on B. Enable `safety` to obtain a precondition failure for debugging."



# unwrap value or get default
#
public get (default Lazy A) =>
switch.this ? a A => a
| B => default


# value of a switch that is known to contain a value
#
# This can only be called in cases where it is known for sure that this
# switch is not a B. A runtime error will be created otherwise.
#
public val A
pre
safety: (switch.this??) # NYI: REGRESSION: parantheses currently necessary, due to PR #2572
=>
switch.this ? a A => a
| B => panic "switch.val called on B. Enable `safety` to obtain a precondition failure for debugging."


# value of a switch or default if switch contains B
#
public val(default A) A
=>
switch.this ? a A => a
| B => default


# converts switch into a list of either a single element in case
# switch.this.exists or `nil`otherwise
#
public redef as_list list A
=>
switch.this ? a A => a : nil
| B => nil

# unwrap this switch
#
public redef unwrap ! try switch.this =>
match switch.this
a A => a
b B => (try switch.this).env.raise (error $b)


# converts switch to a string
#
public redef as_string =>
match switch.this
a A => a.as_string
b B => b.as_string
14 changes: 12 additions & 2 deletions src/dev/flang/ast/Expr.java
Original file line number Diff line number Diff line change
Expand Up @@ -781,8 +781,7 @@ public Expr unwrap(Resolution res, Context context, AbstractType expectedType)
&& !expectedType.isAssignableFrom(t, context)
&& expectedType.compareTo(Types.resolved.t_Any) != 0
&& !t.isGenericArgument()
&& t.feature()
.inherits()
&& allInherited(t.feature())
.stream()
.anyMatch(c ->
c.calledFeature().equals(Types.resolved.f_auto_unwrap)
Expand All @@ -793,6 +792,17 @@ public Expr unwrap(Resolution res, Context context, AbstractType expectedType)
}


/**
* @param f
*
* @return the whole tree of inherited features flattened to a list.
*/
private List<AbstractCall> allInherited(AbstractFeature f)
{
return f.inherits().flatMap(x -> new List<>(x, allInherited(x.calledFeature())));
}


/**
* This expression as a compile time constant.
*/
Expand Down
Loading

0 comments on commit 66a8a67

Please sign in to comment.