generator.py :  » Development » PyFort » Pyfort-8.5.3 » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Development » PyFort 
PyFort » Pyfort 8.5.3 » generator.py
# Copyright, 1999, Regents of the University of California
# Please see file Legal.htm
import string
import sys, re, os
from semantics import *
sizere = re.compile(r'(size[ \t]*\([ \t]*)([a-zA-Z_][a-zA-Z_0-9]*)', re.IGNORECASE)
class PyFortError (Exception):
    def __init__ (self, *args):
        self.args=args
    def __str__ (self):
        return str(self.args)

class Generator:
    def __init__(self, module_name, routine_list, common_list):
        self.module_name = module_name
        self.routine_list = routine_list
        self.common_list = common_list
        if common_list:
            raise PyFortError, "Data blocks not supported."

class Document_Generator (Generator):
    def __init__(self, module_name, outdir, routine_list, common_list):
        Generator.__init__ (self, module_name, routine_list, common_list)
        self.filename = os.path.join(outdir, module_name + ".txt")

    def generate(self):
        dout = open(self.filename, "w")
        dout.write("Procedures in module " + self.module_name + '\n')
        for proc in self.routine_list:
            dout.write("\n----------- " + proc.routine_name() + " ------------\n")
            s = proc.head_comments()
            if s:
                dout.write(s)
            dout.write('\nCalling sequence: \n   ' + self.generate_routine_interface (proc)+ '\n')
            dout.write('Fortran declarations for these variables are:\n')
            for x in proc.declarations():
                dout.write('          ')
                y = x.intent
                if y == 'valued': x.set_intent('in')
                dout.write(repr(x))
                x.set_intent(y)
                dout.write('\n')

    def generate_routine_interface (self, proc):
        "Generate the calling sequence for proc in Python"
        t = proc.python_outputs()
        if t:
            if t[0] == proc.routine_name():
                t[0] = 'function_result'
            s = string.join(t, ', ') + ' = '
        else:
            s = ''
        s = s + proc.routine_name()
        s = s + '('
        s = s + string.join(proc.python_inputs(), ', ')
        s = s + ')'
        return s

_nlre = re.compile(r'$', re.MULTILINE)
_begre = re.compile(r'^', re.MULTILINE)

def fixup (acomment):
    "Fix the comment so it can be a C string literal."
    out = string.replace(acomment, '"', r'\"')
    out = _nlre.sub(r'\\n"', out)
    out = _begre.sub(r'"', out)
    return out

class C_Module_Generator (Generator):
    def __init__(self, 
            compiler,
            module_name, 
            outdir, 
            routine_list, 
            common_list, 
        ):
        Generator.__init__ (self, module_name, routine_list, common_list)
        self.compiler = compiler
        self.filename = os.path.join(outdir, module_name +  "module.c")

    def generate(self):
        "Generate the C module wrapper."
        self.module_file = open (self.filename, 'w')
        try:
            self.write_header ()
            self.write_array_argument_handler ()
            self.write_methods()
            self.write_method_table ()
            self.write_init_function ()
            self.write_trailer()
            self.module_file.close()
        except PyFortError, msg:
            print msg
            self.module_file.close()
            self.module_file.unlink()
            raise SystemExit, 1

##################################################
# writing the module header
##################################################
    def write_header (self):
        """Write the beginning of the module file."""
        text = \
"""\
#ifdef __CPLUSPLUS__
extern "C" {
#endif
#include "Python.h"
#include "Numeric/arrayobject.h"
 
static PyObject *ErrorObject;

static int array_really_contiguous(PyArrayObject *ap) {
      int sd;
      int i;

      sd = ap->descr->elsize;
      for (i = ap->nd-1; i >= 0; --i) {
              if (ap->dimensions[i] == 0) return 1; /* contiguous by definition */
              if (ap->strides[i] != sd) return 0;
              sd *= ap->dimensions[i];
      }
      return 1;
}

struct fcomplex {
    float r;
    float i;
    };
typedef struct fcomplex Py_complex_float;
"""
        self.put(text)
        text = \
