File: commander/subcommand.rb

Overview
Module Structure
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: Umu#4
  module: Commander#6
  module: Subcommand#8
has properties
function: execute / 4 #12
function: print_class_tree / 2 #84
function: print_class_signat / 3 #100
function: __print_class_message_list__ / 3 #225
function: __print_instance_message_list__ / 3 #236
function: __format_message_infos__ / 1 #247
function: get_message_infos_of_class / 2 #313
function: get_binding_lines / 2 #377

Code

   1  # coding: utf-8
   2  # frozen_string_literal: true
   3 
   4  module Umu
   5 
   6  module Commander
   7 
   8  module Subcommand
   9 
  10  module_function
  11 
  12      def execute(line, line_num, env, setup_env)
  13          ASSERT.kind_of line,        ::String
  14          ASSERT.kind_of line_num,    ::Integer
  15          ASSERT.kind_of env,         E::Entry
  16          ASSERT.kind_of setup_env,   E::Entry
  17 
  18          name, *args = line.split
  19 
  20          new_env = case name
  21          when ':trace'
  22              env.update_trace_mode true
  23          when ':notrace'
  24              env.update_trace_mode false
  25          when ':lextrace'
  26              env.update_lex_trace_mode true
  27          when ':nolextrace'
  28              env.update_lex_trace_mode false
  29          when ':dump'
  30              env.update_dump_mode true
  31          when ':nodump'
  32              env.update_dump_mode false
  33          when ':class'
  34              case args.size
  35              when 0
  36                  Subcommand.print_class_tree env.ty_context.root_class_signat
  37              when 1
  38                  class_signat = env.ty_lookup(
  39                      args[0].to_sym,
  40                      LOC.make_location(STDIN_FILE_NAME, line_num)
  41                  )
  42 
  43                  Subcommand.print_class_signat class_signat, env
  44              else
  45                  raise X::CommandError.new "Syntax error"
  46              end
  47 
  48              env
  49          when ':env'
  50              setup_bindings = setup_env.va_get_bindings
  51 
  52              Subcommand.get_binding_lines(env){ |sym, value|
  53                  opt_setup_value = setup_bindings[sym]
  54                  if opt_setup_value
  55                      if opt_setup_value == value
  56                          false
  57                      else
  58                          true
  59                      end
  60                  else
  61                      true
  62                  end
  63              }.each do |_sym, line|
  64                  STDERR.puts line
  65              end
  66 
  67              env
  68          when ':envall'
  69              Subcommand.get_binding_lines(env).sort { |a, b|
  70                  a[0] <=> b[0]
  71              }.each do |_sym, line|
  72                  STDERR.puts line
  73              end
  74 
  75              env
  76          else
  77              raise X::CommandError.new "Unknown command: '%s'", line
  78          end
  79 
  80          ASSERT.kind_of new_env, E::Entry
  81      end
  82 
  83 
  84      def print_class_tree(class_signat, nest = 0)
  85          ASSERT.kind_of class_signat, ECTSC::Abstract
  86          ASSERT.kind_of nest,         ::Integer
  87 
  88          printf("%s%s%s\n",
  89                   '    ' * nest,
  90                  class_signat.to_sym.to_s,
  91                  class_signat.abstract_class? ? '/' : ''
  92          )
  93 
  94          class_signat.subclasses.sort.each do |subclass_signat|
  95              Subcommand.print_class_tree subclass_signat, nest + 1
  96          end
  97      end
  98 
  99 
 100      def print_class_signat(class_signat, env, nest = 0)
 101          ASSERT.kind_of class_signat, ECTSC::Abstract
 102          ASSERT.kind_of env,          E::Entry
 103          ASSERT.kind_of nest,         ::Integer
 104 
 105          indent_0 = '    ' * nest
 106          indent_1 = '    ' * (nest + 1)
 107 
 108          printf("%sABSTRACT CLASS?: %s\n",
 109                  indent_0,
 110 
 111                  if class_signat.abstract_class?
 112                      "Yes"
 113                  else
 114                      "No, this is a concrete class"
 115                  end
 116          )
 117 
 118          opt_superclass = class_signat.opt_superclass
 119          if opt_superclass
 120              superclass = opt_superclass
 121 
 122              printf "%sSUPERCLASS: %s\n", indent_0, superclass.to_sym
 123          end
 124 
 125          subclasses = class_signat.subclasses
 126          unless subclasses.empty?
 127              printf("%sSUBCLASSES: %s\n",
 128                  indent_0,
 129                  subclasses.map(&:to_sym).join(', ')
 130              )
 131          end
 132 
 133          ancestors = class_signat.ancestors
 134          unless ancestors.empty?
 135              printf("%sANCESTORS: %s\n",
 136                  indent_0,
 137                  ancestors.map(&:to_sym).join(', ')
 138              )
 139          end
 140 
 141          descendants = class_signat.descendants
 142          unless descendants.empty?
 143              printf("%sDESCENDANTS: %s\n",
 144                  indent_0,
 145                  descendants.map(&:to_sym).join(', ')
 146              )
 147          end
 148 
 149          class_message_infos_of_class_sym,
 150          instance_message_infos_of_class_sym =
 151              Subcommand.get_message_infos_of_class class_signat.klass, env
 152 
 153          sub_cmess_infos_of_sym, *super_cmess_infos_of_sym =
 154              class_message_infos_of_class_sym.to_a
 155          class_sym_of_sub_cmess, sub_cmess_infos =
 156               sub_cmess_infos_of_sym
 157 
 158          sub_imess_infos_of_sym, *super_imess_infos_of_sym =
 159              instance_message_infos_of_class_sym.to_a
 160          class_sym_of_sub_imess, sub_imess_infos =
 161              sub_imess_infos_of_sym
 162 
 163          if super_cmess_infos_of_sym.any? { |_sym, infos|
 164              ! infos.empty?
 165          }
 166              printf "%sINHERITED CLASS MESSAGES:\n", indent_0
 167 
 168              super_cmess_infos_of_sym.reverse_each do |class_sym, infos|
 169                  unless infos.empty?
 170                      printf("%s  INHERIT FROM: %s\n",
 171                              indent_0, class_sym.to_s
 172                      )
 173 
 174                      __print_class_message_list__(
 175                          indent_1,
 176                          class_sym.to_s,
 177                          infos
 178                      )
 179                  end
 180              end
 181          end
 182 
 183          if sub_cmess_infos && ! sub_cmess_infos.empty?
 184              printf "%sCLASS MESSAGES:\n", indent_0
 185 
 186              __print_class_message_list__(
 187                  indent_1,
 188                  class_sym_of_sub_cmess.to_s,
 189                  sub_cmess_infos
 190              )
 191          end
 192 
 193          if super_imess_infos_of_sym.any? { |_sym, infos|
 194              ! infos.empty?
 195          }
 196              printf "%sINHERITED INSTANCE MESSAGES:\n", indent_0
 197 
 198              super_imess_infos_of_sym.reverse_each do |class_sym, infos|
 199                  unless infos.empty?
 200                      printf("%s  INHERIT FROM: %s\n",
 201                              indent_0, class_sym.to_s
 202                      )
 203 
 204                      __print_instance_message_list__(
 205                          indent_1,
 206                          class_sym.to_s,
 207                          infos
 208                      )
 209                  end
 210              end
 211          end
 212 
 213          if sub_imess_infos && ! sub_imess_infos.empty?
 214              printf "%sINSTANCE MESSAGES:\n", indent_0
 215 
 216              __print_instance_message_list__(
 217                  indent_1,
 218                  class_sym_of_sub_imess.to_s,
 219                  sub_imess_infos
 220              )
 221          end
 222      end
 223 
 224 
 225      def __print_class_message_list__(indent, class_name, infos)
 226          __format_message_infos__(infos).each do |info|
 227              printf("%s&%s .%s\n",
 228                  indent,
 229                  class_name,
 230                  info
 231              )
 232          end
 233      end
 234 
 235 
 236      def __print_instance_message_list__(indent, class_name, infos)
 237          __format_message_infos__(infos).each do |info|
 238              printf("%s%s #%s\n",
 239                  indent,
 240                  class_name,
 241                  info
 242              )
 243          end
 244      end
 245 
 246 
 247      def __format_message_infos__(infos_1)
 248          max_mess_length = infos_1.map { |info|
 249                  mess_name, opt_param_list, _ret_name = info.format_info
 250 
 251                  opt_param_list ? mess_name.length : 0
 252              }.max
 253 
 254          infos_2 = infos_1.map { |info|
 255              mess_name, opt_param_list, ret_name = info.format_info
 256 
 257              [
 258                  if opt_param_list
 259                      padding = " " * (max_mess_length - mess_name.length)
 260 
 261                      format("%s%s :", mess_name, padding)
 262                  else
 263                      mess_name
 264                  end
 265              ] + [
 266                  opt_param_list,
 267                  ret_name
 268              ]
 269          }
 270 
 271          max_body_length = infos_2.map {
 272                  |mess_name, opt_param_list, _ret_name|
 273 
 274                  (
 275                      mess_name + (
 276                          opt_param_list ?  opt_param_list : ''
 277                      )
 278                  ).length
 279              }.max
 280 
 281          infos_2.map {
 282              |mess_name, opt_param_list, ret_name|
 283 
 284              if opt_param_list
 285                  padding = " " * (
 286                              max_body_length - (
 287                                  mess_name + opt_param_list
 288                              ).length
 289                          )
 290 
 291                  if opt_param_list.length == 0
 292                      format("%s %s",
 293                          mess_name,
 294                          ret_name
 295                      )
 296                  else
 297                      format("%s %s%s -> %s",
 298                              mess_name,
 299                              opt_param_list,
 300                              padding,
 301                              ret_name
 302                      )
 303                  end
 304              else
 305                  padding = " " * (max_body_length - mess_name.length)
 306 
 307                  format "%s%s  -> %s", mess_name, padding, ret_name
 308              end
 309          }
 310      end
 311 
 312 
 313      def get_message_infos_of_class(klass, env)
 314          ASSERT.subclass_of klass,   VC::Top
 315          ASSERT.kind_of     env,     E::Entry
 316 
 317          pair = if klass <= VC::Class
 318              [{}, {}]
 319          else
 320              loop.inject(
 321                   [
 322                      {},
 323                      {},
 324                      klass,
 325                      {},
 326                      {}
 327                  ]
 328              ) {
 329                  |
 330                      (
 331                          cmess_infos_of_sym,
 332                          imess_infos_of_sym,
 333                          k,
 334                          set_of_cmess,
 335                          set_of_imess
 336                      ),
 337 
 338                      _
 339                  |
 340 
 341                  unless k <= VC::Top
 342                      break [cmess_infos_of_sym, imess_infos_of_sym]
 343                  end
 344 
 345                  cmess_infos = k.class_method_infos.reject { |info|
 346                                      set_of_cmess[info.mess_sym] ||
 347                                      /^%/ =~ info.mess_sym.to_s
 348                                  }
 349 
 350                  imess_infos = k.instance_method_infos.reject { |info|
 351                                      set_of_imess[info.mess_sym] ||
 352                                      /^%/ =~ info.mess_sym.to_s
 353                                  }
 354 
 355                  [
 356                      cmess_infos_of_sym.merge(k.type_sym => cmess_infos),
 357 
 358                      imess_infos_of_sym.merge(k.type_sym => imess_infos),
 359 
 360                      k.superclass,
 361 
 362                      cmess_infos.inject(set_of_cmess) { |set, info|
 363                          set.merge(info.mess_sym => true)
 364                      },
 365 
 366                      imess_infos.inject(set_of_imess) { |set, info|
 367                          set.merge(info.mess_sym => true)
 368                      }
 369                  ]
 370              }
 371          end
 372 
 373          ASSERT.tuple_of pair, [::Hash, ::Hash]
 374      end
 375 
 376 
 377      def get_binding_lines(env, &_block)
 378          ASSERT.kind_of env, E::Entry
 379 
 380          lines = env.va_context.reverse_each.inject({}) { |lines, context|
 381                  ASSERT.kind_of lines,   ::Hash
 382                  ASSERT.kind_of context, ECV::Entry
 383 
 384                  lines.merge(
 385                      context.get_bindings.select { |sym, value|
 386                          if /^%/ =~ sym.to_s
 387                              false
 388                          else
 389                              if block_given?
 390                                  yield sym, value
 391                              else
 392                                  true
 393                              end
 394                          end
 395                      }.inject({}) { |hash, (sym, value)|
 396                          line = case value
 397                                  when VC::Fun
 398                                      format "fun %s", sym.to_s
 399                                  when VC::Struct::Entry
 400                                      format "structure %s", sym.to_s
 401                                  else
 402                                      format("val %s : %s",
 403                                                   sym.to_s,
 404                                                   value.type_sym.to_s
 405                                              )
 406                                  end
 407 
 408                          hash.merge(sym => line) {
 409                              ASSERT.abort "No case: %s", sym
 410                          }
 411                      }
 412                  ) { |_sym, newer_line, _older_line|
 413                      newer_line
 414                  }
 415              }
 416 
 417          ASSERT.kind_of lines, ::Hash
 418      end
 419 
 420  end # Umu::Commander::Subcommand
 421 
 422  end # Umu::Commander
 423 
 424  end # Umu