Added docparse
This commit is contained in:
25
sly/ast.py
Normal file
25
sly/ast.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# sly/ast.py
|
||||
import sys
|
||||
|
||||
class AST(object):
|
||||
|
||||
@classmethod
|
||||
def __init_subclass__(cls, **kwargs):
|
||||
mod = sys.modules[cls.__module__]
|
||||
if not hasattr(cls, '__annotations__'):
|
||||
return
|
||||
|
||||
hints = list(cls.__annotations__.items())
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if len(hints) != len(args):
|
||||
raise TypeError(f'Expected {len(hints)} arguments')
|
||||
for arg, (name, val) in zip(args, hints):
|
||||
if isinstance(val, str):
|
||||
val = getattr(mod, val)
|
||||
if not isinstance(arg, val):
|
||||
raise TypeError(f'{name} argument must be {val}')
|
||||
setattr(self, name, arg)
|
||||
|
||||
cls.__init__ = __init__
|
||||
|
60
sly/docparse.py
Normal file
60
sly/docparse.py
Normal file
@@ -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')
|
Reference in New Issue
Block a user