[Python-checkins] python/dist/src/Tools/framer/framer __init__.py,NONE,1.1 bases.py,NONE,1.1 function.py,NONE,1.1 member.py,NONE,1.1 slots.py,NONE,1.1 struct.py,NONE,1.1 structparse.py,NONE,1.1 template.py,NONE,1.1 util.py,NONE,1.1

jhylton@users.sourceforge.net jhylton@users.sourceforge.net
2002年8月05日 11:29:48 -0700


Update of /cvsroot/python/python/dist/src/Tools/framer/framer
In directory usw-pr-cvs1:/tmp/cvs-serv10915/framer/framer
Added Files:
	__init__.py bases.py function.py member.py slots.py struct.py 
	structparse.py template.py util.py 
Log Message:
Initial prototype of framer: a tool to build the frame for extension modules.
--- NEW FILE: __init__.py ---
"""A tool to generate basic framework for C extension types.
The basic ideas is the same as modulator, but the code generates code
using many of the new features introduced in Python 2.2. It also
takes a more declarative approach to generating code.
"""
--- NEW FILE: bases.py ---
"""Provides the Module and Type base classes that user code inherits from."""
__all__ = ["Module", "Type", "member"]
from framer import struct, template
from framer.function import Function, Method
from framer.member import member
from framer.slots import *
from framer.util import cstring, unindent
from types import FunctionType
def sortitems(dict):
 L = dict.items()
 L.sort()
 return L
# The Module and Type classes are implemented using metaclasses,
# because most of the methods are class methods. It is easier to use
# metaclasses than the cumbersome classmethod() builtin. They have
# class methods because they are exposed to user code as base classes.
class BaseMetaclass(type):
 """Shared infrastructure for generating modules and types."""
 # just methoddef so far
 def dump_methoddef(self, f, functions, vars):
 def p(templ, vars=vars): # helper function to generate output
 print >> f, templ % vars
 if not functions:
 return
 p(template.methoddef_start)
 for name, func in sortitems(functions):
 if func.__doc__:
 p(template.methoddef_def_doc, func.vars)
 else:
 p(template.methoddef_def, func.vars)
 p(template.methoddef_end)
class ModuleMetaclass(BaseMetaclass):
 """Provides methods for Module class."""
 def gen(self):
 self.analyze()
 self.initvars()
 f = open(self.__filename, "w")
 self.dump(f)
 f.close()
 def analyze(self):
 self.name = getattr(self, "abbrev", self.__name__)
 self.__functions = {}
 self.__types = {}
 self.__members = False
 for name, obj in self.__dict__.iteritems():
 if isinstance(obj, FunctionType):
 self.__functions[name] = Function(obj, self)
 elif isinstance(obj, TypeMetaclass):
 obj._TypeMetaclass__module = self.name
 obj.analyze()
 self.__types[name] = obj
 if obj.has_members():
 self.__members = True
 
 def initvars(self):
 v = self.__vars = {}
 filename = getattr(self, "__file__", None)
 if filename is None:
 filename = self.__name__ + "module.c"
 self.__filename = v["FileName"] = filename
 name = v["ModuleName"] = self.__name__
 v["MethodDefName"] = "%s_methods" % name
 v["ModuleDocstring"] = cstring(unindent(self.__doc__))
 def dump(self, f):
 def p(templ, vars=self.__vars): # helper function to generate output
 print >> f, templ % vars
 p(template.module_start)
 if self.__members:
 p(template.member_include)
 print >> f
 
 if self.__doc__:
 p(template.module_doc)
 for name, type in sortitems(self.__types):
 type.dump(f)
 for name, func in sortitems(self.__functions):
 func.dump(f)
 self.dump_methoddef(f, self.__functions, self.__vars)
 p(template.module_init_start)
 for name, type in sortitems(self.__types):
 type.dump_init(f)
 
 p("}")
class Module:
 __metaclass__ = ModuleMetaclass