"""\
#define TRANSPOSE_OPTION %(transpose_option)d
#define MIRROR_OPTION %(mirror_option)d
#define get_fortran_dim(v,n) v->dimensions[(keyoption & MIRROR_OPTION) ? v->nd - (n) : (n)-1]"""
        D = {'transpose_option': self.compiler.transpose_option(),
             'mirror_option': self.compiler.mirror_option()}
        self.put(text, D)

        self.put(self.compiler.header())

##### Write the array argument acquisition #####
    def write_array_argument_handler (self):
        text = \
"""
static int default_option = TRANSPOSE_OPTION;
static PyObject*
set_pyfort_option (PyObject* unused, PyObject* args) {
    if(!PyArg_ParseTuple(args, "i", &default_option)) return NULL;
    Py_INCREF(Py_None);
    return Py_None;
}

static void
set_pyfort_error (char* routine, char* var, char* problem) {
    char buf[512];
    sprintf(buf, "%%s, argument %%s: %%s", routine, var, problem);
    PyErr_SetString (ErrorObject, buf);
}

static void set_transposed_strides (PyArrayObject* ar)
{
    int m1, n1, itmp; 
    n1 = ar->nd; 
    if (n1 < 2) return;
    m1 = ar->strides[n1-1];   /* stride for one element */ 
    for(itmp=0; itmp < n1 ; itmp++) { 
        ar->strides[itmp] = m1; 
        m1 *= ar->dimensions[itmp]; 
    } 
    ar->flags &= ~CONTIGUOUS; 
}


static PyArrayObject*
transpose_array (char* rname, char* vname, PyArrayObject* ap) {
/* return transpose of ap, possibly not contiguous so as to avoid copy if we
   are transposing a previously transposed contiguous array
   This means with the transpose option on the output of one call might
   not need any copying if used as input to another call. I.e., Fortran 
   arrays stay in row-major order.
*/
    int i, n;
    PyArrayObject *ret;
    n  = ap->nd;

    /* this allocates memory for dimensions and strides (but fills them
           incorrectly), sets up descr, and points data at ap->data. */
    ret = (PyArrayObject *)PyArray_FromDimsAndData(n, ap->dimensions,
                                                    ap->descr->type_num,
                                                    ap->data);
    if (!ret) {
        set_pyfort_error (rname, vname, "Could not create descriptors for transpose.");
        return NULL;
    }
       
    /* point at true owner of memory: */
    ret->base = (PyObject *)ap;
    Py_INCREF(ap);
    for(i=0; i<n; i++) {
        ret->dimensions[i] = ap->dimensions[n - i - 1];
        ret->strides[i] = ap->strides[n - i - 1];
    }
    if (array_really_contiguous(ret)) {
        ret->flags |= CONTIGUOUS;
    } else {
        ret->flags &= ~CONTIGUOUS;
    }
    return ret;
}

static PyArrayObject* make_contiguous(char* rname, char* vname, PyArrayObject* ap)
{
/* return an owned ref to a contiguous version of ap */
    PyArrayObject* result;
    if (ap->flags & CONTIGUOUS) {
        Py_INCREF (ap);
        return ap;
    } else {
        result = (PyArrayObject *) PyArray_ContiguousFromObject(
      (PyObject*) ap, ap->descr->type_num, 0, 0);
        if(!result) set_pyfort_error(rname, vname, "Failed making object contiguous.");
        return result;
    }
}

static int do_size_check (char* rname, char* vname, PyArrayObject *av, int rank,  int extents[], int mirror)
{
    int size1;
    int i, j;
    char buf[512];

    size1 = av->nd;
    
    if( size1 == rank) {
        for(i=0; i < rank; ++i) {
            /* no checking on last dimension of expected size 1 */
            if (i == size1-1) {
               if (extents[i] == 1) break;
            }
            j = mirror ? size1 - 1 - i : i;
            if(av->dimensions[j] != extents[i]) 
            {
               sprintf(buf, "Incorrect extent in dimension %%d (%%d expected %%d)",
                       i+1, av->dimensions[j], extents[i]);
               set_pyfort_error(rname, vname, buf);
               return 0;
            }
        } 
    } else {
        if (rank != 1 || 
            size1 > 0 ||
            extents[0] != 1) 
        {    
           sprintf(buf, "Incorrect rank (%%d expected %%d)",
                       size1, rank);
           set_pyfort_error(rname, vname, buf);
           return 0;
        }
    }
    return 1; /* size ok */
}

static PyArrayObject*
do_array_in (char* rname, char* vname, PyObject *v, 
    enum PyArray_TYPES python_array_type)
{
    PyArrayObject* av;
    PyArrayObject* t;

    if(!PyArray_Check (v)) {
        t = (PyArrayObject *) PyArray_ContiguousFromObject(v, PyArray_NOTYPE, 0, 0);
        if (!t) {
            set_pyfort_error(rname, vname, "Argument cannot be converted to needed array.");
            goto err;
        }
    } else {
        t = (PyArrayObject*) v;
        Py_INCREF((PyObject*) t);
    }
    if (t->descr->type_num != python_array_type) {
        av = (PyArrayObject*) PyArray_Cast (t, python_array_type);
        Py_DECREF((PyObject*) t);
        t = av;
        if (!t) {
            set_pyfort_error(rname, vname, "Argument cannot be cast to needed type.");
            goto err;
        }
    } 
    return t;

err:
   return (PyArrayObject*) 0;
}

static PyArrayObject*
do_array_inout (char* rname, char* vname, PyObject *v, 
    enum PyArray_TYPES python_array_type)
{
    PyArrayObject* av;

   if (!PyArray_Check (v)) {
        set_pyfort_error(rname, vname, "Argument intent(inout) must be an array.");
        goto err;
   }
   av = (PyArrayObject*) v;
   if (av->descr->type_num != python_array_type) {
        set_pyfort_error(rname, vname, "Argument intent(inout) must be of correct type.");
        goto err;
   }
   if (!(av->flags & CONTIGUOUS))  {
       set_pyfort_error(rname, vname, "Argument intent(inout) must be contiguous.");
       goto err;
   }
   Py_INCREF(av);
   return av;
err:
   return (PyArrayObject*) 0;
}

static PyArrayObject*
do_array_create (char* rname, char* vname, enum PyArray_TYPES python_array_type, 
    int rank, int extents[], int mirror)
{
    PyArrayObject* av;
    int i, dims[7];
    if (rank > 7) {
        set_pyfort_error(rname, vname, "Too many dimensions -- limit is 7.");
        goto err;
    }
    if(mirror) {
        for(i=0; i < rank; ++i) dims[i] = extents[rank-1-i];
    } else {
        for(i=0; i < rank; ++i) dims[i] = extents[i];
    }
    av = (PyArrayObject*) PyArray_FromDims(rank, dims, python_array_type);
    if (!av) {
        set_pyfort_error(rname, vname, "Could not create array -- too big?");
        goto err;
    }
    return av;
err:
    return (PyArrayObject*) 0;
}
"""
        self.put(text);
        

