Fuzion Logo
flang.dev — The Fuzion Language Portal
JavaScript seems to be disabled. Functionality is limited.

effect.fz


# 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 effect
#
#  Author: Fridtjof Siebert (siebert@tokiwa.software)
#
# -----------------------------------------------------------------------

# effect -- abstract parent feature for effects
#
# effect provides a means to perform effectful operations.  Instances
# of effect are installed in the current environment while their code is
# executed.  The code may access the effect via <type>.env.
#
effect (
  # action to be performed, may include code to run while this effect is installed.
  #
  r effectMode.val
  )
is

  match r
    _ effectMode.plain   =>
    i effectMode.inst    => run i.f (_)->unit
    _ effectMode.repl    => replace
    _ effectMode.abort   => fuzion.std.panic "abort"
    _ effectMode.default => default
    _ effectMode.new     =>

  mode effectMode.val is
    match r
      effectMode.plain => effectMode.plain
      effectMode.inst, effectMode.repl, effectMode.abort, effectMode.default, effectMode.new => effectMode.repl

  # replace effect in the current context by this
  private replace unit is intrinsic


  # execute code provided in f.call while this effect is installed
  # in the current environment. Return immediately in case abort is
  # called.
  #
  # NYI: uses type parameter T only to simplify C backend
  #
  private abortable(T (Function unit).type, f T) unit is intrinsic

  # replace effect in the current context by this and abort current execution
  private abort void is intrinsic

  # set default effect in the current context to this if none is installed
  private default unit is intrinsic

  # execute the code of 'f' in the context of this effect
  #
  private run(R type, f () -> R, def (unit /* NYI: unit type only to distingish 'f' and 'def' in static analysis, remove once 'fz -effecs' uses DFA */)->R) R is
    res option R := nil
    cf := effect_call f
    abortable cf
    match cf.res
      nil => def(unit)
      x R => x


  # abort the current execution and return from the surrounding call to
  # abortable with result == false.
  #
  return void is abort


  # install this effect and run code.
  #
  # NYI: Currently, there is no direct way to return a result value
  # from the code.
  #
  private use0(
      # the code to be executed within this effect.  This is typically
      # redefined as an argument field of a sub-feature of effect.
      code ()->unit
     )
    pre
      match mode
        effectMode.new => true
        * => false
  is
    abortable (effect_call code)


# helper instance for effect.aboratable to wrap call to f() into a ()->unit
#
private effect_call(redef R type, f () -> R) ref : Function unit is
  res option R := nil
  call =>
    set res := f()

effects is

  # has an effect of the given type been installed?
  exists(E type) bool is intrinsic


# effect mode is an enum that determines how an instance of effect is used
#
effectMode is

  val : choice of
    plain,             # a plain effect, not installed as 'env'
    repl,              # effect instance replaces previous one in 'env'
    abort,             # effect instance aborts, jump back to where 'env' was installed
    default,           # install as default. NYI: remove and use 'new' instead, see io.stdin.fz
    new.               # a new effect to be installed
    inst(f ()->unit).  # install and run 'f'. NYI: remove and use 'new' instead, see io.stdin.fz


effect : effect (effectMode.inst code)
is

  # the code to be executed within this effect.  This is typically
  # redefined as an argument field of a sub-feature of effect.
  #
  # NYI: Currently, there is no direct way to return a result value
  # from the code.
  #
  code ()->unit is abstract


# simpleEffect provides a simple means to define and use an effect
#
# user-defined effects should inherit from this feature and add
# operations as inner features or fields of function type.
#
# To install this effect to execute a function, simpleEffect.use
# can be called.
#
simpleEffect : effect effectMode.plain
is

  # install this simpleEffect and run code
  #
  private use(code ()->unit) unit is
    abortable (effect_call code)