class TypeMetaclass(BaseMetaclass):
 def dump(self, f):
 self.initvars()
 # defined after initvars() so that __vars is defined
 def p(templ, vars=self.__vars):
 print >> f, templ % vars
 if self.struct is not None:
 print >> f, unindent(self.struct, False)
 if self.__doc__:
 p(template.docstring)
 for name, func in sortitems(self.__methods):
 func.dump(f)
 
 self.dump_methoddef(f, self.__methods, self.__vars)
 self.dump_memberdef(f)
 self.dump_slots(f)
 def has_members(self):
 if self.__members:
 return True
 else:
 return False
 def analyze(self):
 # called by ModuleMetaclass analyze()
 self.name = getattr(self, "abbrev", self.__name__)
 src = getattr(self, "struct", None)
 if src is not None:
 self.__struct = struct.parse(src)
 else:
 self.__struct = None
 self.__methods = {}
 self.__members = {}
 for cls in self.__mro__:
 for k, v in cls.__dict__.iteritems():
 if isinstance(v, FunctionType):
 self.__methods[k] = Method(v, self)
 if isinstance(v, member):
 self.__members[k] = v
 assert self.__struct is not None
 v.register(k, self.__struct)
 self.analyze_slots()
 def analyze_slots(self):
 self.__slots = {}
 for s in Slots:
 if s.special is not None:
 meth = self.__methods.get(s.special)
 if meth is not None:
 self.__slots[s] = meth
 self.__slots[TP_NAME] = '"%s.%s"' % (self.__module, self.__name__)
 if self.__doc__:
 self.__slots[TP_DOC] = "%s_doc" % self.name
 if self.__struct is not None:
 self.__slots[TP_BASICSIZE] = "sizeof(%s)" % self.__struct.name
 self.__slots[TP_DEALLOC] = "%s_dealloc" % self.name
 if self.__methods:
 self.__slots[TP_METHODS] = "%s_methods" % self.name
 if self.__members:
 self.__slots[TP_MEMBERS] = "%s_members" % self.name
 def initvars(self):
 v = self.__vars = {}
 v["TypeName"] = self.__name__
 v["CTypeName"] = "Py%s_Type" % self.__name__
 v["MethodDefName"] = self.__slots[TP_METHODS]
 if self.__doc__:
 v["DocstringVar"] = self.__slots[TP_DOC]
 v["Docstring"] = cstring(unindent(self.__doc__))
 if self.__struct is not None:
 v["StructName"] = self.__struct.name
 if self.__members:
 v["MemberDefName"] = self.__slots[TP_MEMBERS]
 def dump_memberdef(self, f):
 def p(templ, vars=self.__vars):
 print >> f, templ % vars
 if not self.__members:
 return
 p(template.memberdef_start)
 for name, slot in sortitems(self.__members):
 slot.dump(f)
 p(template.memberdef_end)
 def dump_slots(self, f):
 def p(templ, vars=self.__vars):
 print >> f, templ % vars
 if self.struct:
 p(template.dealloc_func, {"name" : self.__slots[TP_DEALLOC]})
 p(template.type_struct_start)
 for s in Slots[:-5]: # XXX
 val = self.__slots.get(s, s.default)
 ntabs = 4 - (4 + len(val)) / 8
 line = " %s,%s/* %s */" % (val, "\t" * ntabs, s.name)
 print >> f, line
 p(template.type_struct_end)
 def dump_init(self, f):
 def p(templ):
 print >> f, templ % self.__vars
 p(template.type_init_type)
 p(template.module_add_type)
class Type:
 __metaclass__ = TypeMetaclass
--- NEW FILE: function.py ---
"""Functions."""
from framer import template
from framer.util import cstring, unindent
METH_O = "METH_O"
METH_NOARGS = "METH_NOARGS"
METH_VARARGS = "METH_VARARGS"
def parsefmt(fmt):
 for c in fmt:
 if c == '|':
 continue
 yield c
class Argument:
 def __init__(self, name):
 self.name = name
 self.ctype = "PyObject *"
 self.default = None
 def __str__(self):
 return "%s%s" % (self.ctype, self.name)
 def setfmt(self, code):
 self.ctype = self._codes[code]
 if self.ctype[-1] != "*":
 self.ctype += " "
 _codes = {"O": "PyObject *",
 "i": "int",
 }
 def decl(self):
 if self.default is None:
 return str(self) + ";"
 else:
 return "%s = %s;" % (self, self.default)
class _ArgumentList(object):
 # these instance variables should be initialized by subclasses
 ml_meth = None
 fmt = None
 def __init__(self, args):
 self.args = map(Argument, args)
 def __len__(self):
 return len(self.args)
 def __getitem__(self, i):
 return self.args[i]
 def dump_decls(self, f):
 pass
 
class NoArgs(_ArgumentList):
 def __init__(self, args):
 assert len(args) == 0
 super(NoArgs, self).__init__(args)
 self.ml_meth = METH_NOARGS
 def c_args(self):
 return "PyObject *self"
class OneArg(_ArgumentList):
 
 def __init__(self, args):
 assert len(args) == 1
 super(OneArg, self).__init__(args)
 self.ml_meth = METH_O
 def c_args(self):
 return "PyObject *self, %s" % self.args[0]