##################################################
# writing the trailer
##################################################
    def write_trailer(self):
        text = \
"""
/* C++ trailer */
#ifdef __CPLUSCPLUS__
}
#endif
"""
        self.put(text);
##################################################
# writing the method table
##################################################
    def write_method_table (self):
        "Write the method table."

        D = {'module_name': self.module_name}

        # Declare the method table
        text = \
"""
static struct PyMethodDef %(module_name)s_methods[] = {
"""
        self.put(text, D)

        # Put the wrapper functions of routines in the method table
        text = \
"""\
   {"%(routine_name)s", (PyCFunction) %(module_name)s_%(routine_name)s, METH_VARARGS, %(module_name)s_%(routine_name)s__doc__},
"""
        for routine in self.routine_list:
            D['routine_name'] = routine.routine_name()
            self.module_file.write(text % D)
        text = \
"""\
   {"set_pyfort_option", (PyCFunction) set_pyfort_option, METH_VARARGS, 
           "set_pyfort_option (value) sets default value of option keyword."},
   {NULL,          NULL, 0, NULL}/* sentinel */
};
"""
        self.put(text)


##################################################
# writing the initialization function for Python
##################################################
    def write_init_function (self):

        D = {'module_name': self.module_name}
        text = \
"""
static char %(module_name)s_module_documentation[] =
"Fortran interface module %(module_name)s";

void init%(module_name)s(void)
{
        PyObject *m, *d, *j;
 
        import_array ();
        m = Py_InitModule4("%(module_name)s", %(module_name)s_methods,
                %(module_name)s_module_documentation,
                (PyObject*)NULL,PYTHON_API_VERSION);
 
        d = PyModule_GetDict(m);
        ErrorObject = PyString_FromString("%(module_name)s.error");
        PyDict_SetItemString(d, "error", ErrorObject);
        j = PyInt_FromLong((long) TRANSPOSE_OPTION);
        PyDict_SetItemString(d, "TRANSPOSE", j);
        Py_XDECREF(j);
        j = PyInt_FromLong((long) MIRROR_OPTION);
        PyDict_SetItemString(d, "MIRROR", j);
        Py_XDECREF(j);
        j = PyInt_FromLong(0L);
        PyDict_SetItemString(d, "NONE", j);
        Py_XDECREF(j);

        if (PyErr_Occurred()) {
            Py_FatalError("can't initialize module %(module_name)s");
        }
}
"""
        self.put(text, D)
        
