"""
	Author: GianC-Dev <gianegekck@gmail.com>
					  _    _
					 | |  | |
					 | |__| | __ ___   ____ _
					 |  __  |/ _` \ \ / / _` |
					 | |  | | (_| |\ V / (_| |
					 |_|  |_|\__,_| \_/ \__,_|
      
	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.
"""


__all__ = [ 'DocParseMeta' ]

class DocParseMeta(type):
    '''
    Metaclass that processes the class docstring through a parser and
    incorporates the result into the resulting class definition. This
    allows Python classes to be defined with alternative syntax. 
    To use this class, you first need to define a lexer and parser:

        from sly import Lexer, Parser
        class MyLexer(Lexer):
           ...

        class MyParser(Parser):
           ...

    You then need to define a metaclass that inherits from DocParseMeta.
    This class must specify the associated lexer and parser classes.
    For example:

        class MyDocParseMeta(DocParseMeta):
            lexer = MyLexer
            parser = MyParser

    This metaclass is then used as a base for processing user-defined
    classes:

        class Base(metaclass=MyDocParseMeta):
            pass

        class Spam(Base):
            """
            doc string is parsed
            ...
            """

    It is expected that the MyParser() class would return a dictionary. 
    This dictionary is used to create the final class Spam in this example.
    '''

    @staticmethod
    def __new__(meta, clsname, bases, clsdict):
        if '__doc__' in clsdict:
            lexer = meta.lexer()
            parser = meta.parser()
            lexer.cls_name = parser.cls_name = clsname
            lexer.cls_qualname = parser.cls_qualname = clsdict['__qualname__']
            lexer.cls_module = parser.cls_module = clsdict['__module__']
            parsedict = parser.parse(lexer.tokenize(clsdict['__doc__']))
            assert isinstance(parsedict, dict), 'Parser must return a dictionary'
            clsdict.update(parsedict)
        return super().__new__(meta, clsname, bases, clsdict)

    @classmethod
    def __init_subclass__(cls):
        assert hasattr(cls, 'parser') and hasattr(cls, 'lexer')