class VarArgs(_ArgumentList):
 def __init__(self, args, fmt=None):
 super(VarArgs, self).__init__(args)
 self.ml_meth = METH_VARARGS
 if fmt is not None:
 self.fmt = fmt
 i = 0
 for code in parsefmt(fmt):
 self.args[i].setfmt(code)
 i += 1
 def c_args(self):
 return "PyObject *self, PyObject *args"
 def targets(self):
 return ", ".join(["&%s" % a.name for a in self.args])
 def dump_decls(self, f):
 for a in self.args:
 print >> f, " %s" % a.decl()
def ArgumentList(func, method):
 code = func.func_code
 args = code.co_varnames[:code.co_argcount]
 if method:
 args = args[1:]
 pyarg = getattr(func, "pyarg", None)
 if pyarg is not None:
 args = VarArgs(args, pyarg)
 if func.func_defaults:
 L = list(func.func_defaults)
 ndefault = len(L)
 i = len(args) - ndefault
 while L:
 args[i].default = L.pop(0)
 return args
 else:
 if len(args) == 0:
 return NoArgs(args)
 elif len(args) == 1:
 return OneArg(args)
 else:
 return VarArgs(args)
class Function:
 method = False
 def __init__(self, func, parent):
 self._func = func
 self._parent = parent
 self.analyze()
 self.initvars()
 def dump(self, f):
 def p(templ, vars=None): # helper function to generate output
 if vars is None:
 vars = self.vars
 print >> f, templ % vars
 if self.__doc__:
 p(template.docstring)
 
 d = {"name" : self.vars["CName"],
 "args" : self.args.c_args(),
 }
 p(template.funcdef_start, d)
 self.args.dump_decls(f)
 if self.args.ml_meth == METH_VARARGS:
 p(template.varargs)
 
 p(template.funcdef_end)
 def analyze(self):
 self.__doc__ = self._func.__doc__
 self.args = ArgumentList(self._func, self.method)
 
 def initvars(self):
 v = self.vars = {}
 v["PythonName"] = self._func.__name__
 s = v["CName"] = "%s_%s" % (self._parent.name, self._func.__name__)
 v["DocstringVar"] = s + "_doc"
 v["MethType"] = self.args.ml_meth
 if self.__doc__:
 v["Docstring"] = cstring(unindent(self.__doc__))
 if self.args.fmt is not None:
 v["ArgParse"] = self.args.fmt
 v["ArgTargets"] = self.args.targets()
class Method(Function):
 method = True
--- NEW FILE: member.py ---
from framer import template
from framer.util import cstring, unindent
T_SHORT = "T_SHORT"
T_INT = "T_INT"
T_LONG = "T_LONG"
T_FLOAT = "T_FLOAT"
T_DOUBLE = "T_DOUBLE"
T_STRING = "T_STRING"
T_OBJECT = "T_OBJECT"
T_CHAR = "T_CHAR"
T_BYTE = "T_BYTE"
T_UBYTE = "T_UBYTE"
T_UINT = "T_UINT"
T_ULONG = "T_ULONG"
T_STRING_INPLACE = "T_STRING_INPLACE"
T_OBJECT_EX = "T_OBJECT_EX"
RO = READONLY = "READONLY"
READ_RESTRICTED = "READ_RESTRICTED"
WRITE_RESTRICTED = "WRITE_RESTRICTED"
RESTRICT = "RESTRICTED"
c2t = {"int" : T_INT,
 "unsigned int" : T_UINT,
 "long" : T_LONG,
 "unsigned long" : T_LONG,
 "float" : T_FLOAT,
 "double" : T_DOUBLE,
 "char *" : T_CHAR,
 "PyObject *" : T_OBJECT,
 }
class member(object):
 def __init__(self, cname=None, type=None, flags=None, doc=None):
 self.type = type
 self.flags = flags
 self.cname = cname
 self.doc = doc
 self.name = None
 self.struct = None
 def register(self, name, struct):
 self.name = name
 self.struct = struct
 self.initvars()
 def initvars(self):
 v = self.vars = {}
 v["PythonName"] = self.name
 if self.cname is not None:
 v["CName"] = self.cname
 else:
 v["CName"] = self.name
 v["Flags"] = self.flags or "0"
 v["Type"] = self.get_type()
 if self.doc is not None:
 v["Docstring"] = cstring(unindent(self.doc))
 v["StructName"] = self.struct.name
 def get_type(self):
 """Deduce type code from struct specification if not defined"""
 if self.type is not None:
 return self.type
 ctype = self.struct.get_type(self.name)
 return c2t[ctype]
 def dump(self, f):
 if self.doc is None:
 print >> f, template.memberdef_def % self.vars
 else:
 print >> f, template.memberdef_def_doc % self.vars