##################################################
# writing the method wrappers
##################################################
    def write_methods (self):
        self.put("/* Methods */\n")
        for routine in self.routine_list:
            self.write_a_routine_wrapper (routine)

##################################################
# writing the wrapper for one routine
##################################################
    def write_a_routine_wrapper (self, routine):
        "Write out one routine's wrapper."
        self.array_result_flag = 0
        self.compiler.modify_routine (routine)
        self.write_docstring (routine)
        self.write_prototype(routine)
        self.write_method_header(routine)
        self.write_general_locals(routine)
        self.write_fortran_argument_locals(routine)
        self.write_initialization(routine)
        self.write_argument_parsing(routine)
        self.write_preprocessing(routine)
        self.write_fortran_call(routine)
        self.write_postprocessing(routine)
        self.write_fortran_argument_cleanup(routine, 0)
        self.write_return_value_construction(routine)
        self.write_fortran_argument_cleanup(routine, 1)
        self.write_method_finish(routine)

    def write_docstring (self, routine):
        "Write out one routine's doc string."
        h = routine.head_comments()
        if h:
            c = fixup(h)
        else:
            c = '"' + routine.routine_name() + '(' + \
                   string.join(routine.python_inputs(), ', ') + ')' + '"'
        D = {'module_name': self.module_name,
             'routine_name': routine.routine_name(),
             'comment': c \
            }
        text = \
"""
/* %(routine_name)s */
static char %(module_name)s_%(routine_name)s__doc__[] =
%(comment)s;
"""
        self.put(text, D)

    def set_variable (self, name, routine, D):
        "Set things in D"
        if name == routine.routine_name():
            n = 'fortran_result'
        else:
            n = string.upper(name)
        d = routine.declaration(name)
        c = self.compiler.c_type(d)
        D['routine_name'] = routine.routine_name()
        D['c_type'] = c
        D['variable_name'] = string.upper(name)
        if d.rank():
            D['d_type'] = 'PyObject*'
        else:
            D['d_type'] = c

    def write_prototype(self, routine):
        """Write the prototype for the Fortran call"""
        self.put(self.compiler.prototype(routine))

    def write_method_header(self, routine):
        D = {'module_name': self.module_name,
             'routine_name': routine.routine_name() \
            }
        text = \
"""
static PyObject*
%(module_name)s_%(routine_name)s (PyObject* unused, PyObject* args) {
"""
        self.put(text, D)

    def write_general_locals(self, routine):
        text = \
"""
    PyObject *pyfort_result;
    int keyoption;
"""
        self.put (text)
        if routine.is_function():
            text = \
"""\
    %(result_type)s fortran_result;
"""
            D = {'result_type': self.compiler.c_type(routine.declaration(routine.routine_name())) }
            self.put (text, D)
            if D['result_type'] == 'Py_complex' or D['result_type'] == 'Py_complex_float':
                text = \
"""\
    PyArrayObject* fortran_result_array;
    PyObject* rfortran_result_array;
    int fortran_result_array_length;
"""
                self.put(text)
                self.array_result_flag = 1

    def write_fortran_argument_locals(self, routine):
        text = \
"""\
    %(d_type)s %(prefix)s%(variable_name)s;
"""
        texte = \
