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)