File:  [CENS] / python / pyGiNaC / tools / check_dep.py
Revision 1.5: download - view: text, annotated - select for diffs - revision graph
Thu Mar 15 13:48:35 2001 UTC (16 years, 8 months ago) by pearu
Branches: MAIN
CVS tags: HEAD
Major revision, now more explicit wrapping

#!/usr/bin/env python

import re,sys

fn_cl = 'strip_ginac_class.txt'
fn_cln = 'strip_ginac_classnames.txt'
fn_cdcl = 'check_dep_class.txt'
ftodo = open('todo_cd.txt','w')
def todo(s):
    ftodo.write(s+'\n')
classes = {}

with_cln = 0

def getclass(name,verbose=0):
    global classes
    if classes.has_key(name): return classes[name]
    f = open(fn_cl,'r')
    cl_m = re.compile(r'class \b'+name+r'\b')
    fl = 0
    base = ''
    body = []
    for l in f.xreadlines():
        l = l.rstrip()
        if not l: continue
        if fl:
            if l[0].isalpha(): break
            l = l.strip()
            if '~' not in l:
                body.append(l.strip())
        else:
            if cl_m.match(l):
                fl = 1
                if verbose:
                    print 'Found:',`l`
                i = l.find(': public')
                if i>0:
                    base = l[i+9:].strip()
                    if verbose:
                        print ' base=',`base`
    classes[name] = base,body
    return base,body

def check_def(name,fun,verbose=0):
    if not name: return 0
    base,body = getclass(name)
    sfun = get_signature(fun).replace(' ','')
    vm = re.compile('virtual')
    for f in body:
        f = get_signature(f)
        f = f.replace(' ','')
        if vm.match(f):
            f = f[7:]
            if f==sfun:
                if verbose:
                    print 'Function %s is defined in %s'%(`fun`,`name`)
                return 1
    return check_def(base,fun,verbose)

def only_type(a):
    a = a.strip()
    if not a: return a
    if a in ['void']:
        return a
    i = a.find('&')
    if i != -1: # std::ostream & os
        return a[:i+1]
    i = a.find('*')
    if i != -1: # const char *s
        return a[:i+1]
    i = a.find('=')
    if i != -1: # unsigned upper_precedence = 0
        j = a[:i].rstrip().rfind(' ')
        if j != -1:
            return a[:j]
    j = a.rfind(' ')
    if j != -1 and a[j+1].isalpha(): # int i
        return a[:j]
    print >> sys.stderr,'Could not extract type for:',`a`
    return a
def get_signature(fun):
    m = re.match(r'(?P<before>.*?)[(](?P<args>.*?)[)](?P<after>.*)',fun)
    if m:
        before,args,rest = m.group('before'),m.group('args'),m.group('after')
        l = []
        for a in args.split(','):
            l.append(only_type(a))
        return before+'('+', '.join(l)+')'+rest
    else:
        print >> sys.stderr, 'Failed to get the signature:',fun
        return fun

ignore_class = """\
_numeric_digits # noneed

archive_node # ifthenboth
archive


fail # noneed
expand_options
series_options
determinant_algo
solve_algo
status_flags
info_flags
return_types
csrc_types
remember_strategies

in_ exprseq
ncmul
function_options # needskindawrapper
function # needskindawrapper


registered_class_info # noneed
registered_structure_info # noneed
structure # noneed
spmapkey_is_less # noneed

tensor # theseareoptinal
tensdelta
tensmetric
minkmetric
tensepsilon
scalar_products
idx
varidx

in_ indexed
in_ expair

expair_is_less

in_ expairseq
in_ mul
in_ add

in_ lst
matrix

in_ relational

pseries # needwrapper4epvectorargument
power

in_basic
in_ ex
in_constant # needscallbackwrapper
in_numeric
in_ symbol
""".split()
# minimal set is: basic, ex, expair, numeric, symbol

ignore_class = map(lambda s:s.strip(),ignore_class)

ok_types = [
    'int','unsigned int','long','unsigned long','double const','const std::string &',
    'bool','unsigned','double','const char *','const cln::cl_N &','void',
    'std::ostream &','std::string const &'
    ]