"""\
    int e%(variable_name)s[%(rank)d];
"""
        formal_argument_list = routine.arguments()
        D={}
        apv = 0 # have we declared pyarray_value yet?
        for a in formal_argument_list:
            self.set_variable(a, routine, D)
            d = routine.declaration(a)
            if d.intent == 'in':
                if d.rank():
                    if not apv: 
                        self.put("    PyArrayObject* pyarray_value;\n")
                        apv = 1
                        
                    D['prefix'] = ''
                    self.put(text, D)
                    
                    D['prefix'] = 'a'
                    D['d_type'] = 'PyArrayObject*'
                    self.put(text, D)
                    
                    D['rank'] = d.rank()
                    self.put(texte, D)
                    if D['c_type'] == 'char*':
                        raise PyFortError, \
                              "Character arrays not supported."
                else:
                    D['prefix'] = ''
                    self.put(text, D)
                    
                    if D['c_type'] == 'char*':
                        D['prefix'] = 'n'
                        D['d_type'] = 'int'
                        self.put(text, D)
                    
            if d.intent == 'valued':
                if d.rank():
                    raise PyFortError, "Initial value cannot be specified for array."
                else:
                    D['prefix'] = ''
                    self.put(text, D)
                    
                    if D['c_type'] == 'char*':
                        D['prefix'] = 'n'
                        D['d_type'] = 'int'
                        self.put(text, D)
                    
            elif d.intent == 'inout':
                if d.rank():
                    D['prefix'] = ''
                    self.put(text, D)
                    
                    D['prefix'] = 'a'
                    D['d_type'] = 'PyArrayObject*'
                    self.put(text, D)

                    D['rank'] = d.rank()
                    self.put(texte, D)
                    if D['c_type'] == 'char*':
                        raise PyFortError, \
                              "Character arrays not supported."
                else:
                    raise PyFortError, \
                        "Intent inout must be an array."

            elif d.intent == "temporary":
                if D['c_type'] == 'char*':
                    raise PyFortError, \
                          "Character temporaries not supported."
                if d.rank():
                    if not apv: 
                        self.put("    PyArrayObject* pyarray_value;\n")
                        apv = 1
                        
                    D['prefix'] = 'a'
                    D['d_type'] = 'PyArrayObject*'
                    self.put(text, D)

                    D['rank'] = d.rank()
                    self.put(texte, D)
                else:
                    D['prefix'] = ''
                    self.put(text, D)

            elif d.intent == "out":
                if D['c_type'] == 'char*':
                    raise PyFortError, \
                          "Character outputs not yet supported."
                if d.rank():
                    if not apv: 
                        self.put("    PyArrayObject* pyarray_value;\n")
                        apv = 1
                        
                    D['prefix'] = 'a'
                    D['d_type'] = 'PyArrayObject*'
                    self.put(text, D)

                    D['prefix'] = 'r'
                    D['d_type'] = 'PyObject*'
                    self.put(text, D)

                    D['rank'] = d.rank()
                    self.put(texte, D)
                else:
                    D['prefix'] = ''
                    self.put(text, D)

            elif d.intent == "hidden":
                D['prefix'] = ''
                self.put(text, D)

        # Check if we need to set pointers for allocatable arrays
        allocatable_array_used = 0
        for a in formal_argument_list:
            d = routine.declaration(a)
            if d.rank() > 1 and d.allocatable:
                allocatable_array_used = 1
        if allocatable_array_used:
            text = \
"""\
    int ii;
"""
            self.put(text)

        # Declare the pointer arrays needed for allocatable arrays
        text = \
"""\
    %(c_type)s%(pointers)s %(prefix)s%(variable_name)s;
"""
        for a in formal_argument_list:
            d = routine.declaration(a)
            if d.rank() > 1 and d.allocatable:
                self.set_variable(a, routine, D)
                for dimension in range(d.rank()):
                    D['prefix'] = (dimension+1)*'p' + 'a'
                    D['pointers'] = (dimension+1)*'*'
                    self.put(text,D)


    def write_initialization(self, routine):
        if self.array_result_flag:
            text = \
"""\
    fortran_result_array = (PyArrayObject*) 0;
    fortran_result_array_length = 1;
"""
            self.put(text)
        text = \