--- NEW FILE: slots.py ---
"""Descriptions of all the slots in Python's type objects."""
class Slot(object):
 def __init__(self, name, cast=None, special=None, default="0"):
 self.name = name
 self.cast = cast
 self.special = special
 self.default = default
Slots = (Slot("ob_size"),
 Slot("tp_name"),
 Slot("tp_basicsize"),
 Slot("tp_itemsize"),
 Slot("tp_dealloc", "destructor"),
 Slot("tp_print", "printfunc"),
 Slot("tp_getattr", "getattrfunc"),
 Slot("tp_setattr", "setattrfunc"),
 Slot("tp_compare", "cmpfunc", "__cmp__"),
 Slot("tp_repr", "reprfunc", "__repr__"),
 Slot("tp_as_number"),
 Slot("tp_as_sequence"),
 Slot("tp_as_mapping"),
 Slot("tp_hash", "hashfunc", "__hash__"),
 Slot("tp_call", "ternaryfunc", "__call__"),
 Slot("tp_str", "reprfunc", "__str__"),
 Slot("tp_getattro", "getattrofunc", "__getattr__", # XXX
 "PyObject_GenericGetAttr"),
 Slot("tp_setattro", "setattrofunc", "__setattr__"),
 Slot("tp_as_buffer"),
 Slot("tp_flags", default="Py_TPFLAGS_DEFAULT"),
 Slot("tp_doc"),
 Slot("tp_traverse", "traverseprox"),
 Slot("tp_clear", "inquiry"),
 Slot("tp_richcompare", "richcmpfunc"),
 Slot("tp_weaklistoffset"),
 Slot("tp_iter", "getiterfunc", "__iter__"),
 Slot("tp_iternext", "iternextfunc", "__next__"), # XXX
 Slot("tp_methods"),
 Slot("tp_members"),
 Slot("tp_getset"),
 Slot("tp_base"),
 Slot("tp_dict"),
 Slot("tp_descr_get", "descrgetfunc"),
 Slot("tp_descr_set", "descrsetfunc"),
 Slot("tp_dictoffset"),
 Slot("tp_init", "initproc", "__init__"),
 Slot("tp_alloc", "allocfunc"),
 Slot("tp_new", "newfunc"),
 Slot("tp_free", "freefunc"),
 Slot("tp_is_gc", "inquiry"),
 Slot("tp_bases"),
 Slot("tp_mro"),
 Slot("tp_cache"),
 Slot("tp_subclasses"),
 Slot("tp_weaklist"),
 )
# give some slots symbolic names
TP_NAME = Slots[1]
TP_BASICSIZE = Slots[2]
TP_DEALLOC = Slots[4]
TP_DOC = Slots[20]
TP_METHODS = Slots[27]
TP_MEMBERS = Slots[28]
--- NEW FILE: struct.py ---
"""Rudimentary parser for C struct definitions."""
import re
PyObject_HEAD = "PyObject_HEAD"
PyObject_VAR_HEAD = "PyObject_VAR_HEAD"
rx_name = re.compile("} (\w+);")
class Struct:
 def __init__(self, name, head, members):
 self.name = name
 self.head = head
 self.members = members
 def get_type(self, name):
 for _name, type in self.members:
 if name == _name:
 return type
 raise ValueError, "no member named %s" % name
def parse(s):
 """Parse a C struct definition.
 The parser is very restricted in what it will accept.
 """
 lines = filter(None, s.split("\n")) # get non-empty lines
 assert lines[0].strip() == "typedef struct {"
 pyhead = lines[1].strip()
 assert (pyhead.startswith("PyObject") and
 pyhead.endswith("HEAD"))
 members = []
 for line in lines[2:]:
 line = line.strip()
 if line.startswith("}"):
 break
 
 assert line.endswith(";")
 line = line[:-1]
 words = line.split()
 name = words[-1]
 type = " ".join(words[:-1])
 if name[0] == "*":
 name = name[1:]
 type += " *"
 members.append((name, type))
 name = None
 mo = rx_name.search(line)
 assert mo is not None
 name = mo.group(1)
 return Struct(name, pyhead, members)