def fix_type(a):
    if a in ok_types:
        return a
    m = re.match(r'(?P<before>.*?)\b(?P<type>symbol|ex|numeric|expairseq|exprseq|basic|exvector|epvector|exlist|evalffunctype|matrix|lst|scalar_products|pseries|relational|expair)\b(?P<rest>.*)',a)
    if m:
        return m.group('before')+'GiNaC::'+m.group('type')+m.group('rest')
    m = re.match(r'(?P<before>.*?)\b(?P<type>(operators))\b(?P<rest>.*)',a)
    if m:
        return m.group('before')+'GiNaC::relational::'+m.group('type')+m.group('rest')
    m = re.match(r'(?P<before>.*?)\b(?P<type>(symmetry_type))\b(?P<rest>.*)',a)
    if m:
        return m.group('before')+'GiNaC::indexed::'+m.group('type')+m.group('rest')
    print 'Not fixed:',a
    return a

name_map = {'print':'print_'}

def get_wrappers(name,body,verbose=0):
    nm = re.compile(r'(?P<before>.*?)(?P<name>\b[\w]+\b)[(](?P<args>.*?)[)](?P<rest>.*)')
    dm = re.compile(r'(?P<type>.*)(?P<name>\b[\w]+\b);')
    ret = {'constructors':[],'auxfuncs':[],'methods':[]}
    if verbose:
        print 'Class:',`name`
    for b in body:
        m = nm.match(b)
        m2 = dm.match(b)
        if m and m.group('name').strip()==name: # only constructors
            args = [fix_type(only_type(a)) for a in m.group('args').split(',') if a]
            if name in ['exprseq','lst','function'] and len(args)>10:
                todo('In %s:%s'%(name,b))
                pass # this is due to boost limitation where nof args must be <=10
            elif name == 'numeric' and len(args)==1 and args[0] in ['int','unsigned int','long','unsigned long',{0:'const cln::cl_N &',1:''}[with_cln]]:
                todo('In %s:%s'%(name,b))
                pass # not impl.
            elif name == 'ex' and len(args)==1 and args[0] in ['int','unsigned int','unsigned long','double const']:
                todo('In %s:%s'%(name,b))
                # note that 3.7 == numeric(3.7) != ex(3.7) == 3
                pass # not needed, using long type instead
            elif name == 'constant' and len(args)==2 and args[1]=='GiNaC::evalffunctype':
                todo('In %s:%s'%(name,b))
                pass # not impl. need callback function
            elif name == 'lst' and len(args) and args[0] in ['In: GiNaC::exlist const &','GiNaC::exlist *']:
                todo('In %s:%s'%(name,b))
                pass # not impl. need wrapper for exlist
            elif name == 'exprseq' and len(args) and args[0] in ['In: GiNaC::exvector const &','GiNaC::exvector *']:
                todo('In %s:%s'%(name,b))
                pass # not impl. need wrapper for exvector
            elif name == 'expairseq' and len(args) and args[0] in ['const GiNaC::exvector &','const GiNaC::epvector &','GiNaC::epvector *']:
                todo('In %s:%s'%(name,b))
                pass # not impl. need wrapper for exvector, epvector
            elif name == 'matrix' and len(args)==3:
                todo('In %s:%s'%(name,b))
                pass # not impl. need wrapper for exvector
            elif name == 'indexed' and len(args)>1 and (args[1] in ['const GiNaC::exvector &','const GiNaC::exvector &','GiNaC::exvector *','GiNaC::indexed::symmetry_type'] or (len(args)>2 and args[2] == 'const GiNaC::exvector &') or args[0]=='GiNaC::indexed::symmetry_type'):
                todo('In %s:%s'%(name,b))
                pass # not impl. need wrapper for exvector, indexed::symmetry_type
            elif name in ['mul','add'] and len(args) and args[0] in ['IN: const GiNaC::exvector &','const GiNaC::epvector &','GiNaC::epvector *']:
                todo('In %s:%s'%(name,b))
                pass # not impl. need wrapper for exvector,epvector
            elif name == 'ncmul' and len(args) and args[0] in ['GiNaC::exvector *','const GiNaC::exvector &']:
                todo('In %s:%s'%(name,b))
                pass # not impl. need wrapper for exvector
            elif name == 'function' and len(args)>1 and (args[1] in ['const GiNaC::exvector &','GiNaC::exvector *'] or len(args)>3):
                todo('In %s:%s'%(name,b))
                pass # not impl. need wrapper for exvector
            else:
                ret['constructors'].append('\t%s_class.def(python::constructor<%s>());'%(name,', '.join(args)))
                if verbose: print '\t'+b
        elif m and m.group('name')[:5]=='print': # print* methods
            fun = m.group('name')
            args = [fix_type(only_type(a)) for a in m.group('args').split(',') if a]
            #print name,m.group('name'),args
            args[0] = 'GiNaC::%s const & f'%name
            cargs = ['o']
            for i in range(1,len(args)):
                args[i] += ' a'+`i`
                cargs.append('a'+`i`)
            r = '\tstd::string %s_%s_wrap (%s) { std::ostrstream o; f.%s(%s); o << ends; return o.str(); }'%(name,fun,', '.join(args),fun,', '.join(cargs))
            ret['auxfuncs'].append(r)
            try: n = name_map[fun]
            except KeyError: n = fun
            ret['methods'].append('\t%s_class.def(&%s_%s_wrap, "%s");'%(name,name,fun,n))
            if verbose: print '\t'+b
        elif m and name=='expair': # expair methods
            fun = m.group('name')
            #args = [fix_type(only_type(a)) for a in m.group('args').split(',') if a]
            try: n = name_map[fun]
            except KeyError: n = fun
            ret['methods'].append('\t%s_class.def(&GiNaC::%s::%s, "%s");'%(name,name,fun,n))
            if verbose: print '\t'+b
        elif m2 and name=='expair': # expair attributes
            t = fix_type(m2.group('type'))
            n = m2.group('name').strip()
            #r = '\t%s %s(const GiNaC::%s & x) { return x.%s; }'%(t,n,name,n)
            #ret['auxfuncs'].append(r)
            ret['methods'].append('\t%s_class.def_read_write(&GiNaC::%s::%s, "%s");'%(name,name,n,n))
            if verbose: print '\t'+b
        elif m and name=='ex' and m.group('name') in \
             ['swap','info','nops','expand','has','degree','ldegree',
              'coeff','lcoeff','tcoeff','numer','denom','unit',
              'content','integer_content','normal','to_rational',
              'smod','max_coefficient','collect','eval','evalf','diff','series',
              'get_free_indices','simplify_ncmul',
              'op','let_op','lhs','rhs','compare','is_equal','is_zero',
              'return_type','return_type_tinfo','gethash','exadd','exmul',
              'exncmul']:
            fun = m.group('name')
            try: n = name_map[fun]
            except KeyError: n = fun
            ret['methods'].append('\t%s_class.def(&GiNaC::%s::%s, "%s");'%(name,name,fun,n))
            if verbose: print '\t'+b
        elif 0 and m and name=='basic' and m.group('name') in ['info','nops','op','let_op',
                                                         'has','degree','ldegree','coeff','collect','eval','evalf','series','integer_content','smod','max_coefficient','get_free_indices','simplify_ncmul','eval_indexed','contract_with','diff','compare','is_equal','hold','gethash','tinfo','setflag','clearflag','normal','to_rational']: # basic methods
            fun = m.group('name')
            try: n = name_map[fun]
            except KeyError: n = fun
            ret['methods'].append('\t%s_class.def(&GiNaC::%s::%s, "%s");'%(name,name,fun,n))
            if verbose: print '\t'+b
        elif m and name=='relational' and m.group('name') != 'bool':
            fun = m.group('name')
            #args = [fix_type(only_type(a)) for a in m.group('args').split(',') if a]
            try: n = name_map[fun]
            except KeyError: n = fun
            ret['methods'].append('\t%s_class.def(&GiNaC::%s::%s, "%s");'%(name,name,fun,n))
            if verbose: print '\t'+b
        elif m and name=='symbol':
            fun = m.group('name')
            try: n = name_map[fun]
            except KeyError: n = fun
            ret['methods'].append('\t%s_class.def(&GiNaC::%s::%s, "%s");'%(name,name,fun,n))
            if verbose: print '\t'+b
        else:
            todo('In %s:%s'%(name,b))
            #print 'No match:',`b`,`name`
            pass

    if verbose: print '\t%s.__str__()'%(name) # __str__ method
    if name == 'expair':
        ret['auxfuncs'].append('\tstd::string %s_to_string(GiNaC::%s const& f) { std::ostrstream s; f.printraw(s); s << ends; return s.str(); }'%(name,name))
        ret['methods'].append('\t%s_class.def(&%s_to_string, "__str__");'%(name,name))
    elif name in ['ex','basic']: 
        ret['auxfuncs'].append('\tstd::string %s_to_string(GiNaC::%s const& f) { std::ostrstream s; f.print(s, 0); s << ends; return s.str(); }'%(name,name))
        ret['methods'].append('\t%s_class.def(&%s_to_string, "__str__");'%(name,name))
    else:
        ret['methods'].append('\t%s_class.def(&basic_to_string, "__str__");'%(name))
    return ret
