File: abstract-syntax/core/expression/binary/send.rb

Overview
Module Structure
Class Hierarchy
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: Umu#6
  module: AbstractSyntax#8
  module: Core#10
  module: Expression#12
has properties
function: make_message / 3 #338
function: make_send / 5 #347
  module: Binary#14
  module: Send#16
  class: Message#18
inherits from
  Model ( Umu::Abstraction )
has properties
attribute: sym [R] #19
attribute: exprs [R] #19
method: initialize / 3 #22
method: to_s #33
method: pretty_print / 1 #46
  class: Entry#63
inherits from
  Abstract ( Umu::AbstractSyntax::Core::Expression::Binary )
has properties
alias: rhs_head_message rhs #64
attribute: rhs_tail_messages [R] #65
attribute: opt_receiver_type_sym [R] #66
method: initialize / 5 #69
method: rhs_messages #86
method: to_s #91
method: pretty_print / 1 #106
method: __evaluate__ / 2 #120
method: __send_message__ / 4 #158
method: __validate_type_of_args__ / 6 #299

Code

   1  # coding: utf-8
   2  # frozen_string_literal: true
   3 
   4 
   5 
   6  module Umu
   7 
   8  module AbstractSyntax
   9 
  10  module Core
  11 
  12  module Expression
  13 
  14  module Binary
  15 
  16  module Send
  17 
  18  class Message < Umu::Abstraction::Model
  19      attr_reader :sym, :exprs
  20 
  21 
  22      def initialize(loc, sym, exprs)
  23          ASSERT.kind_of sym,     ::Symbol
  24          ASSERT.kind_of exprs,   ::Array
  25 
  26          super(loc)
  27 
  28          @sym    = sym
  29          @exprs  = exprs
  30      end
  31 
  32 
  33      def to_s
  34          format(".%s",
  35              if self.exprs.empty?
  36                  self.sym.to_s
  37              else
  38                  format "(%s %s)",
  39                          self.sym.to_s,
  40                          self.exprs.map(&:to_s).join(' ')
  41              end
  42          )
  43      end
  44 
  45 
  46      def pretty_print(q)
  47          PRT.group_for_enum(
  48              q,
  49 
  50              self.exprs,
  51 
  52              bb: format(self.exprs.empty? ? ".%s" : ".(%s ", self.sym.to_s),
  53 
  54              eb: self.exprs.empty? ? '' : ')',
  55 
  56              join: ' '
  57          )
  58      end
  59  end
  60 
  61 
  62 
  63  class Entry < Binary::Abstract
  64      alias       rhs_head_message rhs
  65      attr_reader :rhs_tail_messages
  66      attr_reader :opt_receiver_type_sym
  67 
  68 
  69      def initialize(
  70          loc, lhs_expr,
  71          rhs_head_message, rhs_tail_messages,
  72          opt_receiver_type_sym
  73      )
  74          ASSERT.kind_of      lhs_expr,               ASCE::Abstract
  75          ASSERT.kind_of      rhs_head_message,       Message
  76          ASSERT.kind_of      rhs_tail_messages,      ::Array
  77          ASSERT.opt_kind_of  opt_receiver_type_sym,  ::Symbol
  78 
  79          super(loc, lhs_expr, rhs_head_message)
  80 
  81          @rhs_tail_messages      = rhs_tail_messages
  82          @opt_receiver_type_sym  = opt_receiver_type_sym
  83      end
  84 
  85 
  86      def rhs_messages
  87          [self.rhs_head_message] + self.rhs_tail_messages
  88      end
  89 
  90 
  91      def to_s
  92          format("(%s%s)%s",
  93              self.lhs_expr.to_s,
  94 
  95              if self.opt_receiver_type_sym
  96                  format " : %s", self.opt_receiver_type_sym.to_s
  97              else
  98                  ''
  99              end,
 100 
 101              self.rhs_messages.map(&:to_s).join
 102          )
 103      end
 104 
 105 
 106      def pretty_print(q)
 107          PRT.group q, bb:'(', eb:')' do
 108              q.pp lhs_expr
 109              if self.opt_receiver_type_sym
 110                  q.text format(" : %s", self.opt_receiver_type_sym.to_s)
 111              end
 112          end
 113 
 114          PRT.group_for_enum q, self.rhs_messages
 115      end
 116 
 117 
 118  private
 119 
 120      def __evaluate__(env, event)
 121          ASSERT.kind_of env,     E::Entry
 122          ASSERT.kind_of event,   E::Tracer::Event
 123 
 124          new_env = env.enter event
 125 
 126          lhs_result = self.lhs_expr.evaluate new_env
 127          ASSERT.kind_of lhs_result, ASR::Value
 128          init_receiver = lhs_result.value
 129 
 130          if self.opt_receiver_type_sym
 131              receiver_type_sym = opt_receiver_type_sym
 132 
 133              receiver_signat = new_env.ty_lookup receiver_type_sym, self.loc
 134              ASSERT.kind_of receiver_signat, ECTSC::Base
 135              unless env.ty_kind_of?(init_receiver, receiver_signat)
 136                  raise X::TypeError.new(
 137                      self.loc,
 138                      env,
 139                      "Expected a %s, but %s : %s",
 140                      receiver_type_sym,
 141                      init_receiver,
 142                      init_receiver.type_sym
 143                  )
 144              end
 145          end
 146 
 147          final_receiver = self.rhs_messages.inject(init_receiver) {
 148              |receiver, message|
 149              ASSERT.kind_of receiver,    VC::Top
 150              ASSERT.kind_of message,     Message
 151 
 152              __send_message__ receiver, message, new_env, event
 153          }
 154          ASSERT.kind_of final_receiver, VC::Top
 155      end
 156 
 157 
 158      def __send_message__(receiver, message, env, event)
 159          ASSERT.kind_of receiver,    VC::Top
 160          ASSERT.kind_of message,     Message
 161          ASSERT.kind_of env,         E::Entry
 162          ASSERT.kind_of event,       E::Tracer::Event
 163 
 164          message_sym  = message.sym
 165          arg_values   = message.exprs.map { |expr|
 166              result = expr.evaluate env
 167              ASSERT.kind_of result, ASR::Value
 168 
 169              result.value
 170          }
 171          arg_num     = arg_values.size
 172 
 173          receiver_signat = env.ty_class_signat_of receiver
 174          ASSERT.kind_of receiver_signat, ECTSC::Abstract
 175          method_signat   = receiver_signat.lookup_instance_method(
 176                                          message_sym, message.loc, env
 177                                      )
 178          ASSERT.kind_of method_signat, ECTSM::Entry
 179 
 180          param_signats   = method_signat.param_class_signats
 181          param_num       = method_signat.param_class_signats.size
 182 
 183          result_value =
 184              if param_num == arg_num
 185                  __validate_type_of_args__(
 186                      message_sym,
 187                      param_num, arg_values, param_signats, loc, env
 188                  )
 189 
 190                  next_receiver = receiver.invoke(
 191                      method_signat, message.loc, env, event, *arg_values
 192                  )
 193                  ASSERT.assert(
 194                      env.ty_kind_of?(
 195                          next_receiver, method_signat.ret_class_signat
 196                      ), (
 197                          {
 198                              nx_recv:
 199                                   next_receiver.class,
 200                              ret_class_signat:
 201                                   method_signat.ret_class_signat.symbol
 202                          }.inspect
 203                      )
 204                  )
 205                  ASSERT.kind_of next_receiver, VC::Top
 206              elsif param_num < arg_num
 207                  __validate_type_of_args__(
 208                      message_sym,
 209                      param_num, arg_values, param_signats, loc, env
 210                  )
 211 
 212                  invoked_values = if param_num == 0
 213                                          []
 214                                      else
 215                                          arg_values[0 .. param_num - 1]
 216                                      end
 217 
 218                  value = receiver.invoke(
 219                      method_signat, loc, env.enter(event), event,
 220                      *invoked_values
 221                  )
 222                  ASSERT.assert env.ty_kind_of?(
 223                      value, method_signat.ret_class_signat
 224                  )
 225                  ASSERT.kind_of value, VC::Top
 226 
 227                  hd_arg_value, *tl_arg_values = arg_values[param_num .. -1]
 228 
 229                  value.apply hd_arg_value, tl_arg_values, loc, env
 230              elsif param_num > arg_num
 231  =begin
 232                  p({
 233                      param_num: param_num,
 234                      arg_num: arg_num,
 235                      arg_values: arg_values
 236                  })
 237  =end
 238                  free_idents, bound_idents = (0 .. param_num - 1).inject(
 239                               [[],        []]
 240                          ) { |(fr_idents, bo_idents), i|
 241                      ident = ASCE.make_identifier(
 242                                  loc, format("%%x_%d", i + 1).to_sym
 243                              )
 244 
 245                      if i < arg_num
 246                          [fr_idents + [ident],   bo_idents]
 247                      else
 248                          [fr_idents,             bo_idents + [ident]]
 249                      end
 250                  }
 251  =begin
 252                  p({
 253                      free_idents: free_idents,
 254                      bound_idents: bound_idents
 255                  })
 256  =end
 257                  new_env = free_idents.zip(
 258                          arg_values
 259                      ).inject(
 260                          env.va_extend_value :'%r', receiver
 261                      ) { |e, (ident, v)|
 262                      ASSERT.kind_of e,       E::Entry
 263                      ASSERT.kind_of ident,   ASCEU::Identifier::Short
 264                      ASSERT.kind_of v,       VC::Top
 265 
 266                      e.va_extend_value ident.sym, v
 267                  }
 268 
 269                  lamb_params = bound_idents.map { |ident|
 270                      ASSERT.kind_of ident, ASCEU::Identifier::Short
 271 
 272                      ASCE.make_parameter ident.loc, ident
 273                  }
 274 
 275                  VC.make_function(
 276                      ASCE.make_lambda(
 277                          loc,
 278                          lamb_params,
 279                          ASCE.make_send(
 280                              loc,
 281                              ASCE.make_identifier(loc, :'%r'),
 282                              ASCE.make_message(
 283                                  loc,
 284                                  method_signat.mess_sym,
 285                                  free_idents + bound_idents
 286                              )
 287                          )
 288                      ),
 289                      new_env.va_context
 290                  )
 291              else
 292                  ASSERT.abort 'No case'
 293              end
 294 
 295          ASSERT.kind_of result_value, VC::Top
 296      end
 297 
 298 
 299      def __validate_type_of_args__(
 300          mess_sym, num, arg_values, param_signats, loc, env
 301      )
 302          ASSERT.kind_of mess_sym,        ::Symbol
 303          ASSERT.kind_of num,             ::Integer
 304          ASSERT.kind_of arg_values,      ::Array
 305          ASSERT.kind_of param_signats,   ::Array
 306          ASSERT.kind_of loc,             LOC::Entry
 307          ASSERT.kind_of env,             E::Entry
 308 
 309          (0 .. num - 1).each do |i|
 310              arg_value       = arg_values[i]
 311              param_signat    = param_signats[i]
 312              ASSERT.kind_of arg_value,       VC::Top
 313              ASSERT.kind_of param_signat,    ECTSC::Base
 314 
 315              unless env.ty_kind_of?(arg_value, param_signat)
 316                  raise X::TypeError.new(
 317                      loc,
 318                      env,
 319                      "For '%s's #%d argument, expected a %s, but %s : %s",
 320                          mess_sym.to_s,
 321                          i + 1,
 322                          param_signat.symbol,
 323                          arg_value.to_s,
 324                          arg_value.type_sym
 325                  )
 326              end
 327          end
 328      end
 329  end
 330 
 331  end # Umu::AbstractSyntax::Core::Expression::Binary::Send
 332 
 333  end # Umu::AbstractSyntax::Core::Expression::Binary
 334 
 335 
 336  module_function
 337 
 338      def make_message(loc, sym, exprs = [])
 339          ASSERT.kind_of loc,     LOC::Entry
 340          ASSERT.kind_of sym,     ::Symbol
 341          ASSERT.kind_of exprs,   ::Array
 342 
 343          Binary::Send::Message.new(loc, sym, exprs.freeze).freeze
 344      end
 345 
 346 
 347      def make_send(
 348          loc, lhs_expr,
 349          rhs_head_message, rhs_tail_messages = [],
 350          opt_receiver_type_sym = nil
 351      )
 352          ASSERT.kind_of      loc,                    LOC::Entry
 353          ASSERT.kind_of      lhs_expr,               ASCE::Abstract
 354          ASSERT.kind_of      rhs_head_message,       Binary::Send::Message
 355          ASSERT.kind_of      rhs_tail_messages,      ::Array
 356          ASSERT.opt_kind_of  opt_receiver_type_sym,  ::Symbol
 357 
 358          Binary::Send::Entry.new(
 359              loc, lhs_expr, rhs_head_message, rhs_tail_messages.freeze,
 360              opt_receiver_type_sym
 361          ).freeze
 362      end
 363 
 364  end # Umu::AbstractSyntax::Core::Expression
 365 
 366  end # Umu::AbstractSyntax::Core
 367 
 368  end # Umu::AbstractSyntax
 369 
 370  end # Umu