--- NEW FILE: structparse.py ---
"""Rudimentary parser for C struct definitions."""
import re
PyObject_HEAD = "PyObject_HEAD"
PyObject_VAR_HEAD = "PyObject_VAR_HEAD"
rx_name = re.compile("} (\w+);")
class Struct:
 def __init__(self, name, head, members):
 self.name = name
 self.head = head
 self.members = members
def parse(s):
 """Parse a C struct definition.
 The parser is very restricted in what it will accept.
 """
 lines = filter(None, s.split("\n")) # get non-empty lines
 assert lines[0].strip() == "typedef struct {"
 pyhead = lines[1].strip()
 assert (pyhead.startswith("PyObject") and
 pyhead.endswith("HEAD"))
 members = []
 for line in lines[2:]:
 line = line.strip()
 if line.startswith("}"):
 break
 
 assert line.endswith(";")
 line = line[:-1]
 words = line.split()
 name = words[-1]
 type = " ".join(words[:-1])
 if name[0] == "*":
 name = name[1:]
 type += " *"
 members.append((name, type))
 name = None
 mo = rx_name.search(line)
 assert mo is not None
 name = mo.group(1)
 return Struct(name, pyhead, members)
--- NEW FILE: template.py ---
"""framer's C code templates.
Templates use the following variables:
FileName: name of the file that contains the C source code
ModuleName: name of the module, as in "import ModuleName"
ModuleDocstring: C string containing the module doc string
"""
module_start = '#include "Python.h"'
member_include = '#include "structmember.h"'
module_doc = """\
PyDoc_STRVAR(%(ModuleName)s_doc,
%(ModuleDocstring)s);
"""
methoddef_start = """\
static struct PyMethodDef %(MethodDefName)s[] = {"""
methoddef_def = """\
	{"%(PythonName)s", (PyCFunction)%(CName)s, %(MethType)s},"""
 
methoddef_def_doc = """\
	{"%(PythonName)s", (PyCFunction)%(CName)s, %(MethType)s,
 %(DocstringVar)s},"""
 
methoddef_end = """\
	{NULL, NULL}
};
"""
memberdef_start = """\
#define OFF(X) offsetof(%(StructName)s, X)
static struct PyMemberDef %(MemberDefName)s[] = {"""
memberdef_def_doc = """\
 {"%(PythonName)s", %(Type)s, OFF(%(CName)s), %(Flags)s,
 %(Docstring)s},"""
memberdef_def = """\
 {"%(PythonName)s", %(Type)s, OFF(%(CName)s), %(Flags)s},"""
memberdef_end = """\
	{NULL}
};
#undef OFF
"""
dealloc_func = """static void
%(name)s(PyObject *ob)
{
}
"""
docstring = """\
PyDoc_STRVAR(%(DocstringVar)s,
%(Docstring)s);
"""
funcdef_start = """\
static PyObject *
%(name)s(%(args)s)
{"""
funcdef_end = """\
}
"""
varargs = """\
 if (!PyArg_ParseTuple(args, \"%(ArgParse)s:%(PythonName)s\",
 %(ArgTargets)s))
 return NULL;"""
module_init_start = """\
PyMODINIT_FUNC
init%(ModuleName)s(void)
{
 PyObject *mod;
 mod = Py_InitModule3("%(ModuleName)s", %(MethodDefName)s,
 %(ModuleName)s_doc);
 if (mod == NULL)
 return;
"""
type_init_type = " %(CTypeName)s.ob_type = &PyType_Type;"
module_add_type = """\
 if (!PyObject_SetAttrString(mod, "%(TypeName)s",
 (PyObject *)&%(CTypeName)s))
 return;
"""
type_struct_start = """\
static PyTypeObject %(CTypeName)s = {
 PyObject_HEAD_INIT(0)"""
 
type_struct_end = """\
};
"""
--- NEW FILE: util.py ---
def cstring(s, width=70):
 """Return C string representation of a Python string.
 width specifies the maximum width of any line of the C string.
 """
 L = []
 for l in s.split("\n"):
 if len(l) < width:
 L.append(r'"%s\n"' % l)
 return "\n".join(L)
def unindent(s, skipfirst=True):
 """Return an unindented version of a docstring.
 Removes indentation on lines following the first one, using the
 leading whitespace of the first indented line that is not blank
 to determine the indentation.
 """
 lines = s.split("\n")
 if skipfirst:
 first = lines.pop(0)
 L = [first]
 else:
 L = []
 indent = None
 for l in lines:
 ls = l.strip()
 if ls:
 indent = len(l) - len(ls)
 break
 L += [l[indent:] for l in lines]
 return "\n".join(L)

AltStyle によって変換されたページ (->オリジナル) /