File: reader/ruby1.8/parser/leaf.rb

Overview
Module Structure
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: TmDoc#12
  module: Reader
  module: Ruby18#14
  module: Parser#16
  module: Leaf#18
includes
  RubyToken ( Builtin-Module )
has properties
function: parse_constant / 5 #23
function: parse_alias / 5 #94
function: parse_attribute / 6 #185
function: parse_require / 3 #277
function: parse_extend / 4 #321
function: parse_include / 4 #393
function: parse_module_func / 5 #458

Code

   1  # $Id: leaf.rb,v 1.3 2011/11/30 21:48:43 machan Exp $
   2 
   3  require 'tmdoc/tmstd'
   4  require 'tmdoc/constant'
   5  require 'tmdoc/environment'
   6  require 'tmdoc/model/core'
   7  require 'tmdoc/reader/ruby1.8/scanner'
   8  require 'tmdoc/reader/ruby1.8/parser/types'
   9  require 'tmdoc/reader/ruby1.8/parser/common'
  10 
  11 
  12  module TmDoc
  13 
  14  module Reader::Ruby18
  15 
  16  module Parser
  17 
  18  module Leaf
  19      include RubyToken
  20 
  21  module_function
  22 
  23      def parse_constant(scanner, above_path, context, env, c_tk)
  24          ASSERT.kind_of scanner,     Scanner
  25          ASSERT.kind_of above_path,  MCLP::AbsolutePath
  26          ASSERT.kind_of context,     Context
  27          ASSERT.kind_of env,         ENV::Environment
  28          ASSERT.kind_of c_tk,        TkCONSTANT
  29 
  30          LOG::Debug.msgout "CALLED " +
  31                          "above_path='#{above_path.to_s}', " +
  32                          "tk=#{c_tk.inspect}" if env.debug_parser?
  33 
  34          scanner.skip_space!
  35          eq_tk = scanner.get!
  36 
  37          unless eq_tk.kind_of?(TkASSIGN)
  38              scanner.unget! eq_tk
  39              return nil
  40          end
  41 
  42          nest = 0
  43          scanner.get_readed!
  44 
  45          tk = scanner.get!
  46          if tk.kind_of? TkGT
  47              scanner.unget! tk
  48              scanner.unget! eq_tk
  49              return nil
  50          end
  51 
  52          loop do
  53              LOG::Debug.log("Param: #{tk}, #{nest}")  if env.debug_parser?
  54 
  55              case tk
  56              when TkNL, TkSEMICOLON, TkCOMMENT
  57                  break
  58              when TkLPAREN, TkfLPAREN
  59                  nest += 1
  60              when TkRPAREN
  61                  nest -= 1
  62              else
  63                  break unless tk # when EOF
  64              end
  65              tk = scanner.get!
  66          end
  67          value = scanner.get_readed!.tr("\n", " ").strip
  68 
  69          mc_constant =
  70              if context.in_unique_class?
  71                  LOG::Warning.log(
  72                      "I can't parse the constant definiation: <%s> " +
  73                                                      "in unique class.\n" +
  74                                  "\t-- #%d in '%s'",
  75                      c_tk.name,
  76                                  c_tk.line_no, scanner.file_name
  77                  )
  78                  CMD.test_sensitive_level env, LOG::Warning
  79 
  80                  nil
  81              else
  82                  LOG::Debug.msgout("ACCEPT %s",
  83                      mc_constant.to_s
  84                  ) if env.debug_parser?
  85 
  86                  MCLL::Constant.new c_tk.line_no, c_tk.name, value
  87              end
  88 
  89          ASSERT.opt_kind_of mc_constant, MCLL::Constant
  90      end
  91 
  92 
  93 
  94      def parse_alias(scanner, above_path, context, env, a_tk)
  95          ASSERT.kind_of scanner,     Scanner
  96          ASSERT.kind_of above_path,  MCLP::AbsolutePath
  97          ASSERT.kind_of context,     Context
  98          ASSERT.kind_of env,         ENV::Environment
  99          ASSERT.kind_of a_tk,        TkALIAS
 100 
 101          LOG::Debug.msgout "CALLED " +
 102                          "above_path='#{above_path.to_s}', " +
 103                          "a_tk=#{a_tk.inspect}" if env.debug_parser?
 104 
 105          scanner.skip_space_or_nl!
 106          got_tk = scanner.get!
 107          LOG::Debug.log "got_tk=#{got_tk.inspect} " +
 108                                      "[##{__LINE__}]" if env.debug_parser?
 109          name =
 110              if got_tk.respond_to?(:name)
 111                  got_tk.name
 112              elsif got_tk.respond_to?(:value)
 113                  got_tk.value
 114              else
 115                  LOG::Warning.log(
 116                      "I can't recognize a token: %s<%s> for alias name.\n" +
 117                                  "\t-- #%d in '%s'",
 118                      if got_tk.respond_to?(:name)
 119                          got_tk.name
 120                      else
 121                          ''
 122                      end,
 123                      got_tk.class.to_s,
 124                                  got_tk.line_no, scanner.file_name
 125                  )
 126                  CMD.test_sensitive_level env, LOG::Warning
 127 
 128                  nil
 129              end
 130 
 131          scanner.skip_space_or_nl!
 132          got_tk = scanner.get!
 133          LOG::Debug.log "got_tk=#{got_tk.inspect} " +
 134                                      "[##{__LINE__}]" if env.debug_parser?
 135          if got_tk.kind_of?(TkCOLON)
 136              got_tk = scanner.get!
 137              LOG::Debug.log "got_tk=#{got_tk.inspect} " +
 138                                      "[##{__LINE__}]" if env.debug_parser?
 139          end
 140 
 141          orig_name =
 142              if got_tk.respond_to?(:name)
 143                  got_tk.name
 144              elsif got_tk.respond_to?(:value)
 145                  got_tk.value
 146              else
 147                  LOG::Warning.log(
 148                      "I can't recognize a token: %s<%s>" +
 149                                          " for orignal name of alias.\n" +
 150                                  "\t-- #%d in '%s'",
 151                      if got_tk.respond_to?(:name)
 152                          got_tk.name
 153                      else
 154                          ''
 155                      end,
 156                      got_tk.class.to_s,
 157                                  got_tk.line_no, scanner.file_name
 158                  )
 159                  CMD.test_sensitive_level env, LOG::Warning
 160 
 161                  nil
 162              end
 163 
 164          mc_alias =
 165              if name && orig_name
 166                  LOG::Debug.msgout(
 167                      "ACCEPT %s", mc_alias.to_s
 168                  ) if env.debug_parser?
 169 
 170                  MCLL::Alias.new(
 171                      a_tk.line_no,
 172                      name.gsub(/^:/, ''),
 173                      orig_name.gsub(/^:/, ''),
 174                      ! context.in_unique_class?
 175                  )
 176              else
 177                  nil
 178              end
 179 
 180          ASSERT.opt_kind_of mc_alias, MCLL::Alias
 181      end
 182 
 183 
 184 
 185      def parse_attribute(scanner, above_path, context, env, a_tk, accessor)
 186          ASSERT.kind_of      scanner,        Scanner
 187          ASSERT.kind_of      above_path,     MCLP::AbsolutePath
 188          ASSERT.kind_of      context,        Context
 189          ASSERT.kind_of      env,            ENV::Environment
 190          ASSERT.kind_of      a_tk,           TkIDENTIFIER
 191          ASSERT.opt_kind_of  accessor,       String
 192 
 193          LOG::Debug.msgout "CALLED " +
 194                          "above_path='#{above_path.to_s}', " +
 195                          "a_tk=#{a_tk.inspect}" if env.debug_parser?
 196 
 197          args = SeqOfArgument.new
 198          loop do
 199              scanner.skip_space_or_nl!
 200              tk = scanner.get!
 201              case tk
 202              when TkSYMBOL
 203                  args.add! Argument.new(tk.value, tk.line_no)
 204              when TkSTRING
 205                  args.add! Argument.new(scanner.last_readed, tk.line_no)
 206              else
 207                  break
 208              end
 209 
 210              scanner.skip_space!
 211              tk1 = scanner.get!
 212              case tk1
 213              when TkCOMMA
 214                  ;   # nop
 215              when TkNL
 216                  scanner.unget! tk1
 217                  break
 218              else
 219                  break
 220              end
 221          end
 222          LOG::Debug.log "args='#{args.inspect}' " +
 223                                      "[##{__LINE__}]" if env.debug_parser?
 224 
 225          mc_attribute =
 226              if accessor
 227                  mc_attributes = args.map_with_index { |arg, seq_num|
 228                      MCLL::Attribute.new(
 229                          arg.line_num,
 230                          arg.name.gsub(/^:/, ''),
 231                          seq_num,
 232                          accessor.to_sym,
 233                          ! context.in_unique_class?
 234                      )
 235                  }
 236                  if env.debug_parser?
 237                      for mc_attribute in mc_attributes
 238                          LOG::Debug.msgout("ACCEPT %s", mc_attributes.to_s)
 239                      end
 240                  end
 241 
 242                  MCLN::Block.new(
 243                      a_tk.line_no, MCLA::SetOfSubject.new(mc_attributes)
 244                  )
 245              else
 246                  len_of_args = args.length
 247 
 248                  if len_of_args >= 1
 249                      first_arg = args.first
 250 
 251                      LOG::Debug.msgout("ACCEPT %s",
 252                          mc_attribute.to_s
 253                      ) if env.debug_parser?
 254 
 255                      MCLL::Attribute.new(
 256                          first_arg.line_num,
 257                          first_arg.name.gsub(/^:/, ''),
 258                          0,
 259                          if len_of_args == 1 then :reader else :unknown end,
 260                          ! context.in_unique_class?
 261                      )
 262                  else
 263                      LOG::Debug.log(
 264                          "Can't recognize a token: <%s> as attr -- #%d",
 265                          tk.class.to_s, tk.line_no
 266                      ) if env.debug_parser?
 267 
 268                      nil
 269                  end
 270              end
 271                                      # MCLN::Attribute, MCLN::Block, or nil
 272          ASSERT.opt_kind_of mc_attribute, MCLA::Subject
 273      end
 274 
 275 
 276 
 277      def parse_require(scanner, above_path, env)
 278          ASSERT.kind_of scanner,     Scanner
 279          ASSERT.kind_of above_path,  MCLP::AbsolutePath
 280          ASSERT.kind_of env,         ENV::Environment
 281 
 282          LOG::Debug.msgout "CALLED " +
 283                          "above_path=#{above_path}" if env.debug_parser?
 284 
 285          scanner.skip_space_or_nl!
 286          tk = scanner.get!
 287 
 288          name = nil
 289          case tk
 290          when TkSTRING
 291              name = scanner.last_readed
 292          else
 293              LOG::Warning.log(
 294                  "The 'require' expected string, but: %s<%s>.\n" +
 295                          "\t-- #%d in '%s'",
 296                  if tk.respond_to?(:name) then tk.name else '' end,
 297                  tk.class.to_s,
 298                          tk.line_no, scanner.file_name
 299              )
 300              CMD.test_sensitive_level env, LOG::Warning
 301          end
 302 
 303          mc_require =
 304              if name
 305                  LOG::Debug.msgout("ACCEPT %s",
 306                      mc_require.to_s
 307                  ) if env.debug_parser?
 308 
 309                  MCLL::Require.new(tk.line_no, name)
 310              else
 311                  scanner.unget! tk
 312 
 313                  nil
 314              end
 315 
 316          ASSERT.opt_kind_of mc_require, MCLL::Require
 317      end
 318 
 319 
 320 
 321      def parse_extend(scanner, above_path, env, e_tk)
 322          ASSERT.kind_of scanner,     Scanner
 323          ASSERT.kind_of above_path,  MCLP::AbsolutePath
 324          ASSERT.kind_of env,         ENV::Environment
 325          ASSERT.kind_of e_tk,        TkIDENTIFIER
 326 
 327          LOG::Debug.msgout "CALLED " +
 328                          "above_path=#{above_path}" if env.debug_parser?
 329 
 330          seq_num     = 0
 331          mc_extends  = []
 332          loop do
 333              scanner.skip_space_or_nl!
 334              tk = scanner.peek
 335              case tk
 336              when TkCONSTANT, TkCOLON2, TkCOLON3
 337                  name = Common.get_constant(scanner, env)
 338 
 339                  mc_extends << MCLL::Extend.new(tk.line_no, seq_num, name)
 340                  seq_num += 1
 341 
 342              when TkLPAREN, TkfLPAREN
 343                  name =
 344                      Common.get_constant_with_optional_parens(scanner, env)
 345 
 346                  mc_extends << MCLL::Extend.new(tk.line_no, seq_num, name)
 347                  seq_num += 1
 348 
 349              when TkSELF
 350                  mc_extends << MCLL::Extend.new(tk.line_no, seq_num, nil)
 351                  seq_num += 1
 352 
 353              else
 354                  LOG::Warning.log(
 355                      "The 'extend' expected constant, but: %s<%s>.\n" +
 356                              "\t-- #%d in '%s'",
 357                      if tk.respond_to?(:name) then tk.name else '' end,
 358                      tk.class.to_s,
 359                              tk.line_no, scanner.file_name
 360                  )
 361                  CMD.test_sensitive_level env, LOG::Warning
 362              end
 363 
 364              unless scanner.peek.kind_of?(TkCOMMA)
 365                  break
 366              end
 367 
 368              scanner.get!
 369          end
 370          if env.debug_parser?
 371              for mc_extend in mc_extends
 372                  LOG::Debug.msgout("ACCEPT %s", mc_extend.to_s)
 373              end
 374          end
 375 
 376          mc_extend =
 377              case mc_extends.size
 378              when 0
 379                  nil
 380              when 1
 381                  mc_extends[0]
 382              else
 383                  MCLN::Block.new(
 384                      e_tk.line_no, MCLA::SetOfSubject.new(mc_extends)
 385                  )
 386              end
 387                                          # MCLN::Extend, MCLN::Block, or nil
 388          ASSERT.opt_kind_of mc_extend, MCLA::Subject
 389      end
 390 
 391 
 392 
 393      def parse_include(scanner, above_path, env, i_tk)
 394          ASSERT.kind_of scanner,     Scanner
 395          ASSERT.kind_of above_path,  MCLP::AbsolutePath
 396          ASSERT.kind_of env,         ENV::Environment
 397          ASSERT.kind_of i_tk,        TkIDENTIFIER
 398 
 399          LOG::Debug.msgout "CALLED " +
 400                          "above_path=#{above_path}" if env.debug_parser?
 401 
 402          seq_num     = 0
 403          mc_includes = []
 404          loop do
 405              scanner.skip_space_or_nl!
 406              tk = scanner.peek
 407              case tk
 408              when TkCONSTANT, TkCOLON2, TkCOLON3
 409                  name = Common.get_constant(scanner, env)
 410 
 411                  mc_includes << MCLL::Include.new(tk.line_no, seq_num, name)
 412                  seq_num += 1
 413 
 414              when TkSELF
 415                  mc_includes << MCLL::Include.new(tk.line_no, seq_num, nil)
 416                  seq_num += 1
 417 
 418              else
 419                  LOG::Warning.log(
 420                      "The 'include' expected constant, but: %s<%s>.\n" +
 421                              "\t-- #%d in '%s'",
 422                      if tk.respond_to?(:name) then tk.name else '' end,
 423                      tk.class.to_s,
 424                              tk.line_no, scanner.file_name
 425                  )
 426                  CMD.test_sensitive_level env, LOG::Warning
 427              end
 428 
 429              unless scanner.peek.kind_of?(TkCOMMA)
 430                  break
 431              end
 432 
 433              scanner.get!
 434          end
 435          if env.debug_parser?
 436              for mc_include in mc_includes
 437                  LOG::Debug.msgout("ACCEPT %s", mc_include.to_s)
 438              end
 439          end
 440 
 441          mc_include =
 442              case mc_includes.size
 443              when 0
 444                  nil
 445              when 1
 446                  mc_includes[0]
 447              else
 448                  MCLN::Block.new(
 449                      i_tk.line_no, MCLA::SetOfSubject.new(mc_includes)
 450                  )
 451              end
 452                                      # MCLN::Include, MCLN::Block, or nil
 453          ASSERT.opt_kind_of mc_include, MCLA::Subject
 454      end
 455 
 456 
 457 
 458      def parse_module_func(scanner, above_path, context, env, m_tk)
 459          ASSERT.kind_of  scanner,    Scanner
 460          ASSERT.kind_of  above_path, MCLP::AbsolutePath
 461          ASSERT.kind_of  context,    Context
 462          ASSERT.kind_of  env,        ENV::Environment
 463          ASSERT.kind_of  m_tk,       TkIDENTIFIER
 464 
 465          LOG::Debug.msgout "CALLED " +
 466                      "above_path='#{above_path.to_s}'" if env.debug_parser?
 467 
 468          args = SeqOfArgument.new
 469          loop do
 470              scanner.skip_space_or_nl!
 471              tk = scanner.get!
 472              case tk
 473              when TkSYMBOL
 474                  args.add! Argument.new(tk.value, tk.line_no)
 475              else
 476                  scanner.unget! tk
 477                  break
 478              end
 479 
 480              scanner.skip_space!
 481              tk1 = scanner.get!
 482              case tk1
 483              when TkCOMMA
 484                  ;   # nop
 485              when TkNL
 486                  scanner.unget! tk1
 487                  break
 488              else
 489                  break
 490              end
 491          end
 492          LOG::Debug.log(
 493              "args: '%s' -- #%d in %",
 494              format("[%s]", args.map { |arg| arg.name }.join(', ')),
 495              __LINE__, __FILE__
 496          ) if env.debug_parser?
 497 
 498          mc_block =
 499              if args.empty?
 500                  nil         # None argument.
 501              else
 502                  mc_module_funcs = args.map_with_index { |arg, seq_num|
 503                      MCLL::ModuleFunc.new(
 504                          arg.line_num, seq_num, arg.name.gsub(/^:/, '')
 505                      )
 506                  }
 507                  if env.debug_parser?
 508                      for mc_module_func in mc_module_funcs
 509                          LOG::Debug.msgout(
 510                              "ACCEPT %s", mc_module_func.to_s
 511                          )
 512                      end
 513                  end
 514 
 515                  MCLN::Block.new(
 516                      m_tk.line_no, MCLA::SetOfSubject.new(mc_module_funcs)
 517                  )
 518              end
 519 
 520          ASSERT.opt_kind_of mc_block, MCLN::Block
 521      end
 522  end
 523 
 524  end # TmDoc::Reader::Ruby18::Parser
 525 
 526  end # TmDoc::Reader::Ruby18
 527 
 528  end # TmDoc