File: value/core/function.rb

Overview
Module Structure
Class Hierarchy
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: Umu#6
  module: Value#8
  module: Core#10
has properties
function: make_function / 2 #251
  class: Fun#12
inherits from
  Object ( Umu::Value::Core )
has properties
attribute: lam [R] #13
attribute: va_context [R] #13
method: initialize / 2 #16
method: to_s #27
method: pretty_print / 1 #42
method: apply / 4 #55
method: meth_apply / 4 #87
method: meth_apply_binary / 5 #99
method: meth_apply_nary / 6 #112
method: __apply__ / 5 #128
method: __bind__ / 4 #194

Class Hierarchy

Object ( Builtin-Module )
Top ( Umu::Value::Core )
Object ( Umu::Value::Core )
  Fun    #12

Code

   1  # coding: utf-8
   2  # frozen_string_literal: true
   3 
   4 
   5 
   6  module Umu
   7 
   8  module Value
   9 
  10  module Core
  11 
  12  class Fun < Object
  13      attr_reader :lam, :va_context
  14 
  15 
  16      def initialize(lam, va_context)
  17          ASSERT.kind_of lam,         ASCEN::Lambda::Entry
  18          ASSERT.kind_of va_context,  ECV::Abstract
  19 
  20          super()
  21 
  22          @lam        = lam
  23          @va_context = va_context
  24      end
  25 
  26 
  27      def to_s
  28          lam = self.lam
  29 
  30          format("#<%s%s>",
  31              if lam.opt_name
  32                  format "%s: ", lam.opt_name
  33              else
  34                  ''
  35              end,
  36 
  37              self.lam.to_s
  38          )
  39      end
  40 
  41 
  42      def pretty_print(q)
  43          bb = if lam.opt_name
  44                      format "#<%s: ", lam.opt_name
  45                  else
  46                      '#<'
  47                  end
  48 
  49          PRT.group q, bb:bb, eb:'>' do
  50              q.pp self.lam
  51          end
  52      end
  53 
  54 
  55      def apply(head_value, tail_values, loc, env)
  56          ASSERT.kind_of head_value,  VC::Top
  57          ASSERT.kind_of tail_values, ::Array
  58          ASSERT.kind_of loc,         LOC::Entry
  59          ASSERT.kind_of env,         E::Entry
  60 
  61          result_value = E::Tracer.trace(
  62                              env.pref,
  63                              env.trace_stack.count,
  64                              'Apply',
  65                              self.class,
  66                              loc,
  67                              format("(%s %s)",
  68                                  self.to_s,
  69                                  (
  70                                      [head_value] + tail_values
  71                                  ).map(&:to_s).join(' ')
  72                              )
  73                          ) { |event|
  74                              __apply__(
  75                                  head_value, tail_values, loc, env, event
  76                              )
  77                          }
  78          ASSERT.kind_of result_value, VC::Top
  79      end
  80 
  81 
  82      define_instance_method(
  83          :meth_apply,
  84          :apply, [],
  85          [VC::Top], VC::Top
  86      )
  87      def meth_apply(loc, env, event, value)
  88          ASSERT.kind_of value, VC::Top
  89 
  90          self.apply value, [], loc, env.enter(event)
  91      end
  92 
  93 
  94      define_instance_method(
  95          :meth_apply_binary,
  96          :'apply-binary', [],
  97          [VC::Top, VC::Top], VC::Top
  98      )
  99      def meth_apply_binary(loc, env, event, fst_value, snd_value)
 100          ASSERT.kind_of fst_value, VC::Top
 101          ASSERT.kind_of snd_value, VC::Top
 102 
 103          self.apply fst_value, [snd_value], loc, env.enter(event)
 104      end
 105 
 106 
 107      define_instance_method(
 108          :meth_apply_nary,
 109          :'apply-nary', [],
 110          [VC::Top, VC::Top, VCM::Abstract], VC::Top
 111      )
 112      def meth_apply_nary(loc, env, event, fst_value, snd_value, tail_values)
 113          ASSERT.kind_of fst_value,   VC::Top
 114          ASSERT.kind_of snd_value,   VC::Top
 115          ASSERT.kind_of tail_values, VCM::Abstract
 116 
 117          self.apply(
 118              fst_value,
 119              [snd_value] + tail_values.to_a,
 120              loc,
 121              env.enter(event)
 122          )
 123      end
 124 
 125 
 126  private
 127 
 128      def __apply__(init_head_value, init_tail_values, loc, env, event)
 129          ASSERT.kind_of init_head_value,     VC::Top
 130          ASSERT.kind_of init_tail_values,    ::Array
 131          ASSERT.kind_of loc,                 LOC::Entry
 132          ASSERT.kind_of env,                 E::Entry
 133          ASSERT.kind_of event,               E::Tracer::Event
 134 
 135          init_values = [init_head_value] + init_tail_values
 136          lam         = self.lam
 137 
 138          init_params     = lam.params
 139          init_params_num = init_params.size
 140          init_values_num = init_values.size
 141          ASSERT.assert init_params_num >= 1
 142          ASSERT.assert init_values_num >= 1
 143          init_env        = env.update_va_context self.va_context
 144 
 145          result_value = 
 146              if init_params_num == init_values_num
 147                  final_params, final_values, final_env = __bind__(
 148                      init_params_num, init_params, init_values, init_env
 149                  )
 150                  ASSERT.assert final_params.empty?
 151                  ASSERT.assert final_values.empty?
 152 
 153                  new_env = final_env.enter event
 154                  result  = self.lam.expr.evaluate new_env
 155                  ASSERT.kind_of result, ASR::Value
 156 
 157                  result.value
 158              elsif init_params_num < init_values_num
 159                  final_params, final_values, final_env = __bind__(
 160                      init_params_num, init_params, init_values, init_env
 161                  )
 162                  ASSERT.assert final_params.empty?
 163                  ASSERT.assert (not final_values.empty?)
 164                  final_head_value, *final_tail_values = final_values
 165 
 166                  new_env = final_env.enter event
 167                  result  = self.lam.expr.evaluate new_env
 168                  ASSERT.kind_of result, ASR::Value
 169 
 170                  result.value.apply(
 171                      final_head_value, final_tail_values, loc, new_env
 172                  )
 173              elsif init_params_num > init_values_num
 174                  final_params, final_values, final_env = __bind__(
 175                      init_values_num, init_params, init_values, init_env
 176                  )
 177                  ASSERT.assert (not final_params.empty?)
 178                  ASSERT.assert final_values.empty?
 179 
 180                  VC.make_function(
 181                      ASCE.make_lambda(
 182                          loc, final_params, lam.expr, lam.opt_name
 183                      ),
 184                      final_env.va_context
 185                  )
 186              else
 187                  ASSERT.abort 'No case'
 188              end
 189 
 190          ASSERT.kind_of result_value, VC::Top
 191      end
 192 
 193 
 194      def __bind__(init_num, init_params, init_values, init_env)
 195          tuple = loop.inject(
 196               [init_num, init_params,    init_values,    init_env]
 197          ) {
 198              |(num,      params,         values,         env),       _|
 199              ASSERT.kind_of num,     ::Integer
 200              ASSERT.kind_of params,  ::Array
 201              ASSERT.kind_of values,  ::Array
 202              ASSERT.kind_of env,     E::Entry
 203 
 204              if num <= 0
 205                  break [params, values, env]
 206              end
 207 
 208              head_param, *tail_params    = params
 209              head_value, *tail_values    = values
 210              ASSERT.kind_of head_param,  ASCEN::Lambda::Parameter
 211              ASSERT.kind_of tail_params, ::Array
 212              ASSERT.kind_of head_value,  VC::Top
 213              ASSERT.kind_of tail_values, ::Array
 214 
 215              if head_param.opt_type_sym
 216                  type_sym = head_param.opt_type_sym
 217 
 218                  signat = env.ty_lookup type_sym, head_param.loc
 219                  ASSERT.kind_of signat, ECTSC::Base
 220                  unless env.ty_kind_of?(head_value, signat)
 221                      raise X::TypeError.new(
 222                          head_param.loc,
 223                          env,
 224                          "Expected a %s, but %s : %s",
 225                          type_sym,
 226                          head_value,
 227                          head_value.type_sym
 228                      )
 229                  end
 230              end
 231 
 232              [
 233                  num - 1,
 234 
 235                  tail_params,
 236 
 237                  tail_values,
 238 
 239                  env.va_extend_value(head_param.ident.sym, head_value)
 240              ]
 241          }
 242 
 243          ASSERT.tuple_of tuple, [::Array, ::Array, E::Entry]
 244      end
 245  end
 246  Fun.freeze
 247 
 248 
 249  module_function
 250 
 251      def make_function(lam, va_context)
 252          ASSERT.kind_of lam,         ASCEN::Lambda::Entry
 253          ASSERT.kind_of va_context,  ECV::Abstract
 254 
 255          Fun.new(lam, va_context).freeze
 256      end
 257 
 258  end # Umu::Value::Core
 259 
 260  end # Umu::Value
 261 
 262  end # Umu