Package libxyz :: Package parser :: Module multi |
[hide private]
[frames] | no frames]

# Source Code for Module libxyz.parser.multi

      1  #-*- coding: utf8 -*
      2  #
      3  # Max E. Kuznecov ~syhpoon <syhpoon@syhpoon.name> 2008
      4  #
      5  # This file is part of XYZCommander.
      6  # XYZCommander is free software: you can redistribute it and/or modify
      7  # it under the terms of the GNU Lesser Public License as published by
      8  # the Free Software Foundation, either version 3 of the License, or
      9  # (at your option) any later version.
     10  # XYZCommander is distributed in the hope that it will be useful,
     11  # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     13  # GNU Lesser Public License for more details.
     14  # You should have received a copy of the GNU Lesser Public License
     15  # along with XYZCommander. If not, see <http://www.gnu.org/licenses/>.
     16
     17  import re
     18
     19  from libxyz.parser import Lexer
     20  from libxyz.parser import BaseParser
     21  from libxyz.parser import SourceData
     22  from libxyz.exceptions import XYZValueError
     23  from libxyz.exceptions import LexerError
     24  from libxyz.exceptions import ParseError
     25
     26 -class MultiParser(BaseParser):
     27      """
     28      MultiParser is a simple container for any other parsers
     29      Usually parsers, such as BlockParser designed to parse homogeneous blocks in
     30      single source: file or string. But still it might be useful sometimes to
     31      parse multiple blocks of different syntax in single source.
     32      Thus, one can register some necessary parsers into MultiParser and go on.
     33      """
     34
     35      DEFAULT_OPT = {
     36                     u"comment": u"#",
     37                     u"tokens": (),
     38                     }
     39
     40 -    def __init__(self, parsers, opt=None):
     41          """
     42          @param parsers: dictionary containing string, list or
     43                          compiled regexp of keywords as key
     44                          and *Parser objects as values.
     45          @type parsers: dictionary with string or sequence keys
     46
     47          @param opt: Options
     48
     49          Available options:
     50          - comment: Comment character.
     51            Everything else ignored until EOL.
     52            Type: I{string (single char)}
     53
     54          - tokens: List of tokens.
     55            Type: I{sequence}
     56          """
     57
     58          super(MultiParser, self).__init__()
     59
     60          self._rx = re.compile("")
     61
     62          if parsers:
     63              if not isinstance(parsers, dict):
     64                  raise XYZValueError(_(u"Invalid argument type %s. "\
     65                                        u"Dictionary expected" % str(parsers)))
     66              else:
     67                  self.parsers = parsers
     68          else:
     69              self.parsers = {}
     70
     71          self.opt = opt or self.DEFAULT_OPT
     72          self.set_opt(self.DEFAULT_OPT, self.opt)
     73
     74          self._lexer = None
     75          self._result = {}
     76
     77      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     78
     79 -    def parse(self, source, default_data=None):
     80          """
     81          Begin parsing
     82          """
     83
     84          def _get_parser(val):
     85              _p = None
     86
     87              for _key in self.parsers:
     88                  # First string
     89                  if isinstance(_key, basestring) and _key == val:
     90                      _p = self.parsers[_key]
     91                      break
     92                  # Next sequence
     93                  elif hasattr(_key, "__contains__") and val in _key:
     94                      _p = self.parsers[_key]
     95                      break
     96                  # Otherwise regexp
     97                  elif type(_key) is type(self._rx) and _key.match(val):
     98                      _p = self.parsers[_key]
     99                      break
    100
    101              return _p
    102
    103          #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    104
    105          self._result = {}
    106          self._lexer = Lexer(source, self.tokens, self.comment)
    107
    108          _data = default_data or {}
    109
    110          try:
    111              while True:
    112                  _res = self._lexer.lexer()
    113
    114                  if _res is None:
    115                      break
    116                  else:
    117                      _lex, _val = _res
    118
    119                  _parser = _get_parser(_val)
    120
    121                  if _parser:
    122                      # Push read token back
    123                      self._lexer.unget(_val)
    124                      _data = _parser.parse(self._lexer.sdata, _data)
    125                      self._result.update(_data)
    126                  else:
    127                      self.error(_(u"Unknown keyword: %s" % _val))
    128          except LexerError, e:
    129              self.error(str(e))
    130
    131          return self._result
    132
    133      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    134
    135 -    def register(self, keyword, parser):
    136          """
    137          Register new parser. If parser for keyword given already registered
    138          replace it with new one.
    139
    140          @param keyword: Keyword that will trigger the parser.
    141          @type keyword: string, sequence or compiled regular expression
    142
    143          @param param: Any *Parser instance. Must be subclassed
    144                        from L{BaseParser}.
    145          """
    146
    147          if not isinstance(parser, BaseParser):
    148              raise XYZValueError(_(u"Invalid argument type %s. "\
    149                                    u"BaseParser or subclassed expected" % \
    150                                    str(parsers)))
    151
    152          self.parsers[keyword] = parser
    153
    154      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    155
    156 -    def unregister(self, keyword):
    157          """
    158          Unregister parser. Ignore if was not registered.
    159          """
    160
    161          try:
    162              del(self.parsers[keyword])
    163          except KeyError:
    164              pass
    165