"""\
    %(prefix)s%(variable_name)s = (%(d_type)s) 0;
"""
        formal_argument_list = routine.arguments()
        D={}
        for a in formal_argument_list:
            d = routine.declaration(a)
            if d.rank():
                self.set_variable(a, routine, D)
                D['prefix'] = 'a'
                D['d_type'] = 'PyArrayObject*'
                self.put(text, D)
        text = \
"""\
    keyoption = default_option;
"""
        self.put(text)

    def write_argument_parsing(self, routine):
        "Make the call to PyArg_ParseTuple"
        paps=''
        D = {}
        input_arguments = routine.python_inputs()
        for a in input_arguments:
            self.set_variable(a, routine, D)
            d = routine.declaration(a)
            if d.rank():
                paps = paps + 'O'
            else:
                paps = paps + self.compiler.python_code(d)
        papt = self.compiler.parser_argument_list (routine)
        if papt:
            D['list'] = papt + ', &keyoption'
        else:
            D['list'] = '&keyoption'
        D['paps'] = paps
        text = \
"""
    if(!PyArg_ParseTuple(args, "%(paps)s|i", %(list)s)) {
        return NULL;
    }
"""
        self.put(text, D)

    def write_preprocessing(self, routine):
        "The part between getting the arguments and making the call."
        D={}
        D['routine_name'] = routine.routine_name()        
# Get the intent in arrays
        textin = \
"""\
    if (!(a%(variable_name)s = do_array_in ("%(routine_name)s", "%(variable_name)s", %(variable_name)s, %(python_array_type)s))) goto err;
"""
        for a in routine.python_inputs():
            d = routine.declaration(a)
            if d.intent == 'in':
                if d.rank():
                    self.set_variable(a, routine, D)        
                    D['python_array_type'] = self.compiler.python_array_type(d)
                    self.put(textin, D)

# Get the intent inout arguments
        textinout = \
"""\
    if (!(a%(variable_name)s = do_array_inout ("%(routine_name)s", "%(variable_name)s", %(variable_name)s, %(python_array_type)s))) goto err;
"""
        for a in routine.python_inputs():
            d = routine.declaration(a)
            if d.intent == 'inout':
                if d.rank():
                    self.set_variable(a, routine, D)        
                    D['python_array_type'] = self.compiler.python_array_type(d)
                    self.put(textinout, D)

# Set the sizes of valued integers
        text = \
"""\
    %(variable_name)s = %(value)s;
"""
        for a in routine.valued():
            self.set_variable(a, routine, D)
            d = routine.declaration(a)
            s = string.upper(d.value)
            f = sizere.match (s)
            while f:
                v = f.group(2)
                replacement = 'get_fortran_dim(a' + string.upper(v)
                s = s[0:f.start(1)] + replacement + s[f.end(2):]
                f = sizere.match (s)
            D['value'] = s
            self.put (text, D);

# do size checking on inputs, then transposes if requested.
        text = \
"""\
    e%(variable_name)s[%(j)d] = %(n)s;
"""
        for a in routine.arguments():
            d = routine.declaration(a)
            if d.rank():
                self.set_variable(a, routine, D)
                for j in range(d.rank()):
                    D['j'] = j
                    D['n'] = string.upper(d.dimension(j))
                    self.put(text, D);

        text = \
"""\
    if (!do_size_check ("%(routine_name)s", "%(variable_name)s", a%(variable_name)s, %(rank)s, e%(variable_name)s, keyoption & MIRROR_OPTION)) goto err;
"""
        textin = \
"""\
    if ((keyoption & TRANSPOSE_OPTION) && (a%(variable_name)s->nd > 1)) {
        pyarray_value = a%(variable_name)s;
        a%(variable_name)s = transpose_array ("%(routine_name)s", "%(variable_name)s", pyarray_value);
        Py_DECREF(pyarray_value);
        if(!a%(variable_name)s) goto err;
    }
    pyarray_value = a%(variable_name)s;
    a%(variable_name)s = make_contiguous ("%(routine_name)s", "%(variable_name)s", pyarray_value);
    Py_DECREF(pyarray_value);
    if(!a%(variable_name)s) goto err;
"""
        for a in routine.python_inputs():
            d = routine.declaration(a)
            if d.rank():
                self.set_variable(a, routine, D)        
                D['rank'] = d.rank()
                D['variable'] = D['variable_name']
                D['python_array_type'] = self.compiler.python_array_type(d)
                if d.intent == 'in':
                    self.put(text, D)
                    self.put(textin, D)
                if d.intent == 'inout':
                    self.put(text, D)

