diff options
Diffstat (limited to 'lib/sly/docparse.py')
-rw-r--r-- | lib/sly/docparse.py | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/lib/sly/docparse.py b/lib/sly/docparse.py new file mode 100644 index 0000000..d5a83ce --- /dev/null +++ b/lib/sly/docparse.py @@ -0,0 +1,60 @@ +# docparse.py +# +# Support doc-string parsing classes + +__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') |