github.com/grumpyhome/grumpy@v0.3.1-0.20201208125205-7b775405bdf1/grumpy-tools-src/grumpy_tools/compiler/parser.py (about)

     1  # coding: utf-8
     2  """
     3  Grumpy uses `pythonparser` as its AST parser. This module contains an augmented
     4  (extended) parser from it, letting us to accept special Grumpy-only syntax, like
     5  the `import '__go__/...'` syntax for importing Go code.
     6  """
     7  import logging
     8  
     9  import pythonparser.parser
    10  from pythonparser.parser import Parser, Seq, Loc, Opt, Tok, List, Alt, Rule, action
    11  from pythonparser import ast
    12  
    13  logger = logging.getLogger(__name__)
    14  
    15  PYTHNOPARSER_PATCHED = False
    16  
    17  
    18  def patch_pythonparser():
    19      global PYTHNOPARSER_PATCHED
    20      if PYTHNOPARSER_PATCHED:
    21          return False
    22  
    23      logger.info('Monkeypatching pythonparser.parser.Parser with Grumpy extensions')
    24      pythonparser.parser.Parser = GrumpyParser
    25      PYTHNOPARSER_PATCHED = True
    26      return True
    27  
    28  
    29  class GrumpyParser(Parser):
    30      # From: https://github.com/google/grumpy/commit/9d80504e8d42c4a03ece9ed983b0ca160d170969#diff-c46e216e8423951b5f41dde139575b68R1038
    31      @action(Rule("atom_5"))
    32      def import_from_7(self, string):
    33          return (None, 0), (string.loc, string.s)
    34  
    35      # From: https://github.com/google/grumpy/commit/9d80504e8d42c4a03ece9ed983b0ca160d170969#diff-c46e216e8423951b5f41dde139575b68R1046
    36      @action(Seq(Loc("from"), Alt(Parser.import_from_3, Parser.import_from_4, import_from_7),
    37                  Loc("import"), Alt(Parser.import_from_5,
    38                                     Seq(Loc("("), Rule("import_as_names"), Loc(")")),
    39                                     Parser.import_from_6)))
    40      def import_from(self, from_loc, module_name, import_loc, names):
    41          """
    42          (2.6, 2.7)
    43          import_from: ('from' ('.'* dotted_name | '.'+)
    44                      'import' ('*' | '(' import_as_names ')' | import_as_names))
    45          (3.0-)
    46          # note below: the ('.' | '...') is necessary because '...' is tokenized as ELLIPSIS
    47          import_from: ('from' (('.' | '...')* dotted_name | ('.' | '...')+)
    48                      'import' ('*' | '(' import_as_names ')' | import_as_names))
    49          """
    50          (dots_loc, dots_count), dotted_name_opt = module_name
    51          module_loc = module = None
    52          if dotted_name_opt:
    53              module_loc, module = dotted_name_opt
    54          lparen_loc, names, rparen_loc = names
    55          loc = from_loc.join(names[-1].loc)
    56          if rparen_loc:
    57              loc = loc.join(rparen_loc)
    58  
    59          if module == "__future__":
    60              self.add_flags([x.name for x in names])
    61  
    62          return ast.ImportFrom(names=names, module=module, level=dots_count,
    63                                keyword_loc=from_loc, dots_loc=dots_loc, module_loc=module_loc,
    64                                import_loc=import_loc, lparen_loc=lparen_loc, rparen_loc=rparen_loc,
    65                                loc=loc)
    66  
    67      @action(Seq(Rule("atom_5"), Opt(Seq(Loc("as"), Tok("ident")))))
    68      def str_as_name(self, string, as_name_opt):
    69          asname_name = asname_loc = as_loc = None
    70          loc = string.loc
    71          if as_name_opt:
    72              as_loc, asname = as_name_opt
    73              asname_name = asname.value
    74              asname_loc = asname.loc
    75              loc = loc.join(asname.loc)
    76          return ast.alias(name=string.s, asname=asname_name,
    77                           loc=loc, name_loc=string.loc, as_loc=as_loc, asname_loc=asname_loc)
    78  
    79      dotted_as_names = List(Alt(Rule("dotted_as_name"), Rule("str_as_name")), ",", trailing=False)