# create any desired temporaries and output arrays
        textarray = \
"""\
    if (!(a%(variable_name)s = do_array_create ("%(routine_name)s", "%(variable_name)s", %(python_array_type)s, %(rank)s, e%(variable_name)s, keyoption&MIRROR_OPTION))) goto err;
"""
        for a in routine.temporaries():
            self.set_variable(a, routine, D)
            d = routine.declaration(a)
            if d.rank():
                D['rank'] = d.rank()
                D['python_array_type'] = self.compiler.python_array_type(d)
                self.put(textarray, D)
            else:
                raise routine.routine_name() + ": Argument " + a + "declared temporary but is not dimensioned."

        for a in routine.python_outputs():
            self.set_variable(a, routine, D)
            d = routine.declaration(a)
            if d.rank():
                D['rank'] = d.rank()
                D['python_array_type'] = self.compiler.python_array_type(d)
                self.put(textarray, D)

        # Allocate memory for the pointer arrays needed for ansi-style arrays
        text = \
"""\
    %(prefix)s%(variable_name)s = (%(c_type)s%(pointers)s)malloc((size_t)%(arraysize)ssizeof(%(element)s));
"""
        for a in routine.arguments():
            d = routine.declaration(a)
            if d.rank() > 1 and d.allocatable:
                self.set_variable(a, routine, D)
                for dimension in range(1,d.rank()):
                    D['prefix'] = (dimension+1)*'p' + 'a'
                    D['pointers'] = (dimension+1)*'*'
                    arraysize = ''
                    for j in range(d.rank()-dimension):
                        arraysize = arraysize + string.upper(d.dimension(j))+'*'
                    D['arraysize'] = arraysize
                    D['element'] = D['c_type'] + dimension*'*'
                    self.put(text,D)

        # Fill the pointer arrays needed for allocatable arrays
        text = \
"""\
    pa%(variable_name)s = (%(c_type)s*) (a%(variable_name)s->data);
"""
        for a in routine.arguments():
            d = routine.declaration(a)
            if d.rank() > 1 and d.allocatable:
                self.set_variable(a, routine, D)
                self.put(text,D)

        text = \
"""\
    for (ii=0; ii<%(arraysize)s; ii++) %(prefix1)sa%(variable_name)s[ii]=&(%(prefix2)sa%(variable_name)s[ii*%(stride)s]);
"""
        for a in routine.arguments():
            d = routine.declaration(a)
            if d.rank() > 1 and d.allocatable:
                self.set_variable(a, routine, D)
                for dimension in range(1,d.rank()):
                    arraysize = string.upper(d.dimension(0))
                    for j in range(1,d.rank()-dimension):
                        arraysize = arraysize+'*'+string.upper(d.dimension(j))
                    D['arraysize'] = arraysize
                    D['prefix1'] = (dimension+1)*'p'
                    D['prefix2'] = dimension*'p'
                    D['stride'] = string.upper(d.dimension(d.rank()-dimension))
                    self.put(text,D)

    def write_fortran_call(self, routine):
        self.put("    ")
        if routine.is_function():
            self.put("fortran_result = ")
        self.put(self.fortran_link_name(routine.routine_name()))
        self.put("(")
        actual_argument_list = self.compiler.actual_argument_list(routine)
        self.put(string.join(actual_argument_list, ", \n        "))
        self.put(");\n")

    def write_postprocessing(self, routine):
        text = \
