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

Overview
Module Structure
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: TmDoc#12
  module: Reader
  module: Ruby18#14
  module: Parser#16
has properties
function: parse / 2 #21
  module: Statements#38
includes
  RubyToken ( Builtin-Module )
has properties
function: parse / 4 #43
function: parse_identifier / 5 #222
constant: SKIPPED_TOKENS #308
function: skip_tokens / 2 #318

Code

   1  # $Id: parser.rb,v 1.3 2011/11/28 11:06:05 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/node'
   9  require 'tmdoc/reader/ruby1.8/parser/leaf'
  10 
  11 
  12  module TmDoc
  13 
  14  module Reader::Ruby18
  15 
  16  module Parser
  17 
  18  module_function
  19 
  20 
  21      def parse(scanner, env)
  22          ASSERT.kind_of scanner, Scanner
  23          ASSERT.kind_of env,     ENV::Environment
  24 
  25          mc_subjects = Statements.parse(
  26              scanner,
  27              MCLP::AbsolutePath.new_root,
  28              Context.new,
  29              env
  30          )
  31          ASSERT.kind_of mc_subjects, MCLA::SetOfSubject
  32 
  33          MCLN::ToplevelModule.new(mc_subjects)
  34      end
  35 
  36 
  37 
  38  module Statements
  39      include RubyToken
  40 
  41  module_function
  42 
  43      def parse(scanner, above_path, context, env)
  44          ASSERT.kind_of scanner,     Scanner
  45          ASSERT.kind_of above_path,  MCLP::AbsolutePath
  46          ASSERT.kind_of context,     Context
  47          ASSERT.kind_of env,         ENV::Environment
  48 
  49          LOG::Debug.msgout "CALLED " +
  50                      "above_path='#{above_path}'" if env.debug_parser?
  51 
  52          mc_subjects = MCLA::SetOfSubject.new
  53          nest        = 1
  54          prev_tk     = nil
  55          while tk = scanner.get!
  56              new_mc_subjects = 
  57                  case tk
  58 
  59                  when TkMODULE       # 'module'
  60                      if context.in_unique_class?
  61                          LOG::Warning.log(
  62                              "I can't parse module definiation " +
  63                                          "in unique class definiation.\n" +
  64                                  "\t-- #%d in '%s'",
  65                              name,
  66                                  tk.line_no, scanner.file_name
  67                          )
  68                          CMD.test_sensitive_level env, LOG::Warning
  69 
  70                          skip_tokens(scanner, env)
  71 
  72                          mc_subjects
  73                      else
  74                          mc_module = Node::Module.parse(
  75                              scanner, above_path, context, env, tk
  76                          )
  77 
  78                          if mc_module
  79                              mc_subjects << mc_module
  80                          else
  81                              skip_tokens(scanner, env)
  82 
  83                              mc_subjects
  84                          end
  85                      end
  86 
  87                  when TkCLASS        # 'class'
  88                      if context.in_unique_class?
  89                          LOG::Warning.log(
  90                              "I can't parse class definiation " +
  91                                          "in unique class definiation.\n" +
  92                                  "\t-- #%d in '%s'",
  93                                  tk.line_no, scanner.file_name
  94                          )
  95                          CMD.test_sensitive_level env, LOG::Warning
  96 
  97                          skip_tokens(scanner, env)
  98 
  99                          mc_subjects
 100                      else
 101                          msub = Node::Class.parse(
 102                              scanner, above_path, context, env, tk
 103                          )
 104 
 105                          if msub
 106                              mc_subjects << msub
 107                          else
 108                              skip_tokens(scanner, env)
 109 
 110                              mc_subjects
 111                          end
 112                      end
 113 
 114                  when TkDEF          # 'def'
 115                      mc_method = Node::Method.parse(
 116                          scanner, above_path, context, env, tk
 117                      )
 118 
 119                      if mc_method
 120                          mc_subjects << mc_method
 121                      else
 122                          skip_tokens(scanner, env)
 123 
 124                          mc_subjects
 125                      end
 126 
 127                  when TkCONSTANT
 128                      mc_constant = Leaf.parse_constant(
 129                          scanner, above_path, context, env, tk
 130                      )
 131 
 132                      if mc_constant
 133                          mc_subjects << mc_constant
 134                      else
 135                          mc_subjects
 136                      end
 137 
 138                  when TkALIAS        # 'alias'
 139                      mc_alias = Leaf.parse_alias(
 140                          scanner, above_path, context, env, tk
 141                      )
 142 
 143                      if mc_alias
 144                          mc_subjects << mc_alias
 145                      else
 146                          mc_subjects
 147                      end
 148 
 149                  when TkIDENTIFIER
 150                      case prev_tk
 151                      when TkDOT
 152                          LOG::Debug.log(
 153                              "TkIDENTIFIER(%s) at #%d [#%d]",
 154                              tk.name,
 155                              tk.line_no,
 156                              __LINE__
 157                          ) if env.debug_parser?
 158 
 159                          mc_subjects
 160 
 161                      else
 162                          msub, context = parse_identifier(
 163                              tk, scanner, above_path, context, env
 164                          )
 165 
 166                          if msub
 167                              mc_subjects << msub
 168                          else
 169                              mc_subjects
 170                          end
 171                      end
 172 
 173                  when TkCASE,        # 'case'
 174                          TkDO,       # 'do'
 175                          TkFOR,      # 'for'
 176                          TkIF,       # 'if'
 177                          TkUNLESS,   # 'unless'
 178                          TkUNTIL,    # 'until'
 179                          TkWHILE,    # 'while'
 180                          TkBEGIN     # 'begin'
 181                      nest += 1
 182 
 183                      mc_subjects
 184 
 185                  when TkEND          # 'end'
 186                      nest -= 1
 187                      LOG::Debug.log(
 188                          "Found 'end' on #{above_path.to_s}, " +
 189                          "nest=#{nest}, " +
 190                          "line #{tk.line_no}"
 191                      ) if env.debug_parser?
 192                      if nest <= 0
 193                          ASSERT.kind_of mc_subjects, MCLA::SetOfSubject
 194 
 195                          return mc_subjects
 196                      end
 197 
 198                      mc_subjects
 199 
 200                  else
 201                      LOG::Debug.log(
 202                          "%s at #%d [#%d]",
 203                          tk.class, tk.line_no, __LINE__
 204                      ) if env.debug_parser?
 205 
 206                      mc_subjects
 207                  end
 208              mc_subjects = new_mc_subjects
 209              prev_tk     = tk
 210 
 211              begin
 212                  scanner.get_readed!
 213                  scanner.skip_space!
 214              end while scanner.peek == TkNL
 215          end
 216 
 217          ASSERT.kind_of mc_subjects, MCLA::SetOfSubject
 218      end
 219 
 220 
 221 
 222      def parse_identifier(tk, scanner, above_path, context, env)
 223          ASSERT.kind_of tk,          TkIDENTIFIER
 224          ASSERT.kind_of scanner,     Scanner
 225          ASSERT.kind_of above_path,  MCLP::AbsolutePath
 226          ASSERT.kind_of context,     Context
 227          ASSERT.kind_of env,         ENV::Environment
 228 
 229          LOG::Debug.msgout "CALLED name #{tk.name}, " +
 230                      "above_path='#{above_path}'" if env.debug_parser?
 231 
 232          mc_subject, new_context =
 233              case tk.name
 234              when 'require'
 235                  [Leaf.parse_require(scanner, above_path, env), context]
 236 
 237              when 'extend'
 238                  if context.in_unique_class?
 239                      LOG::Warning.log(
 240                          "I can't parse module extending " +
 241                                          "in unique class.\n" +
 242                              "\t-- #%d in '%s'",
 243                          name,
 244                              tk.line_no, scanner.file_name
 245                      )
 246                      CMD.test_sensitive_level env, LOG::Warning
 247 
 248                      [nil, context]
 249                  else
 250                      [
 251                          Leaf.parse_extend(scanner, above_path, env, tk),
 252                          context
 253                      ]
 254                  end
 255 
 256              when 'include'
 257                  [
 258                      Leaf.parse_include(scanner, above_path, env, tk),
 259                      context
 260                  ]
 261 
 262              when 'attr'
 263                  [
 264                      Leaf.parse_attribute(
 265                          scanner, above_path, context, env, tk, nil
 266                      ),
 267                      context
 268                  ]
 269 
 270              when /^attr_(reader|writer|accessor)$/
 271                  [
 272                      Leaf.parse_attribute(
 273                          scanner, above_path, context, env, tk, $1
 274                      ),
 275                      context
 276                  ]
 277 
 278              when /^module_function$/
 279                  msub = Leaf.parse_module_func(
 280                      scanner, above_path, context, env, tk
 281                  )
 282 
 283                  if msub
 284                      [msub, context]
 285                  else
 286 
 287                      [nil, context.update_module_func(true)]
 288                  end
 289 
 290              else
 291                  LOG::Debug.log(
 292                      "TkIDENTIFIER(%s) at #%d [#%d]",
 293                      tk.name,
 294                      tk.line_no,
 295                      __LINE__
 296                  ) if env.debug_parser?
 297 
 298                  [nil, context]
 299              end
 300 
 301          ASSERT.opt_kind_of  mc_subject,     MCLA::Subject
 302          ASSERT.kind_of      new_context,    Context
 303          [mc_subject, new_context]
 304      end
 305 
 306 
 307 
 308      SKIPPED_TOKENS = [  :module,
 309                          :class,
 310                          :method,
 311                          :const,
 312                          :require,
 313                          :alias,
 314                          :extend,
 315                          :include,
 316                          :attr ]
 317 
 318      def skip_tokens(scanner, env)
 319          ASSERT.kind_of scanner, Scanner
 320          ASSERT.kind_of env,     ENV::Environment
 321 
 322          LOG::Debug.msgout "CALLED" if env.debug_parser?
 323          LOG::Debug.log "Begin skipping" if env.debug_parser?
 324 
 325          map_of_skipping_token_sym_to_num = Hash[
 326              *(
 327                  SKIPPED_TOKENS.map { |token_sym| [token_sym, 0] }
 328              ).flatten
 329          ]
 330 
 331          skipping_nest = 1
 332          while tk = scanner.get!
 333              case tk
 334              when TkMODULE
 335                  map_of_skipping_token_sym_to_num[:module] += 1
 336                  skipping_nest += 1
 337 
 338              when TkCLASS
 339                  map_of_skipping_token_sym_to_num[:class] += 1
 340                  skipping_nest += 1
 341 
 342              when TkDEF
 343                  map_of_skipping_token_sym_to_num[:method] += 1
 344                  skipping_nest += 1
 345 
 346              when TkCONSTANT
 347                  map_of_skipping_token_sym_to_num[:const] += 1
 348 
 349              when TkALIAS        # 'alias'
 350                  map_of_skipping_token_sym_to_num[:alias] += 1
 351 
 352              when TkIDENTIFIER
 353                  case tk.name
 354                  when "require"
 355                      map_of_skipping_token_sym_to_num[:require] += 1
 356 
 357                  when "extend"
 358                      map_of_skipping_token_sym_to_num[:extend] += 1
 359 
 360                  when "include"
 361                      map_of_skipping_token_sym_to_num[:include] += 1
 362 
 363                  when "attr", /^attr_(reader|writer|accessor)$/
 364                      map_of_skipping_token_sym_to_num[:attr] += 1
 365 
 366                  else
 367                      ;   # Skip others ....
 368                  end
 369 
 370              when TkCASE,        # 'case'
 371                      TkDO,       # 'do'
 372                      TkFOR,      # 'for'
 373                      TkIF,       # 'if'
 374                      TkUNLESS,   # 'unless'
 375                      TkUNTIL,    # 'until'
 376                      TkWHILE,    # 'while'
 377                      TkBEGIN     # 'begin'
 378                  skipping_nest += 1
 379 
 380              when TkLBRACE, TkfLBRACE, TkLPAREN, TkfLPAREN
 381                  skipping_nest += 1
 382 
 383              when TkRBRACE, TkRPAREN
 384                  skipping_nest -= 1
 385 
 386              when TkEND          # 'end'
 387                  skipping_nest -= 1
 388                  if skipping_nest <= 0
 389                      break
 390                  end
 391 
 392              else
 393                  ;   # Skip others ....
 394              end
 395          end
 396 
 397          unless tk.kind_of?(TkEND)
 398              scanner.unget! tk
 399          end
 400 
 401          if map_of_skipping_token_sym_to_num.values.any? { |num| num > 0 }
 402              msg_args = map_of_skipping_token_sym_to_num.reject {
 403                  |sym, num|
 404 
 405                  num == 0
 406              }.map { |sym, num| format("%s=%d", sym, num) }.join(', ')
 407 
 408              LOG::Notice.log "==> Skipped tokens: %s", msg_args
 409              CMD.test_sensitive_level env, LOG::Notice
 410          end
 411          LOG::Debug.log(
 412              "End skipping[##{tk.line_no}]"
 413          ) if env.debug_parser?
 414 
 415          nil
 416      end
 417  end
 418 
 419  end # TmDoc::Reader::Ruby18::Parser
 420 
 421  end # TmDoc::Reader::Ruby18
 422 
 423  end # TmDoc