def register(cls, symbol, **kwargs): """ Register/update a token class in the symbol table. :param symbol: The identifier symbol for a new class or an existent token class. :param kwargs: Optional attributes/methods for the token class. :return: A token class. """ try: try: if ' ' in symbol: raise ValueError("%r: a symbol can't contain whitespaces" % symbol) except TypeError: assert isinstance(symbol, type) and issubclass(symbol, Token), \ "A %r subclass requested, not %r." % (Token, symbol) symbol, token_class = symbol.symbol, symbol assert symbol in cls.symbol_table and cls.symbol_table[symbol] is token_class, \ "Token class %r is not registered." % token_class else: token_class = cls.symbol_table[symbol] except KeyError: # Register a new symbol and create a new custom class. The new class # name is registered at parser class's module level. if symbol not in cls.SYMBOLS: raise NameError('%r is not a symbol of the parser %r.' % (symbol, cls)) kwargs['symbol'] = symbol label = kwargs.get('label', 'symbol') if isinstance(label, tuple): label = kwargs['label'] = MultiLabel(*label) token_class_name = "_{}{}".format( symbol_to_classname(symbol), str(label).title().replace(' ', '') ) token_class_bases = kwargs.get('bases', (cls.token_base_class,)) kwargs.update({ '__module__': cls.__module__, '__qualname__': token_class_name, '__return__': None }) token_class = ABCMeta(token_class_name, token_class_bases, kwargs) cls.symbol_table[symbol] = token_class MutableSequence.register(token_class) setattr(sys.modules[cls.__module__], token_class_name, token_class) else: for key, value in kwargs.items(): if key == 'lbp' and value > token_class.lbp: token_class.lbp = value elif key == 'rbp' and value > token_class.rbp: token_class.rbp = value elif callable(value): setattr(token_class, key, value) return token_class
def register(cls, symbol, **kwargs): """ Register/update a token class in the symbol table. :param symbol: The identifier symbol for a new class or an existent token class. :param kwargs: Optional attributes/methods for the token class. :return: A token class. """ def symbol_escape(s): s = re.escape(s) s.replace(r'\ ', r'\s+') if s.isalpha(): s = r'\b%s\b(?![\-\.])' % s elif s[-2:] == r'\(': s = r'%s\s*%s' % (s[:-2], s[-2:]) elif s[-4:] == r'\:\:': s = r'%s\s*%s' % (s[:-4], s[-4:]) return s try: try: if ' ' in symbol: raise ValueError( "%r: a symbol can't contains whitespaces." % symbol) except TypeError: assert isinstance(symbol, type) and issubclass(symbol, Token), \ "A %r subclass requested, not %r." % (Token, symbol) symbol, token_class = symbol.symbol, symbol assert symbol in cls.symbol_table and cls.symbol_table[symbol] is token_class, \ "Token class %r is not registered." % token_class else: token_class = cls.symbol_table[symbol] except KeyError: # Register a new symbol and create a new custom class. The new class # name is registered at parser class's module level. if symbol not in cls.SYMBOLS: raise NameError('%r is not a symbol of the parser %r.' % (symbol, cls)) kwargs['symbol'] = symbol if 'pattern' not in kwargs: pattern = symbol_escape( symbol) if len(symbol) > 1 else re.escape(symbol) kwargs['pattern'] = pattern label = kwargs.get('label', 'symbol') if isinstance(label, tuple): label = kwargs['label'] = MultiLabel(*label) token_class_name = "_{}_{}_token".format( symbol_to_identifier(symbol), str(label).replace(' ', '_')) token_class_bases = (getattr(cls, 'token_base_class', object), ) kwargs.update({ '__module__': cls.__module__, '__qualname__': token_class_name, '__return__': None }) token_class = ABCMeta(token_class_name, token_class_bases, kwargs) cls.symbol_table[symbol] = token_class MutableSequence.register(token_class) setattr(sys.modules[cls.__module__], token_class_name, token_class) else: for key, value in kwargs.items(): if key == 'lbp' and value > token_class.lbp: token_class.lbp = value elif key == 'rbp' and value > token_class.rbp: token_class.rbp = value elif callable(value): setattr(token_class, key, value) return token_class