"""\
    fortran_result_array = (PyArrayObject*) PyArray_FromDims(
                            1,
                            &fortran_result_array_length,
                            %(python_array_type)s
                            );
    if (!fortran_result_array) {
        PyErr_SetString(ErrorObject, 
            "%(routine_name)s: failed creating space for fortran result.");
        goto err;
    }
    *((%(d_type)s *)fortran_result_array->data) = fortran_result;
    /* if fortran_result ever gets to be a non-scalar would need work here */
    rfortran_result_array = PyArray_Return(fortran_result_array);
"""
        if self.array_result_flag:
            d = routine.declaration(routine.routine_name())
            D = {'result_type': self.compiler.c_type(d)}
            self.set_variable (routine.routine_name(), routine, D)
            D['python_array_type'] = self.compiler.python_array_type(d)
            self.put (text, D)

        # We created the outputs at the right size
        # so we just have to make them look right to Python
        text = \
"""\
    r%(variable_name)s = PyArray_Return(a%(variable_name)s);
"""
        if self.compiler.executable_name() != 'cc':
          text = \
"""\
    if(!(keyoption&MIRROR_OPTION)) set_transposed_strides(a%(variable_name)s);
""" + text
        output_list = routine.python_outputs()
        if routine.is_function():
            del output_list[0]
        D = {}
        for a in output_list:
            self.set_variable (a, routine, D)
            d = routine.declaration (a)
            if d.rank():
                self.put (text, D)

    def write_return_value_construction(self, routine):
        "Make the call to Py_BuildValue"
#note Py_BuildValue works with an empty format string, returns Py_None
        paps=''
        D = {}
        output_list = routine.python_outputs()
        if routine.is_function():
            del output_list[0]
            d = routine.declaration(routine.routine_name())
            if self.array_result_flag:
                paps = 'O'
            else:
                paps = self.compiler.python_code(d)
                
        for a in output_list:
            self.set_variable(a, routine, D)
            d = routine.declaration(a)
            ct = self.compiler.c_type(d)
            if d.rank():
                paps = paps + 'O'
            else:
                paps = paps + self.compiler.python_code(d)
        D['papt'] = self.compiler.build_argument_list(routine, self.array_result_flag)
        D['paps'] = paps
        text = \
"""
    pyfort_result = Py_BuildValue("%(paps)s"%(papt)s);

"""
        self.put(text, D)

        text = \
"""\
    Py_XDECREF(r%(variable_name)s);
"""
        if self.array_result_flag:
            D['variable_name'] = 'fortran_result_array'
            self.put(text, D)
        for a in output_list:
            d = routine.declaration(a)
            self.set_variable(a, routine, D)
            if d.rank():
                self.put(text, D)
        self.put(\
"""\
    return pyfort_result;
""")
        
    def write_fortran_argument_cleanup(self, routine, error_flag):
        text = \
"""\
    Py_XDECREF((PyObject*) a%(name)s);
"""
        D={}
        if(error_flag):
            err_label_needed = 0
            for a in routine.arguments():
                d = routine.declaration(a)
                if d.rank():
                    err_label_needed = 1
            if self.array_result_flag:
                err_label_needed = 1

            if err_label_needed:
                self.put("err:\n")
                if self.array_result_flag:
                    self.put(\
"""\
    Py_XDECREF((PyObject*) fortran_result_array);
""")
                for a in routine.arguments():
                    d = routine.declaration(a)
                    D['name'] = string.upper(a)
                    if d.rank():
                        if d.intent != "inout":
                            self.put(text, D)
                self.put("    return NULL;\n")
        else:
            for a in routine.python_inputs() + routine.temporaries():
                d = routine.declaration(a)
                D['name'] = string.upper(a)
                if d.rank():
                    if d.intent != "inout":
                        self.put(text, D)
            text = \
"""\
    free (%(prefix)s%(variable_name)s);
"""
            for a in routine.arguments():
                d = routine.declaration(a)
                if d.rank() > 1 and d.allocatable:
                    self.set_variable(a, routine, D)
                    for dimension in range(1,d.rank()):
                        D['prefix'] = (dimension+1)*'p' + 'a'
                        self.put(text,D)

    def write_method_finish(self, routine):
        "Write the end of the method"
        D={'routine_name': routine.routine_name()}
        text = \
"""\
} 
/* end of wrapper for %(routine_name)s */
"""
        self.put(text, D)
# helpers
    def put(self, text, dictionary={}):
        "Put out the formatted text using the dictionary"
        self.module_file.write(text % dictionary)

    def fortran_link_name (self, name):
        "Return the Fortran link name."
        return self.compiler.link_name(name)


















www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.