def class_def(name):
    return '\tpython::class_builder<GiNaC::%s> %s_class(this_module, "%s");'%(name,name,name)

def class_base(name,base):
    return '\t%s_class.declare_base(%s_class);'%(name,base)

faux = open('../src/class_wrapper._cpp','w')
fmth = open('../src/class_method._cpp','w')

f = open(fn_cln,'r')
fo = open(fn_cdcl,'w')
constructors = {}
classes_def = {}
first_round = []
second_round = []
second_round_dep = []

for l in f.xreadlines():
    name = l.split()[1]
    if name in ignore_class:
        todo('Ignored class: %s'%(name))
        #print 'Skipping class:',name
        continue
    base,body = getclass(name)
    if not base:
        first_round.append(name)
    else:
        second_round.append(name)
        second_round_dep.append(base)
    fo.write(l)
    nbody = []
    enums = {'defs':[],'adds':[],'wraps':[]}
    for b in body:
        if re.match(r'\s*enum\b',b) or re.match(r'\s*typedef\b',b):
            fo.write('\t'+b+'\n')
            m = re.match(r'\s*enum\b\s*\b(?P<type>\w+)\b\s*{(?P<parts>.*?)}',b)
            if m and name=='relational':
                t = m.group('type')
                parts = [p.strip() for p in m.group('parts').split(',')]
                enums['wraps'].append('\ttemplate class python::enum_as_int_converters<GiNaC::%s::%s>;'%(name,t))
                enums['adds'].append('\t// %s::%s'%(name,t))
                for p in parts:
                    enums['adds'].append('\t%s_class.add(PyInt_FromLong(GiNaC::%s::%s), "%s");'%(name,name,p,p))
                continue
            todo('In %s:enum: %s'%(name,b))
        elif not check_def(base,b):
            fo.write('\t'+b+'\n')
            nbody.append(b)
    classes_def[name] = class_def(name)
    ret = get_wrappers(name,nbody,1)
    constructors[name]=ret['constructors']
    fmth.write('\t// %s methods\n'%(name))
    fmth.write('\n'.join(ret['methods'])+'\n')
    fmth.write('\n'.join(enums['defs'])+'\n')
    fmth.write('\n'.join(enums['adds'])+'\n')
    
    faux.write('\t// %s method wrappers\n'%(name))
    faux.write('\n'.join(enums['wraps'])+'\n')
    faux.write('\n'.join(ret['auxfuncs'])+'\n')

    
fo.close()
f.close()
faux.close()
fmth.close()
flag = 1
while flag: # sort class dependencies
    flag = 0
    for i in range(len(second_round)):
        if second_round[i] in first_round:
            continue
        if second_round_dep[i] in first_round:
            first_round.append(second_round[i])
            flag = 1

f = open('../src/class._cpp','w')
f2 = open('../src/class_constructor._cpp','w')
if with_cln:
    f.write('''\
\tpython::class_builder<cln::cl_N> cl_N_class(this_module, "cl_N");
\tcl_N_class.def(python::constructor<>());
''')
    
for c in first_round:
    f.write('\t// Class %s\n'%c)
    f.write(classes_def[c]+'\n')
for c in first_round:
    if c in second_round:
        f.write('\t// %s is derived...\n'%c)
        f.write(class_base(c,second_round_dep[second_round.index(c)])+'\n')
for c in first_round:
    f2.write('\t// %s constructors\n'%c)
    f2.write('\n'.join(constructors[c])+'\n')

f.close()
f2.close()
print 'Classes:',', '.join(first_round)

ftodo.close()

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>