import sys, os, imp

try:
  import template
except ImportError:
  # Make sure autoclutter can be found even though it isn't installed yet.
  file, path, descr = imp.find_module("template")
  template = imp.load_module("template", file, path, descr)
  
def hasUInt64():
  return "--hasUInt64" in sys.argv

def hasFloat128():
  return "--hasFloat128" in sys.argv

all_types = ["Bool", "Int8", "UInt8", "Int16", "UInt16", "Int32", "UInt32",
         "Float32", "Float64", "Complex32","Complex64"]
  
all_types.append("Int64")
if hasUInt64():
  all_types.append("UInt64")

"""This program generates multiple c source code files
It handles the tedium of all the repetitive code dealing with
types and particularly combinations of types with types and
types with functions.
$Id: basecode.py,v 1.5 2005/02/18 15:58:35 jaytmiller Exp $
"""

#*********************************************************************#
#                                                                     #
#                            DATA SECTION                             #
#                                                                     #
#*********************************************************************#
# Of course, the warning below does not apply to this file!

_HEADER = \
'''
/*   W     W   AAA   RRRR   N   N  III  N   N   GGG   !!!
**   W     W  A   A  R   R  NN  N   I   NN  N  G   G  !!!
**   W  W  W  AAAAA  RRRR   N N N   I   N N N  G       !
**    W W W   A   A  R   R  N  NN   I   N  NN  G  GG
**     W W    A   A  R   R  N   N  III  N   N   GGG   !!!
**
** WARNING: This file is program generated by codegenerator.py.
**
** DO NOT EDIT THIS FILE! Any changes made to this file will be lost!
*/

#include <Python.h>
#include <stdio.h>
#include "libnumarray.h"
'''

_TYPE_SEPARATOR = \
'''
/****************** <typename> *******************/
'''

_METHODS_DEF = \
'''
static PyMethodDef <module>Methods[] = {
<module_methods>
\t{NULL,      NULL}        /* Sentinel */
};
'''

_ADDMETHOD_TEMPLATE = \
'''\t{ "%s", %s, METH_VARARGS},
'''

_TAIL = \
'''
/* platform independent*/
#ifdef MS_WIN32
__declspec(dllexport)
#endif
void init<module>(void) {
    PyObject *m, *d;
    m = Py_InitModule("<module>", <module>Methods);
    d = PyModule_GetDict(m);
    import_libnumarray();
    PyDict_SetItemString(d, "functionDict", init_funcDict());
    ADD_VERSION(m);
}
'''

#*********************************************************************#
#                   data for filling function table                   #
#*********************************************************************#
_CFUNCDICT_HEADER = \
'''
static PyObject *init_funcDict(void) {
    PyObject *dict;
    dict = PyDict_New();
'''

_ADDCFUNC_TEMPLATE = \
'''    NA_add_cfunc(dict, "%s", (void *) &%s_descr);
'''

_CFUNCDICT_TAIL = \
'''    return dict;
}
'''

# ============================================================================
#          IMPORTANT:  no <>-sugared strings below this point

# translate <var> --> %(var)s in templates seen *so far*
template.sugar_dict(globals())  

# ============================================================================
    
#*********************************************************************#
#                                                                     #
#                           PROGRAM SECTION                           #
#                                                                     #
#*********************************************************************#

"""
The classes below assemble the various elements defined in
the previous part of the module into the final C modules.

Each subclass of CodeGenerator works basically the same way:

It is constructed by supplying optional module unique header, tail,
and function separator.

When called, a CodeGenerator builds up two lists of strings by calling
its "bodygenerator()" method.  Looping over a parameter table,
the bodygenerator builds:

1. A code list containing the instantiated header and emitted function bodies.
This is the bulk of the code.

2. A function list containing the C struct initializers which are used to
register the function bodies with python.  These are necessarily in a
seperate textual segment so that they may be joined in an array and looped
over at initialization time.

In general, templates are instantiated by formatting them either using a
CodeGenerator instance dict, or a Params instance dict.

After generating its two lists, a CodeGenerator combines them into
the complete C code for a python module and writes the code out to
the specified file.

CodeGenerator subclasses customize behavior by overriding the "bodygenerator"
and "addcfunc" methods.  Each "bodygenerator" tends to be tailored to the
parameter table used to specify the cfuncs for the module.

Several of the codegenerators (cconv, ufunc, bytes) are supported by a
"Params" class, instances of which act as table records.  As the body
generator loops over the parameter table, it creates a Params instance
from each record.  The Params instance dictionary then provides a
source of keyword values to instantiate the code template.  See
ConvParams, ByteParams, and UfuncParams.  Each is essentially a
struct.

In general, template instantiation is performed by string substitution
using the python %(identifier)s syntax.  The %(indentifer)s syntax
permits a string to be formatted using a dictionary to supply identifier
values.
"""

class CodeGenerator:
    """Generates source code using supplied functions and code templates"""

    _cfuncdict_header=_CFUNCDICT_HEADER
    _cfuncdict_tail=_CFUNCDICT_TAIL
    _addcfunc_template=_ADDCFUNC_TEMPLATE

    _methods_def=_METHODS_DEF
    _addmethod_template=_ADDMETHOD_TEMPLATE

    def __init__(self, header=_HEADER, tail=_TAIL, config=None,
                 separator=_TYPE_SEPARATOR):
        self.header = header
        self.tail = tail
        self.separator = separator
        self.config = config
        self.module_methods = ""

    def gen_header(self):
        self.codelist = [ self.header % self.__dict__]
        self.funclist = [ self._cfuncdict_header ]

    def gen_trailer(self):
        self.funclist.append(self._cfuncdict_tail)
        self.codelist.append(self._methods_def % self.__dict__)
        self.codelist.extend(self.funclist)
        self.codelist.append(self.tail % self.__dict__)

    def emit_code(self, file):
        sourcecode = "".join(self.codelist)
        if file:
            f = open(file,"w")
            f.write(sourcecode)
            f.close()
        else:
            return sourcecode
      
    def __call__(self, file=None, Type=None):
        self.gen_header()
        if Type is None:
            self.gen_body()
        else:
          self.gen_body(Type)
        self.gen_trailer()
        return self.emit_code(file)
            
    def addcfunc(self, name, key=None):
        if key is None:
            key = name
        self.funclist.append(self._addcfunc_template % (key, name))

    def addmethod(self, name, key=None):
        if key is None:
            key = name
        self.module_methods += (self._addmethod_template % (key, name))

