Added docparse

This commit is contained in:
David Beazley
2018-09-27 14:22:51 -05:00
parent 6a27431f81
commit 5fdc971f36
3 changed files with 264 additions and 0 deletions

25
sly/ast.py Normal file
View 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
View 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')