[Numpy-svn] r3170 - in trunk/numpy/f2py/lib: . research research/pointers src
numpy-svn at scipy.org
numpy-svn at scipy.org
Sat Sep 16 01:56:48 EDT 2006
Author: pearu
Date: 2006-09-16 00:56:18 -0500 (Sat, 16 Sep 2006)
New Revision: 3170
Added:
trunk/numpy/f2py/lib/doc.txt
trunk/numpy/f2py/lib/python_wrapper.py
trunk/numpy/f2py/lib/research/pointers/
trunk/numpy/f2py/lib/research/pointers/pointer_size.c
trunk/numpy/f2py/lib/research/pointers/settypeinfo.f90
trunk/numpy/f2py/lib/src/
trunk/numpy/f2py/lib/src/F_FUNC.cpp
trunk/numpy/f2py/lib/src/pyobj_to_Py_complex.c
trunk/numpy/f2py/lib/src/pyobj_to_double.c
trunk/numpy/f2py/lib/src/pyobj_to_long.c
trunk/numpy/f2py/lib/src/pyobj_to_npy_longlong.c
trunk/numpy/f2py/lib/src/pyobj_to_string_len.c
Modified:
trunk/numpy/f2py/lib/analyzefortran.py
trunk/numpy/f2py/lib/base_classes.py
trunk/numpy/f2py/lib/block_statements.py
trunk/numpy/f2py/lib/parsefortran.py
trunk/numpy/f2py/lib/statements.py
trunk/numpy/f2py/lib/typedecl_statements.py
trunk/numpy/f2py/lib/utils.py
Log:
4G f2py: first working example.
Modified: trunk/numpy/f2py/lib/analyzefortran.py
===================================================================
--- trunk/numpy/f2py/lib/analyzefortran.py 2006-09-16 02:08:59 UTC (rev 3169)
+++ trunk/numpy/f2py/lib/analyzefortran.py 2006-09-16 05:56:18 UTC (rev 3170)
@@ -19,11 +19,14 @@
block is a BeginSource instance with relevant attributes:
name - reader name
content - a list of statements
+
Statements are either block statements or simple statements.
+
Block statements have the following relevant attributes:
name - block name
blocktype - statement name (equal to lowered statement class name)
content - a list of statements
+
Block statements may have additional attributes:
BeginSource: top
Module:
@@ -42,6 +45,7 @@
Associate: associations
Type: specs, params
Enum:
+
Simple statements have various attributes:
Assignment: variable, expr
PointerAssignment: variable, expr
Modified: trunk/numpy/f2py/lib/base_classes.py
===================================================================
--- trunk/numpy/f2py/lib/base_classes.py 2006-09-16 02:08:59 UTC (rev 3169)
+++ trunk/numpy/f2py/lib/base_classes.py 2006-09-16 05:56:18 UTC (rev 3170)
@@ -50,13 +50,29 @@
% (self.__class__.__name__,name,','.join(self._attributes.keys()))
self._attributes[name] = value
- def __repr__(self):
- l = []
+ def isempty(self):
for k in self._attributes.keys():
v = getattr(self,k)
- l.append('%s=%r' % (k,v))
- return '%s(%s)' % (self.__class__.__name__,', '.join(l))
+ if v: return False
+ return True
+ def __repr__(self): return self.torepr()
+
+ def torepr(self, depth=-1, tab = ''):
+ if depth==0: return tab + self.__class__.__name__
+ l = [self.__class__.__name__+':']
+ ttab = tab + ' '
+ for k in self._attributes.keys():
+ v = getattr(self,k)
+ if v:
+ if isinstance(v,list):
+ l.append(ttab + '%s=<%s-list>' % (k,len(v)))
+ elif isinstance(v,dict):
+ l.append(ttab + '%s=<dict with keys %s>' % (k,v.keys()))
+ else:
+ l.append(ttab + '%s=<%s>' % (k,type(v)))
+ return '\n'.join(l)
+
def todict(self):
d = {}
for k in self._attributes.keys():
@@ -95,6 +111,33 @@
self.init = None
return
+ def get_bit_size(self):
+ typesize = self.typedecl.get_bit_size(self)
+ if self.is_pointer():
+ # The size of pointer descriptor is compiler version dependent. Read:
+ # http://www.nersc.gov/vendor_docs/intel/f_ug1/pgwarray.htm
+ # https://www.cca-forum.org/pipermail/cca-fortran/2003-February/000123.html
+ # https://www.cca-forum.org/pipermail/cca-fortran/2003-February/000122.html
+ # On sgi descriptor size may be 128+ bits!
+ if self.is_array():
+ wordsize = 4 # XXX: on a 64-bit system it is 8.
+ rank = len(self.bounds or self.dimension)
+ return 6 * wordsize + 12 * rank
+ return typesize
+ if self.is_array():
+ size = reduce(lambda x,y:x*y,self.bounds or self.dimension,1)
+ if self.length:
+ size *= self.length
+ return size * typesize
+ if self.length:
+ return self.length * typesize
+ return typesize
+
+ def get_typedecl(self):
+ if self.typedecl is None:
+ self.set_type(self.parent.get_type(self.name))
+ return self.typedecl
+
def add_parent(self, parent):
if id(parent) not in map(id, self.parents):
self.parents.append(parent)
@@ -182,7 +225,10 @@
def is_parameter(self): return 'PARAMETER' in self.attributes
def is_optional(self): return 'OPTIONAL' in self.attributes
def is_required(self): return 'REQUIRED' in self.attributes
+ def is_pointer(self): return 'POINTER' in self.attributes
+ def is_array(self): return not not (self.bounds or self.dimensions)
+
def update(self, *attrs):
attributes = self.attributes
if len(attrs)==1 and isinstance(attrs[0],(tuple,list)):
@@ -221,8 +267,9 @@
def __str__(self):
s = ''
- if self.typedecl is not None:
- s += self.typedecl.tostr() + ' '
+ typedecl = self.get_typedecl()
+ if typedecl is not None:
+ s += typedecl.tostr() + ' '
a = self.attributes[:]
if self.dimension is not None:
a.append('DIMENSION(%s)' % (', '.join(self.dimension)))
@@ -246,6 +293,10 @@
s += ' = ' + self.init
return s
+ def analyze(self):
+ typedecl = self.get_typedecl()
+ return
+
class ProgramBlock:
pass
@@ -257,6 +308,7 @@
isvalid - boolean, when False, the Statement instance will be ignored
"""
modes = ['free90','fix90','fix77','pyf']
+ _repr_attr_names = []
def __init__(self, parent, item):
self.parent = parent
@@ -264,16 +316,19 @@
self.reader = item.reader
else:
self.reader = parent.reader
- self.top = getattr(parent,'top',None)
+ self.top = getattr(parent,'top',None) # the top of statement tree
+ self.item = item
+
if isinstance(parent, ProgramBlock):
self.programblock = parent
elif isinstance(self, ProgramBlock):
self.programblock = self
elif hasattr(parent,'programblock'):
self.programblock = parent.programblock
+ else:
+ #self.warning('%s.programblock attribute not set.' % (self.__class__.__name__))
+ pass
- self.item = item
-
# when a statement instance is constructed by error, set isvalid to False
self.isvalid = True
# when a statement should be ignored, set ignore to True
@@ -292,6 +347,31 @@
return
+ def __repr__(self):
+ return self.torepr()
+
+ def torepr(self, depth=-1,incrtab=''):
+ tab = incrtab + self.get_indent_tab()
+ clsname = self.__class__.__name__
+ l = [tab + yellow_text(clsname)]
+ if depth==0:
+ return '\n'.join(l)
+ ttab = tab + ' '
+ for n in self._repr_attr_names:
+ attr = getattr(self, n, None)
+ if not attr: continue
+ if hasattr(attr, 'torepr'):
+ r = attr.torepr(depht-1,incrtab)
+ else:
+ r = repr(attr)
+ l.append(ttab + '%s=%s' % (n, r))
+ if self.item is not None: l.append(ttab + 'item=%r' % (self.item))
+ if not self.isvalid: l.append(ttab + 'isvalid=%r' % (self.isvalid))
+ if self.ignore: l.append(ttab + 'ignore=%r' % (self.ignore))
+ if not self.a.isempty():
+ l.append(ttab + 'a=' + self.a.torepr(depth-1,incrtab+' ').lstrip())
+ return '\n'.join(l)
+
def get_indent_tab(self,colon=None,deindent=False):
if self.reader.isfix:
tab = ' '*6
@@ -321,8 +401,11 @@
return tab
def format_message(self, kind, message):
- message = self.reader.format_message(kind, message,
- self.item.span[0], self.item.span[1])
+ if self.item is not None:
+ message = self.reader.format_message(kind, message,
+ self.item.span[0], self.item.span[1])
+ else:
+ return message
return message
def show_message(self, message, stream=sys.stderr):
@@ -350,14 +433,27 @@
return
def get_variable(self, name):
- variables = self.parent.a.variables
- if not variables.has_key(name):
- variables[name] = var = Variable(self, name)
- else:
- var = variables[name]
- var.add_parent(self)
- return var
+ """ Return Variable instance of variable name.
+ """
+ mth = getattr(self,'get_variable_by_name', self.parent.get_variable)
+ return mth(name)
+ def get_type(self, name):
+ """ Return type declaration using implicit rules
+ for name.
+ """
+ mth = getattr(self,'get_type_by_name', self.parent.get_type)
+ return mth(name)
+
+ def get_type_decl(self, kind):
+ mth = getattr(self,'get_type_decl_by_kind', self.parent.get_type_decl)
+ return mth(kind)
+
+ def get_provides(self):
+ """ Returns dictonary containing statements that block provides or None when N/A.
+ """
+ return
+
class BeginStatement(Statement):
""" <blocktype> <name>
@@ -371,13 +467,14 @@
with the line label
parent - Block or FortranParser instance
item - Line instance containing the block start statement
- get_item, put_item - methods to retrive/submit Line instaces
+ get_item, put_item - methods to retrive/submit Line instances
from/to Fortran reader.
isvalid - boolean, when False, the Block instance will be ignored.
stmt_cls, end_stmt_cls
"""
+ _repr_attr_names = ['blocktype','name'] + Statement._repr_attr_names
def __init__(self, parent, item=None):
self.content = []
@@ -388,7 +485,6 @@
if not hasattr(self, 'name'):
# process_item may change this
self.name = '__'+self.blocktype.upper()+'__'
-
Statement.__init__(self, parent, item)
return
@@ -401,6 +497,20 @@
l.append(str(c))
return '\n'.join(l)
+ def torepr(self, depth=-1, incrtab=''):
+ tab = incrtab + self.get_indent_tab()
+ ttab = tab + ' '
+ l=[Statement.torepr(self, depth=depth,incrtab=incrtab)]
+ if depth==0 or not self.content:
+ return '\n'.join(l)
+ l.append(ttab+'content:')
+ for c in self.content:
+ if isinstance(c,EndStatement):
+ l.append(c.torepr(depth-1,incrtab))
+ else:
+ l.append(c.torepr(depth-1,incrtab + ' '))
+ return '\n'.join(l)
+
def process_item(self):
""" Process the line
"""
@@ -543,6 +653,7 @@
name
blocktype
"""
+ _repr_attr_names = ['blocktype','name'] + Statement._repr_attr_names
def __init__(self, parent, item):
if not hasattr(self, 'blocktype'):
@@ -571,7 +682,10 @@
def analyze(self):
return
+ def get_indent_tab(self,colon=None,deindent=False):
+ return Statement.get_indent_tab(self, colon=colon, deindent=True)
+
def __str__(self):
- return self.get_indent_tab()[:-2] + 'END %s %s'\
+ return self.get_indent_tab() + 'END %s %s'\
% (self.blocktype.upper(),self.name or '')
Modified: trunk/numpy/f2py/lib/block_statements.py
===================================================================
--- trunk/numpy/f2py/lib/block_statements.py 2006-09-16 02:08:59 UTC (rev 3169)
+++ trunk/numpy/f2py/lib/block_statements.py 2006-09-16 05:56:18 UTC (rev 3170)
@@ -14,7 +14,7 @@
a = AttributeHolder(implicit_rules = {})
- def get_type(self, name):
+ def get_type_by_name(self, name):
implicit_rules = self.a.implicit_rules
if implicit_rules is None:
raise AnalyzeError,'Implicit rules mapping is null'
@@ -74,8 +74,19 @@
class HasVariables:
- a = AttributeHolder(variables = {})
+ a = AttributeHolder(variables = {},
+ variable_names = [] # defines the order of declarations
+ )
+ def get_variable_by_name(self, name):
+ variables = self.a.variables
+ if variables.has_key(name):
+ var = variables[name]
+ else:
+ var = variables[name] = Variable(self, name)
+ self.a.variable_names.append(name)
+ return var
+
def topyf(self,tab=''):
s = ''
for name, var in self.a.variables.items():
@@ -92,8 +103,17 @@
s += stmt.topyf(tab=' '+tab)
return s
+ def get_type_decl_by_kind(self, kind):
+ type_decls = self.a.type_decls
+ type_decl = type_decls.get(kind, None)
+ if type_decl is None:
+ return self.get_entity(kind)
+ raise NotImplementedError,'get type_decl from use modules'
+ return type_decl
+
class HasAttributes:
+ known_attributes = []
a = AttributeHolder(attributes = [])
def topyf(self, tab=''):
@@ -102,6 +122,29 @@
s += tab + attr + '\n'
return s
+ def is_private(self):
+ attributes = self.a.attributes
+ if 'PUBLIC' in attributes: return False
+ if 'PRIVATE' in attributes: return True
+ return
+ def is_public(self): return not self.is_private()
+
+ def update_attributes(self,*attrs):
+ attributes = self.a.attributes
+ known_attributes = self.known_attributes
+ if len(attrs)==1 and isinstance(attrs[0],(tuple,list)):
+ attrs = attrs[0]
+ for attr in attrs:
+ uattr = attr.upper()
+ if uattr not in attributes:
+ if isinstance(known_attributes,(list, tuple)):
+ if uattr not in known_attributes:
+ self.warning('unknown attribute %r' % (attr))
+ elif known_attributes(uattr):
+ self.warning('unknown attribute %r' % (attr))
+ attributes.append(uattr)
+ return
+
class HasModuleProcedures:
a = AttributeHolder(module_procedures = [])
@@ -196,10 +239,15 @@
"""
match = re.compile(r'module\s*\w+\Z', re.I).match
end_stmt_cls = EndModule
+
a = AttributeHolder(module_subprogram = {},
- module_data = {},
+ module_provides = {}, # all symbols that are public and so
+ # can be imported via USE statement
+ # by other blocks
)
+ known_attributes = ['PUBLIC', 'PRIVATE']
+
def get_classes(self):
return access_spec + specification_part + module_subprogram_part
@@ -208,6 +256,9 @@
self.name = name
return BeginStatement.process_item(self)
+ def get_provides(self):
+ return self.a.module_provides
+
def analyze(self):
content = self.content[:]
@@ -225,11 +276,19 @@
if content:
self.show_message('Not analyzed content: %s' % content)
+ module_provides = self.a.module_provides
+ for name, var in self.a.variables.items():
+ if var.is_public():
+ if module_provides.has_key(name):
+ self.warning('module data object name conflict with %s, overriding.' % (name))
+ module_provides[name] = var
+
return
def topyf(self, tab=''):
s = tab + 'MODULE '+self.name + '\n'
s += HasImplicitStmt.topyf(self, tab=tab+' ')
+ s += HasAttributesStmt.topyf(self, tab=tab+' ')
s += HasTypeDecls.topyf(self, tab=tab+' ')
s += HasVariables.topyf(self, tab=tab+' ')
s += tab + ' CONTAINS\n'
@@ -270,7 +329,7 @@
match = re.compile(r'end(\s*program\s*\w*|)\Z', re.I).match
class Program(BeginStatement, ProgramBlock,
- HasAttributes,
+ HasAttributes, # XXX: why Program needs .attributes?
HasImplicitStmt, HasUseStmt):
""" PROGRAM [name]
"""
@@ -340,6 +399,8 @@
end_stmt_cls = EndInterface
blocktype = 'interface'
+ a = AttributeHolder(interface_provides = {})
+
def get_classes(self):
return intrinsic_type_spec + interface_specification
@@ -358,7 +419,30 @@
return 'ABSTRACT INTERFACE'
return 'INTERFACE '+ str(self.generic_spec)
+ def get_provides(self):
+ return self.a.interface_provides
+ def analyze(self):
+ content = self.content[:]
+
+ while content:
+ stmt = content.pop(0)
+ if isinstance(stmt, self.end_stmt_cls):
+ break
+ stmt.analyze()
+ assert isinstance(stmt, SubProgramStatement),`stmt.__class__.__name__`
+ if content:
+ self.show_message('Not analyzed content: %s' % content)
+
+ parent_provides = self.parent.get_provides()
+ if parent_provides is not None:
+ if self.is_public():
+ if parent_provides.has_key(self.name):
+ self.warning('interface name conflict with %s, overriding.' % (self.name))
+ parent_provides[self.name] = self
+
+ return
+
# Subroutine
class SubProgramStatement(BeginStatement, ProgramBlock,
@@ -369,6 +453,8 @@
"""
[ <prefix> ] <FUNCTION|SUBROUTINE> <name> [ ( <args> ) ] [ <suffix> ]
"""
+ known_attributes = ['PUBLIC', 'PRIVATE']
+
a = AttributeHolder(internal_subprogram = {})
def process_item(self):
@@ -430,7 +516,7 @@
content = self.content[:]
if self.prefix:
- self.a.attributes.extend(prefix.upper().split())
+ self.update_attributes(prefix.upper().split())
variables = self.a.variables
for a in self.args:
@@ -459,6 +545,13 @@
if content:
self.show_message('Not analyzed content: %s' % content)
+ parent_provides = self.parent.get_provides()
+ if parent_provides is not None:
+ if self.is_public():
+ if parent_provides.has_key(self.name):
+ self.warning('module subprogram name conflict with %s, overriding.' % (self.name))
+ parent_provides[self.name] = self
+
return
def topyf(self, tab=''):
@@ -486,6 +579,7 @@
"""
end_stmt_cls = EndSubroutine
match = re.compile(r'(recursive|pure|elemental|\s)*subroutine\s*\w+', re.I).match
+ _repr_attr_names = ['prefix','bind','suffix','args'] + Statement._repr_attr_names
# Function
@@ -506,6 +600,7 @@
"""
end_stmt_cls = EndFunction
match = re.compile(r'(recursive|pure|elemental|\s)*function\s*\w+', re.I).match
+ _repr_attr_names = ['prefix','bind','suffix','args','typedecl'] + Statement._repr_attr_names
# Handle subprogram prefixes
@@ -800,7 +895,11 @@
end_stmt_cls = EndType
a = AttributeHolder(extends = None,
- parameters = [])
+ parameters = {},
+ component_names = [], # specifies component order for sequence types
+ components = {}
+ )
+ known_attributes = re.compile(r'\A(PUBLIC|PRIVATE|SEQUENCE|ABSTRACT|BIND\s*\(.*\))\Z').match
def process_item(self):
line = self.item.get_line()[4:].lstrip()
@@ -858,15 +957,41 @@
spec = 'BIND(%s)' % (', '.join(args))
else:
spec = '%s(%s)' % (s,n)
- self.warning('Unknown type-attr-spec %r' % (spec))
else:
spec = spec.upper()
- if spec not in ['PUBLIC', 'PRIVATE', 'ABSTRACT']:
- self.warning('Unknown type-attr-spec %r' % (spec))
- self.a.attributes.append(spec)
- self.a.parameters.extend(self.params)
- assert isinstance(self.parent,HasTypeDecls),`self.parent.__class__`
+ self.update_attributes(spec)
+
+ component_names = self.a.component_names
+ content = self.content[:]
+ while content:
+ stmt = content.pop(0)
+ if isinstance(stmt, self.end_stmt_cls):
+ break
+ stmt.analyze()
+
+ if content:
+ self.show_message('Not analyzed content: %s' % content)
+
+ parameters = self.a.parameters
+ components = self.a.components
+ component_names = self.a.component_names
+ for name in self.a.variable_names:
+ var = self.a.variables[name]
+ if name in self.params:
+ parameters[name] = var
+ else:
+ component_names.append(name)
+ components[name] = var
+
self.parent.a.type_decls[self.name] = self
+
+ parent_provides = self.parent.get_provides()
+ if parent_provides is not None:
+ if self.is_public():
+ if parent_provides.has_key(self.name):
+ self.warning('type declaration name conflict with %s, overriding.' % (self.name))
+ parent_provides[self.name] = self
+
return
def topyf(self, tab=''):
Added: trunk/numpy/f2py/lib/doc.txt
===================================================================
--- trunk/numpy/f2py/lib/doc.txt 2006-09-16 02:08:59 UTC (rev 3169)
+++ trunk/numpy/f2py/lib/doc.txt 2006-09-16 05:56:18 UTC (rev 3170)
@@ -0,0 +1,311 @@
+
+Created: September 2006
+Author: Pearu Peterson <pearu.peterson at gmail.com>
+
+Structure
+=========
+
+numpy.f2py.lib package contains the following files:
+
+readfortran.py
+--------------
+
+Tools for reading Fortran codes from file and string objects.
+
+To read Fortran code from a file, use FortranFileReader class.
+
+FortranFileReader class is iterator over Fortran code lines
+as is derived from FortranReaderBase class.
+It automatically handles line continuations and comments as
+well as detects if Fortran file is in free or fixed format.
+
+For example,
+
+::
+ >>> from readfortran import *
+ >>> import os
+ >>> reader = FortranFileReader(os.path.expanduser('~/src/blas/daxpy.f'))
+ >>> reader.next()
+ Line('subroutine daxpy(n,da,dx,incx,dy,incy)',(1, 1),'')
+ >>> reader.next()
+ Comment('c constant times a vector plus a vector.\nc uses unrolled loops for increments equal to one.\nc jack dongarra, linpack, 3/11/78.\nc modified 12/3/93, array(1) declarations changed to array(*)',(3, 6))
+ >>> reader.next()
+ Line('double precision dx(*),dy(*),da',(8, 8),'')
+ >>> reader.next()
+ Line('integer i,incx,incy,ix,iy,m,mp1,n',(9, 9),'')
+
+FortranReaderBase.next() method may return Line, SyntaxErrorLine, Comment, MultiLine,
+SyntaxErrorMultiLine instances.
+
+Line instance has the following attributes:
+
+ * .line - contains Fortran code line
+ * .span - a 2-tuple containing the span of line numbers containing
+ Fortran code in the original Fortran file
+ * .label - the label of Fortran code line
+ * .reader - the FortranReaderBase class instance
+ * .strline - if not None then contains Fortran code line with parenthesis
+ content and string literal constants saved in .strlinemap dictionary.
+ * .is_f2py_directive - True if line started with f2py directive comment.
+
+and the following methods:
+
+ * .get_line() - returns .strline (also evalutes it if None). Also
+ handles Hollerith contstants in fixed F77 mode.
+ * .isempty() - returns True if Fortran line contains no code.
+ * .copy(line=None, apply_map=False) - returns a Line instance
+ with given .span, .label, .reader information but line content
+ replaced with line (when not None) and applying .strlinemap
+ mapping (when apply_map is True).
+ * .apply_map(line) - apply .strlinemap mapping to line.
+ * .has_map() - returns True if .strlinemap mapping exists.
+
+For example,
+
+::
+
+ >>> item = reader.next()
+ >>> item
+ Line('if(n.le.0)return',(11, 11),'')
+ >>> item.line
+ 'if(n.le.0)return'
+ >>> item.strline
+ 'if(F2PY_EXPR_TUPLE_4)return'
+ >>> item.strlinemap
+ {'F2PY_EXPR_TUPLE_4': 'n.le.0'}
+ >>> item.label
+ ''
+ >>> item.span
+ (11, 11)
+ >>> item.get_line()
+ 'if(F2PY_EXPR_TUPLE_4)return'
+ >>> item.copy('if(F2PY_EXPR_TUPLE_4)pause',True)
+ Line('if(n.le.0)pause',(11, 11),'')
+
+Comment instance has the following attributes:
+
+ * .comment - comment string
+ * .span - a 2-tuple containing the span of line numbers containing
+ Fortran comment in the original Fortran file
+ * .reader - the FortranReaderBase class instance
+
+and .isempty() method.
+
+MultiLine class represents multiline syntax in .pyf files::
+
+ <prefix>'''<lines>'''<suffix>
+
+MultiLine instance has the following attributes:
+
+ * .prefix - the content of <prefix>
+ * .block - a list of lines
+ * .suffix - the content of <suffix>
+ * .span - a 2-tuple containing the span of line numbers containing
+ multiline syntax in the original Fortran file
+ * .reader - the FortranReaderBase class instance
+
+and .isempty() method.
+
+SyntaxErrorLine and SyntaxErrorMultiLine are like Line and MultiLine
+classes, respectively, with a functionality of issuing an error
+message to sys.stdout when constructing an instance of the corresponding
+class.
+
+To read a Fortran code from a string, use FortranStringReader class::
+
+ reader = FortranStringReader(<string>, <isfree>, <isstrict>)
+
+where the second and third arguments are used to specify the format
+of the given <string> content. When <isfree> and <isstrict> are both
+True, the content of a .pyf file is assumed. For example,
+
+::
+
+ >>> code = """
+ ... c comment
+ ... subroutine foo(a)
+ ... print*, "a=",a
+ ... end
+ ... """
+ >>> reader = FortranStringReader(code, False, True)
+ >>> reader.next()
+ Comment('c comment',(2, 2))
+ >>> reader.next()
+ Line('subroutine foo(a)',(3, 3),'')
+ >>> reader.next()
+ Line('print*, "a=",a',(4, 4),'')
+ >>> reader.next()
+ Line('end',(5, 5),'')
+
+FortranReaderBase has the following attributes:
+
+ * .source - a file-like object with .next() method to retrive
+ a source code line
+ * .source_lines - a list of read source lines
+ * .reader - a FortranReaderBase instance for reading files
+ from INCLUDE statements.
+ * .include_dirs - a list of directories where INCLUDE files
+ are searched. Default is ['.'].
+
+and the following methods:
+
+ * .set_mode(isfree, isstrict) - set Fortran code format information
+ * .close_source() - called when .next() raises StopIteration exception.
+
+parsefortran.py
+---------------
+
+Parse Fortran code from FortranReaderBase iterator.
+
+FortranParser class holds the parser information while
+iterating over items returned by FortranReaderBase iterator.
+The parsing information, collected when calling .parse() method,
+is saved in .block attribute as an instance
+of BeginSource class defined in block_statements.py file.
+
+For example,
+
+::
+
+ >>> reader = FortranStringReader(code, False, True)
+ >>> parser = FortranParser(reader)
+ >>> parser.parse()
+ >>> print parser.block
+ !BEGINSOURCE <cStringIO.StringI object at 0xb751d500> mode=fix77
+ SUBROUTINE foo(a)
+ PRINT *, "a=", a
+ END SUBROUTINE foo
+
+block_statements.py, base_classes.py, typedecl_statements.py, statements.py
+---------------------------------------------------------------------------
+
+The model for representing Fortran code statements consists of a tree of Statement
+classes defined in base_classes.py. There are two types of statements: one line
+statements and block statements. Block statements consists of start and end
+statements, and content statements in between that can be of both types again.
+
+Statement instance has the following attributes:
+
+ * .parent - it is either parent block-type statement or FortranParser instance.
+ * .item - Line instance containing Fortran statement line information, see above.
+ * .isvalid - when False then processing this Statement instance will be skipped,
+ for example, when the content of .item does not match with
+ the Statement class.
+ * .ignore - when True then the Statement instance will be ignored.
+ * .modes - a list of Fortran format modes where the Statement instance is valid.
+
+and the following methods:
+
+ * .info(message), .warning(message), .error(message) - to spit messages to
+ sys.stderr stream.
+ * .get_variable(name) - get Variable instance by name that is defined in
+ current namespace. If name is not defined, then the corresponding
+ Variable instance is created.
+ * .analyze() - calculate various information about the Statement, this information
+ is saved in .a attribute that is AttributeHolder instance.
+
+All statement classes are derived from Statement class. Block statements are
+derived from BeginStatement class and is assumed to end with EndStatement
+instance in .content attribute list. BeginStatement and EndStatement instances
+have the following attributes:
+
+ * .name - name of the block, blocks without names use line label
+ as the name.
+ * .blocktype - type of the block (derived from class name)
+ * .content - a list of Statement (or Line) instances.
+
+and the following methods:
+
+ * .__str__() - returns string representation of Fortran code.
+
+A number of statements may declare a variable that is used in other
+statement expressions. Variables are represented via Variable class
+and its instances have the following attributes:
+
+ * .name - name of the variable
+ * .typedecl - type declaration
+ * .dimension - list of dimensions
+ * .bounds - list of bounds
+ * .length - length specs
+ * .attributes - list of attributes
+ * .bind - list of bind information
+ * .intent - list of intent information
+ * .check - list of check expressions
+ * .init - initial value of the variable
+ * .parent - statement instance declaring the variable
+ * .parents - list of statements that specify variable information
+
+and the following methods:
+
+ * .is_private()
+ * .is_public()
+ * .is_allocatable()
+ * .is_external()
+ * .is_intrinsic()
+ * .is_parameter()
+ * .is_optional()
+ * .is_required()
+
+The following type declaration statements are defined in typedecl_statements.py:
+
+ Integer, Real, DoublePrecision, Complex, DoubleComplex, Logical,
+ Character, Byte, Type, Class
+
+and they have the following attributes:
+
+ * .selector - contains lenght and kind specs
+ * .entity_decls, .attrspec
+
+and methods:
+
+ * .tostr() - return string representation of Fortran type declaration
+ * .astypedecl() - pure type declaration instance, it has no .entity_decls
+ and .attrspec.
+ * .analyze() - processes .entity_decls and .attsspec attributes and adds
+ Variable instance to .parent.a.variables dictionary.
+
+The following block statements are defined in block_statements.py:
+
+ BeginSource, Module, PythonModule, Program, BlockData, Interface,
+ Subroutine, Function, Select, Where, Forall, IfThen, If, Do,
+ Associate, TypeDecl (Type), Enum
+
+Block statement classes may have different properties which are declared via
+deriving them from the following classes:
+
+ HasImplicitStmt, HasUseStmt, HasVariables, HasTypeDecls,
+ HasAttributes, HasModuleProcedures, ProgramBlock
+
+In summary, .a attribute may hold different information sets as follows:
+
+ BeginSource - .module, .external_subprogram, .blockdata
+ Module - .attributes, .implicit_rules, .use, .use_provides, .variables,
+ .type_decls, .module_subprogram, .module_data
+ PythonModule - .implicit_rules, .use, .use_provides
+ Program - .attributes, .implicit_rules, .use, .use_provides
+ BlockData - .implicit_rules, .use, .use_provides, .variables
+ Interface - .implicit_rules, .use, .use_provides, .module_procedures
+ Function, Subroutine - .implicit_rules, .attributes, .use, .use_statements,
+ .variables, .type_decls, .internal_subprogram
+ TypeDecl - .variables, .attributes
+
+Block statements have the following methods:
+
+ * .get_classes() - returns a list of Statement classes that are valid
+ as a content of given block statement.
+
+The following one line statements are defined:
+
+ Implicit, TypeDeclarationStatement derivatives (see above),
+ Assignment, PointerAssignment, Assign, Call, Goto, ComputedGoto,
+ AssignedGoto, Continue, Return, Stop, Print, Read, Write, Flush,
+ Wait, Contains, Allocate, Deallocate, ModuleProcedure, Access,
+ Public, Private, Close, Cycle, Backspace, Endfile, Reeinf, Open,
+ Format, Save, Data, Nullify, Use, Exit, Parameter, Equivalence,
+ Dimension, Target, Pointer, Protected, Volatile, Value,
+ ArithmeticIf, Intrinsic, Inquire, Sequence, External, Namelist,
+ Common, Optional, Intent, Entry, Import, Forall,
+ SpecificBinding, GenericBinding, FinalBinding, Allocatable,
+ Asynchronous, Bind, Else, ElseIf, Case, Where, ElseWhere,
+ Enumerator, FortranName, Threadsafe, Depend, Check,
+ CallStatement, CallProtoArgument, Pause
Modified: trunk/numpy/f2py/lib/parsefortran.py
===================================================================
--- trunk/numpy/f2py/lib/parsefortran.py 2006-09-16 02:08:59 UTC (rev 3169)
+++ trunk/numpy/f2py/lib/parsefortran.py 2006-09-16 05:56:18 UTC (rev 3170)
@@ -10,6 +10,8 @@
Created: May 2006
"""
+__all__ = ['FortranParser']
+
import re
import sys
import traceback
@@ -24,6 +26,10 @@
cache = {}
def __init__(self, reader):
+ """
+ Parser of FortranReader structure.
+ Use .parse() method for parsing, parsing result is saved in .block attribute.
+ """
self.reader = reader
if self.cache.has_key(reader.id):
parser = self.cache[reader.id]
@@ -156,7 +162,7 @@
parser = FortranParser(reader)
parser.parse()
parser.analyze()
- print parser.block.topyf()
+ print parser.block.torepr(4)
#print parser.block
def profile_main():
Added: trunk/numpy/f2py/lib/python_wrapper.py
===================================================================
--- trunk/numpy/f2py/lib/python_wrapper.py 2006-09-16 02:08:59 UTC (rev 3169)
+++ trunk/numpy/f2py/lib/python_wrapper.py 2006-09-16 05:56:18 UTC (rev 3170)
@@ -0,0 +1,549 @@
+
+__all__ = ['TypeWrapper']
+
+import re
+import os
+import sys
+
+from block_statements import *
+#from typedecl_statements import intrinsic_type_spec, Character
+from utils import CHAR_BIT
+
+class WrapperBase:
+
+
+ def __init__(self):
+ self.srcdir = os.path.join(os.path.dirname(__file__),'src')
+ return
+ def warning(self, message):
+ print >> sys.stderr, message
+ def info(self, message):
+ print >> sys.stderr, message
+
+ def get_resource_content(self, name, ext):
+ if name.startswith('pyobj_to_'):
+ body = self.generate_pyobj_to_ctype_c(name[9:])
+ if body is not None: return body
+ generator_mth_name = 'generate_' + name + ext.replace('.','_')
+ generator_mth = getattr(self, generator_mth_name, lambda : None)
+ body = generator_mth()
+ if body is not None:
+ return body
+ fn = os.path.join(self.srcdir,name+ext)
+ if os.path.isfile(fn):
+ f = open(fn,'r')
+ body = f.read()
+ f.close()
+ return body
+ self.warning('No such file: %r' % (fn))
+ return
+
+ def get_dependencies(self, code):
+ l = []
+ for uses in re.findall(r'(?<=depends:)([,\w\s.]+)', code, re.I):
+ for use in uses.split(','):
+ use = use.strip()
+ if not use: continue
+ l.append(use)
+ return l
+
+ def apply_attributes(self, template):
+ """
+ Apply instance attributes to template string.
+
+ Replace rules for attributes:
+ _list - will be joined with newline
+ _clist - _list will be joined with comma
+ _elist - _list will be joined
+ ..+.. - attributes will be added
+ [..] - will be evaluated
+ """
+ replace_names = set(re.findall(r'[ ]*%\(.*?\)s', template))
+ d = {}
+ for name in replace_names:
+ tab = ' ' * (len(name)-len(name.lstrip()))
+ name = name.lstrip()[2:-2]
+ names = name.split('+')
+ joinsymbol = '\n'
+ attrs = None
+ for n in names:
+ realname = n.strip()
+ if n.endswith('_clist'):
+ joinsymbol = ', '
+ realname = realname[:-6] + '_list'
+ elif n.endswith('_elist'):
+ joinsymbol = ''
+ realname = realname[:-6] + '_list'
+ if hasattr(self, realname):
+ attr = getattr(self, realname)
+ elif realname.startswith('['):
+ attr = eval(realname)
+ else:
+ self.warning('Undefined %r attribute: %r' % (self.__class__.__name__, realname))
+ continue
+ if attrs is None:
+ attrs = attr
+ else:
+ attrs += attr
+ if isinstance(attrs, list):
+ attrs = joinsymbol.join(attrs)
+ d[name] = str(attrs).replace('\n','\n'+tab)
+ return template % d
+
+class PythonWrapperModule(WrapperBase):
+
+ main_template = '''\
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+#include "Python.h"
+
+#define PY_ARRAY_UNIQUE_SYMBOL PyArray_API
+#include "numpy/arrayobject.h"
+
+%(include_list)s
+%(cppmacro_list)s
+%(typedef_list)s
+%(objdecl_list)s
+%(extern_list)s
+%(c_function_list)s
+%(capi_function_list)s
+static PyObject *f2py_module;
+static PyMethodDef f2py_module_methods[] = {
+ %(module_method_list)s
+ {NULL,NULL,0,NULL}
+};
+PyMODINIT_FUNC init%(modulename)s(void) {
+ f2py_module = Py_InitModule("%(modulename)s", f2py_module_methods);
+ %(initialize_interface_list)s
+ if (PyErr_Occurred()) {
+ PyErr_SetString(PyExc_ImportError, "can\'t initialize module %(modulename)s");
+ return;
+ }
+}
+#ifdef __cplusplus
+}
+#endif
+'''
+
+ main_fortran_template = '''\
+%(fortran_code_list)s
+'''
+ def __init__(self, modulename):
+ WrapperBase.__init__(self)
+ self.modulename = modulename
+ self.include_list = []
+ self.typedef_list = []
+ self.cppmacro_list = []
+ self.objdecl_list = []
+ self.c_function_list = []
+ self.extern_list = []
+ self.capi_function_list = []
+ self.module_method_list = []
+ self.initialize_interface_list = []
+ self.fortran_code_list = []
+
+ self.defined_types = []
+ self.defined_macros = []
+ self.defined_c_functions = []
+ self.defined_typedefs = []
+ return
+
+ def add(self, block):
+ if isinstance(block, BeginSource):
+ for name, subblock in block.a.external_subprogram.items():
+ self.add(subblock)
+ elif isinstance(block, (Subroutine, Function)):
+ self.info('Generating interface for %s' % (block.name))
+ f = PythonCAPIFunction(self, block)
+ f.fill()
+ else:
+ raise NotImplementedError,`block.__class__.__name__`
+ return
+
+ def c_code(self):
+ return self.apply_attributes(self.main_template)
+ def fortran_code(self):
+ return self.apply_attributes(self.main_fortran_template)
+
+ def add_c_function(self, name):
+ if name not in self.defined_c_functions:
+ body = self.get_resource_content(name,'.c')
+ if body is None:
+ self.warning('Failed to get C function %r content.' % (name))
+ return
+ for d in self.get_dependencies(body):
+ if d.endswith('.cpp'):
+ self.add_cppmacro(d[:-4])
+ elif d.endswith('.c'):
+ self.add_c_function(d[:-2])
+ else:
+ self.warning('Unknown dependence: %r.' % (d))
+ self.defined_c_functions.append(name)
+ self.c_function_list.append(body)
+ return
+
+ def add_cppmacro(self, name):
+ if name not in self.defined_macros:
+ body = self.get_resource_content(name,'.cpp')
+ if body is None:
+ self.warning('Failed to get CPP macro %r content.' % (name))
+ return
+ for d in self.get_dependencies(body):
+ if d.endswith('.cpp'):
+ self.add_cppmacro(d[:-4])
+ elif d.endswith('.c'):
+ self.add_c_function(d[:-2])
+ else:
+ self.warning('Unknown dependence: %r.' % (d))
+ self.defined_macros.append(name)
+ self.cppmacro_list.append(body)
+ return
+
+ def add_type(self, typedecl):
+ typewrap = TypeDecl(self, typedecl)
+ typename = typewrap.typename
+ if typename not in self.defined_types:
+ self.defined_types.append(typename)
+ typewrap.fill()
+ return typename
+
+ def add_typedef(self, name, code):
+ if name not in self.defined_typedefs:
+ self.typedef_list.append(code)
+ self.defined_types.append(name)
+ return
+
+ def add_include(self, include):
+ if include not in self.include_list:
+ self.include_list.append(include)
+ return
+
+ def add_subroutine(self, block):
+ f = PythonCAPIFunction(self, block)
+ f.fill()
+ return
+
+ def generate_pyobj_to_ctype_c(self, ctype):
+ if ctype.startswith('npy_int'):
+ ctype_bits = int(ctype[7:])
+ return '''
+/* depends: pyobj_to_long.c, pyobj_to_npy_longlong.c */
+#if NPY_BITSOF_LONG == %(ctype_bits)s
+#define pyobj_to_%(ctype)s pyobj_to_long
+#else
+#if NPY_BITSOF_LONG > %(ctype_bits)s
+static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
+ long tmp;
+ if (pyobj_to_long(obj,&tmp)) {
+ *value = (%(ctype)s)tmp;
+ return 1;
+ }
+ return 0;
+}
+#else
+static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
+ npy_longlong tmp;
+ if (pyobj_to_npy_longlong(obj,&tmp)) {
+ *value = (%(ctype)s)tmp;
+ return 1;
+ }
+ return 0;
+}
+#endif
+#endif
+''' % (locals())
+ elif ctype.startswith('npy_float'):
+ ctype_bits = int(ctype[9:])
+ return '''
+/* depends: pyobj_to_double.c */
+#if NPY_BITSOF_DOUBLE == %(ctype_bits)s
+#define pyobj_to_%(ctype)s pyobj_to_double
+#else
+#if NPY_BITSOF_DOUBLE > %(ctype_bits)s
+static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
+ double tmp;
+ if (pyobj_to_double(obj,&tmp)) {
+ *value = (%(ctype)s)tmp;
+ return 1;
+ }
+ return 0;
+}
+#else
+#error, "NOTIMPLEMENTED pyobj_to_%(ctype)s"
+#endif
+#endif
+''' % (locals())
+ elif ctype.startswith('npy_complex'):
+ ctype_bits = int(ctype[11:])
+ cfloat_bits = ctype_bits/2
+ return '''
+/* depends: pyobj_to_Py_complex.c */
+#if NPY_BITSOF_DOUBLE >= %(cfloat_bits)s
+static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
+ Py_complex c;
+ if (pyobj_to_Py_complex(obj,&c)) {
+ (*value).real = (npy_float%(cfloat_bits)s)c.real;
+ (*value).imag = (npy_float%(cfloat_bits)s)c.imag;
+ return 1;
+ }
+ return 0;
+}
+#else
+#error, "NOTIMPLEMENTED pyobj_to_%(ctype)s"
+#endif
+''' % (locals())
+ elif ctype.startswith('f2py_string'):
+ ctype_bits = int(ctype[11:])
+ ctype_bytes = ctype_bits / CHAR_BIT
+ self.add_typedef('f2py_string','typedef char * f2py_string;')
+ self.add_typedef(ctype,'typedef struct { char data[%s]; } %s;' % (ctype_bytes,ctype))
+ self.add_include('#include <string.h>')
+ return '''
+/* depends: pyobj_to_string_len.c */
+static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) {
+ return pyobj_to_string_len(obj, (f2py_string*)value, %(ctype_bytes)s);
+}
+''' % (locals())
+
+class PythonCAPIFunction(WrapperBase):
+ capi_function_template = '''
+static char f2py_doc_%(function_name)s[] = "%(function_doc)s";
+static PyObject* f2py_%(function_name)s(PyObject *capi_self, PyObject *capi_args, PyObject *capi_keywds) {
+ PyObject * volatile capi_buildvalue = NULL;
+ volatile int f2py_success = 1;
+ %(decl_list)s
+ static char *capi_kwlist[] = {%(keyword_clist+optkw_clist+extrakw_clist+["NULL"])s};
+ if (!PyArg_ParseTupleAndKeywords(capi_args,capi_keywds,
+ "%(pyarg_format_elist)s",
+ %(["capi_kwlist"]+pyarg_obj_clist)s))
+ return NULL;
+ %(frompyobj_list)s
+ %(call_list)s
+ f2py_success = !PyErr_Occurred();
+ if (f2py_success) {
+ %(pyobjfrom_list)s
+ capi_buildvalue = Py_BuildValue(%(buildvalue_clist)s);
+ %(clean_pyobjfrom_list)s
+ }
+ %(clean_frompyobj_list)s
+ return capi_buildvalue;
+}
+'''
+
+ pymethoddef_template = '''\
+{"%(function_name)s", (PyCFunction)f2py_%(function_name)s, METH_VARARGS | METH_KEYWORDS, f2py_doc_%(function_name)s},\
+'''
+
+ cppmacro_template = '''\
+#define %(function_name)s_f F_FUNC(%(function_name)s,%(FUNCTION_NAME)s)
+'''
+
+ extdef_template = '''\
+extern void %(function_name)s_f();\
+'''
+
+ def __init__(self, parent, block):
+ WrapperBase.__init__(self)
+ self.parent = parent
+ self.block = block
+ self.function_name = block.name
+ self.FUNCTION_NAME = self.function_name.upper()
+ self.function_doc = ''
+ self.args_list = block.args
+ self.decl_list = []
+ self.keyword_list = []
+ self.optkw_list = []
+ self.extrakw_list = []
+ self.frompyobj_list = []
+ self.call_list = []
+ self.pyobjfrom_list = []
+ self.buildvalue_list = []
+ self.clean_pyobjfrom_list = []
+ self.clean_frompyobj_list = []
+ self.pyarg_format_list = []
+ self.pyarg_obj_list = []
+ return
+
+ def fill(self):
+ for argname in self.args_list:
+ var = self.block.a.variables[argname]
+ argwrap = ArgumentWrapper(self, var)
+ argwrap.fill()
+ self.call_list.append('%s_f(%s);' % (self.function_name, ', '.join(['&'+a for a in self.args_list])))
+ if not self.buildvalue_list:
+ self.buildvalue_list.append('""')
+ self.parent.capi_function_list.append(self.apply_attributes(self.capi_function_template))
+ self.parent.module_method_list.append(self.apply_attributes(self.pymethoddef_template))
+ self.parent.extern_list.append(self.apply_attributes(self.extdef_template))
+ self.parent.add_cppmacro('F_FUNC')
+ self.parent.cppmacro_list.append(self.apply_attributes(self.cppmacro_template))
+ return
+
+class ArgumentWrapper(WrapperBase):
+
+ objdecl_template = '%(ctype)s %(name)s;'
+ pyarg_obj_template = '\npyobj_to_%(ctype)s, &%(name)s'
+
+ def __init__(self, parent, variable):
+ WrapperBase.__init__(self)
+ self.parent = parent
+ self.grand_parent = parent.parent
+ self.variable = variable
+ self.typedecl = variable.typedecl
+ self.name = variable.name
+ self.ctype = self.typedecl.get_c_type()
+
+ def fill(self):
+ typename = self.grand_parent.add_type(self.typedecl)
+ self.parent.decl_list.append(self.apply_attributes(self.objdecl_template))
+
+ self.parent.pyarg_obj_list.append(self.apply_attributes(self.pyarg_obj_template))
+ self.parent.pyarg_format_list.append('O&')
+ self.parent.keyword_list.append('"%s"' % (self.name))
+
+ self.grand_parent.add_c_function('pyobj_to_%s' % (self.ctype))
+ return
+
+class TypeDecl(WrapperBase):
+ cppmacro_template = '''\
+#define initialize_%(typename)s_interface F_FUNC(initialize_%(typename)s_interface_f,INITIALIZE_%(TYPENAME)s_INTERFACE_F)\
+'''
+ typedef_template = '''\
+typedef struct { char data[%(byte_size)s] } %(ctype)s;
+typedef %(ctype)s (*create_%(typename)s_functype)(void);
+typedef void (*initialize_%(typename)s_interface_functype)(create_%(typename)s_functype);\
+'''
+ objdecl_template = '''\
+static create_%(typename)s_functype create_%(typename)s_object;
+'''
+ funcdef_template = '''\
+static void initialize_%(typename)s_interface_c(create_%(typename)s_functype create_object_f) {
+ create_%(typename)s_object = create_object_f;
+}
+'''
+ extdef_template = '''\
+extern void initialize_%(typename)s_interface(initialize_%(typename)s_interface_functype);\
+'''
+ initcall_template = '''\
+initialize_%(typename)s_interface(initialize_%(typename)s_interface_c);\
+'''
+ fortran_code_template = '''\
+ function create_%(typename)s_object_f() result (obj)
+ %(typedecl)s obj
+! %(initexpr)s
+ end
+ subroutine initialize_%(typename)s_interface_f(init_c)
+ external create_%(typename)s_object_f
+ call init_c(create_%(typename)s_object_f)
+ end
+'''
+
+ def __init__(self, parent, typedecl):
+ WrapperBase.__init__(self)
+ self.parent = parent
+ self.typedecl = typedecl.astypedecl()
+ self.ctype = self.typedecl.get_c_type()
+ self.byte_size = self.typedecl.get_byte_size()
+ self.typename = self.typedecl.name.lower()
+ self.TYPENAME = self.typedecl.name.upper()
+ self.initexpr = self.typedecl.assign_expression('obj',self.typedecl.get_zero_value())
+ return
+
+ def fill(self):
+ ctype =self.typedecl.get_c_type()
+ if ctype.startswith('npy_'):
+ pass
+ elif ctype.startswith('f2py_string'):
+ pass
+ else:
+ self.parent.typedef_list.append(self.apply_attributes(self.typedef_template))
+ self.parent.objdecl_list.append(self.apply_attributes(self.objdecl_template))
+ self.parent.c_function_list.append(self.apply_attributes(self.funcdef_template))
+ self.parent.extern_list.append(self.apply_attributes(self.extdef_template))
+ self.parent.initialize_interface_list.append(self.apply_attributes(self.initcall_template))
+ self.parent.fortran_code_list.append(self.apply_attributes(self.fortran_code_template))
+ self.parent.add_cppmacro('F_FUNC')
+ self.parent.cppmacro_list.append(self.apply_attributes(self.cppmacro_template))
+ return
+
+
+
+
+if __name__ == '__main__':
+ from utils import str2stmt, get_char_bit
+
+ stmt = str2stmt("""
+ module rat
+ integer :: i
+ type rational
+ integer n
+ integer*8 d
+ end type rational
+ end module rat
+ subroutine foo(a)
+ use rat
+ type(rational) a
+ end
+ """)
+ #stmt = stmt.content[-1].content[1]
+ #print stmt
+ #wrapgen = TypeWrapper(stmt)
+ #print wrapgen.fortran_code()
+ #print wrapgen.c_code()
+
+ foo_code = """! -*- f90 -*-
+ module rat
+ type rational
+ integer d,n
+ end type rational
+ end module rat
+ subroutine foo(a,b)
+ use rat
+ integer a
+ character*5 b
+ type(rational) c
+ print*,'a=',a,b,c
+ end
+"""
+
+ wm = PythonWrapperModule('foo')
+ wm.add(str2stmt(foo_code))
+ #wm.add_fortran_code(foo_code)
+ #wm.add_subroutine(str2stmt(foo_code))
+ #print wm.c_code()
+
+ c_code = wm.c_code()
+ f_code = wm.fortran_code()
+
+ f = open('foomodule.c','w')
+ f.write(c_code)
+ f.close()
+ f = open('foo.f','w')
+ f.write(foo_code)
+ f.close()
+ f = open('foo_wrap.f','w')
+ f.write(f_code)
+ f.close()
+ f = open('foo_setup.py','w')
+ f.write('''\
+def configuration(parent_package='',top_path=None):
+ from numpy.distutils.misc_util import Configuration
+ config = Configuration('foopack',parent_package,top_path)
+ config.add_library('foolib',
+ sources = ['foo.f','foo_wrap.f'])
+ config.add_extension('foo',
+ sources=['foomodule.c'],
+ libraries = ['foolib'],
+ )
+ return config
+if __name__ == '__main__':
+ from numpy.distutils.core import setup
+ setup(configuration=configuration)
+''')
+ f.close()
+ print get_char_bit()
+ os.system('python foo_setup.py config_fc --fcompiler=gnu95 build build_ext --inplace')
+ import foo
+ print dir(foo)
+ foo.foo(2,"abcdefg")
Added: trunk/numpy/f2py/lib/research/pointers/pointer_size.c
===================================================================
--- trunk/numpy/f2py/lib/research/pointers/pointer_size.c 2006-09-16 02:08:59 UTC (rev 3169)
+++ trunk/numpy/f2py/lib/research/pointers/pointer_size.c 2006-09-16 05:56:18 UTC (rev 3170)
@@ -0,0 +1,30 @@
+#include <stdio.h>
+
+#define settypeinfo settypeinfo_
+
+void settypeinfo(int*);
+
+int main(int argc, char* argv[])
+{
+ int i;
+ int a[512];
+ for(i=0;i<512;i++) a[i] = 0;
+
+ settypeinfo(a);
+
+ if (a[0] != 333331) {
+ printf("FAILED, start flag is incorrect = %d\n", a[0]);
+ return 1;
+ }
+
+ for (i = 0; i < 512; i++) {
+ if (a[i] == 333332) {
+ printf("SUCCESSFULLY found Fortran pointer length of %d bytes\n",
+ (i-1)*sizeof(int));
+ return 0;
+ }
+ }
+
+ printf("FAILED to find end flag\n");
+ return 1;
+}
Added: trunk/numpy/f2py/lib/research/pointers/settypeinfo.f90
===================================================================
--- trunk/numpy/f2py/lib/research/pointers/settypeinfo.f90 2006-09-16 02:08:59 UTC (rev 3169)
+++ trunk/numpy/f2py/lib/research/pointers/settypeinfo.f90 2006-09-16 05:56:18 UTC (rev 3170)
@@ -0,0 +1,13 @@
+! Author: Pearu Peterson
+! Got idea from https://www.cca-forum.org/pipermail/cca-fortran/2003-February/000123.html
+
+subroutine settypeinfo(wrapper)
+ type data_wrapper
+ integer :: ibegin
+ character*20 :: p_data*10
+ integer :: iend
+ end type data_wrapper
+ type(data_wrapper), intent(out) :: wrapper
+ wrapper%ibegin = 333331
+ wrapper%iend = 333332
+end subroutine settypeinfo
Added: trunk/numpy/f2py/lib/src/F_FUNC.cpp
===================================================================
--- trunk/numpy/f2py/lib/src/F_FUNC.cpp 2006-09-16 02:08:59 UTC (rev 3169)
+++ trunk/numpy/f2py/lib/src/F_FUNC.cpp 2006-09-16 05:56:18 UTC (rev 3170)
@@ -0,0 +1,34 @@
+#if defined(PREPEND_FORTRAN)
+#if defined(NO_APPEND_FORTRAN)
+#if defined(UPPERCASE_FORTRAN)
+#define F_FUNC(f,F) _##F
+#else
+#define F_FUNC(f,F) _##f
+#endif
+#else
+#if defined(UPPERCASE_FORTRAN)
+#define F_FUNC(f,F) _##F##_
+#else
+#define F_FUNC(f,F) _##f##_
+#endif
+#endif
+#else
+#if defined(NO_APPEND_FORTRAN)
+#if defined(UPPERCASE_FORTRAN)
+#define F_FUNC(f,F) F
+#else
+#define F_FUNC(f,F) f
+#endif
+#else
+#if defined(UPPERCASE_FORTRAN)
+#define F_FUNC(f,F) F##_
+#else
+#define F_FUNC(f,F) f##_
+#endif
+#endif
+#endif
+#if defined(UNDERSCORE_G77)
+#define F_FUNC_US(f,F) F_FUNC(f##_,F##_)
+#else
+#define F_FUNC_US(f,F) F_FUNC(f,F)
+#endif
Added: trunk/numpy/f2py/lib/src/pyobj_to_Py_complex.c
===================================================================
--- trunk/numpy/f2py/lib/src/pyobj_to_Py_complex.c 2006-09-16 02:08:59 UTC (rev 3169)
+++ trunk/numpy/f2py/lib/src/pyobj_to_Py_complex.c 2006-09-16 05:56:18 UTC (rev 3170)
@@ -0,0 +1,39 @@
+int pyobj_to_Py_complex(PyObject* obj, Py_complex* value) {
+ if (PyComplex_Check(obj)) {
+ *value =PyComplex_AsCComplex(obj);
+ return 1;
+ }
+ /* Python does not provide PyNumber_Complex function :-( */
+ (*value).imag=0.0;
+ if (PyFloat_Check(obj)) {
+#ifdef __sgi
+ (*value).real = PyFloat_AsDouble(obj);
+ return (!PyErr_Occurred());
+#else
+ (*value).real = PyFloat_AS_DOUBLE(obj);
+ return 1;
+#endif
+ }
+ if (PyInt_Check(obj)) {
+ (*value).real = (double)PyInt_AS_LONG(obj);
+ return 1;
+ }
+ if (PyLong_Check(obj)) {
+ (*value).real = PyLong_AsDouble(obj);
+ return (!PyErr_Occurred());
+ }
+ if (PySequence_Check(obj) && (!PyString_Check(obj))) {
+ PyObject *tmp = PySequence_GetItem(obj,0);
+ if (tmp) {
+ if (pyobj_to_Py_complex(tmp,value)) {
+ Py_DECREF(tmp);
+ return 1;
+ }
+ Py_DECREF(tmp);
+ }
+ }
+ if (!PyErr_Occurred()) {
+ PyErr_SetString(PyExc_TypeError, "Failed to convert python object to C Py_complex.");
+ }
+ return 0;
+}
Added: trunk/numpy/f2py/lib/src/pyobj_to_double.c
===================================================================
--- trunk/numpy/f2py/lib/src/pyobj_to_double.c 2006-09-16 02:08:59 UTC (rev 3169)
+++ trunk/numpy/f2py/lib/src/pyobj_to_double.c 2006-09-16 05:56:18 UTC (rev 3170)
@@ -0,0 +1,39 @@
+int pyobj_to_double(PyObject* obj, double* value) {
+ PyObject* tmp = NULL;
+ if (PyFloat_Check(obj)) {
+#ifdef __sgi
+ *value = PyFloat_AsDouble(obj);
+ return (!PyErr_Occurred());
+#else
+ *value = PyFloat_AS_DOUBLE(obj);
+ return 1;
+#endif
+ }
+ tmp = PyNumber_Float(obj);
+ if (tmp) {
+#ifdef __sgi
+ *value = PyFloat_AsDouble(tmp);
+ Py_DECREF(tmp);
+ return (!PyErr_Occurred());
+#else
+ *value = PyFloat_AS_DOUBLE(tmp);
+ Py_DECREF(tmp);
+ return 1;
+#endif
+ }
+ if (PyComplex_Check(obj))
+ tmp = PyObject_GetAttrString(obj,"real");
+ else if (PyString_Check(obj))
+ /*pass*/;
+ else if (PySequence_Check(obj))
+ tmp = PySequence_GetItem(obj,0);
+ if (tmp) {
+ PyErr_Clear();
+ if (pyobj_to_double(tmp, value)) {Py_DECREF(tmp); return 1;}
+ Py_DECREF(tmp);
+ }
+ if (!PyErr_Occurred()) {
+ PyErr_SetString(PyExc_TypeError, "Failed to convert python object to C double.");
+ }
+ return 0;
+}
Added: trunk/numpy/f2py/lib/src/pyobj_to_long.c
===================================================================
--- trunk/numpy/f2py/lib/src/pyobj_to_long.c 2006-09-16 02:08:59 UTC (rev 3169)
+++ trunk/numpy/f2py/lib/src/pyobj_to_long.c 2006-09-16 05:56:18 UTC (rev 3170)
@@ -0,0 +1,31 @@
+int pyobj_to_long(PyObject *obj, long* value) {
+ PyObject* tmp = NULL;
+ if (PyInt_Check(obj)) {
+ *value = PyInt_AS_LONG(obj);
+ return 1;
+ }
+ tmp = PyNumber_Int(obj);
+ if (tmp) {
+ *value = PyInt_AS_LONG(tmp);
+ Py_DECREF(tmp);
+ return 1;
+ }
+ if (PyComplex_Check(obj))
+ tmp = PyObject_GetAttrString(obj,"real");
+ else if (PyString_Check(obj))
+ /*pass*/;
+ else if (PySequence_Check(obj))
+ tmp = PySequence_GetItem(obj,0);
+ if (tmp) {
+ PyErr_Clear();
+ if (pyobj_to_long(tmp, value)) {
+ Py_DECREF(tmp);
+ return 1;
+ }
+ Py_DECREF(tmp);
+ }
+ if (!PyErr_Occurred()) {
+ PyErr_SetString(PyExc_TypeError, "Failed to convert python object to C long.");
+ }
+ return 0;
+}
Added: trunk/numpy/f2py/lib/src/pyobj_to_npy_longlong.c
===================================================================
--- trunk/numpy/f2py/lib/src/pyobj_to_npy_longlong.c 2006-09-16 02:08:59 UTC (rev 3169)
+++ trunk/numpy/f2py/lib/src/pyobj_to_npy_longlong.c 2006-09-16 05:56:18 UTC (rev 3170)
@@ -0,0 +1,36 @@
+int pyobj_to_npy_longlong(PyObject *obj, npy_longlong* value) {
+ PyObject* tmp = NULL;
+ if (PyLong_Check(obj)) {
+ *value = PyLong_AsLongLong(obj);
+ return (!PyErr_Occurred());
+ }
+ if (PyInt_Check(obj)) {
+ *value = (npy_longlong)PyInt_AS_LONG(obj);
+ return 1;
+ }
+ tmp = PyNumber_Long(obj);
+ if (tmp) {
+ *value = PyLong_AsLongLong(tmp);
+ Py_DECREF(tmp);
+ return (!PyErr_Occurred());
+ }
+ if (PyComplex_Check(obj))
+ tmp = PyObject_GetAttrString(obj,"real");
+ else if (PyString_Check(obj))
+ /*pass*/;
+ else if (PySequence_Check(obj))
+ tmp = PySequence_GetItem(obj,0);
+ if (tmp) {
+ PyErr_Clear();
+ if (pyobj_to_npy_longlong(tmp, value)) {
+ Py_DECREF(tmp);
+ return 1;
+ }
+ Py_DECREF(tmp);
+ }
+ if (!PyErr_Occurred()) {
+ PyErr_SetString(PyExc_TypeError, "Failed to convert python object to C npy_longlong.");
+ }
+ return 0;
+}
+
Added: trunk/numpy/f2py/lib/src/pyobj_to_string_len.c
===================================================================
--- trunk/numpy/f2py/lib/src/pyobj_to_string_len.c 2006-09-16 02:08:59 UTC (rev 3169)
+++ trunk/numpy/f2py/lib/src/pyobj_to_string_len.c 2006-09-16 05:56:18 UTC (rev 3170)
@@ -0,0 +1,10 @@
+int pyobj_to_string_len(PyObject* obj, f2py_string* value, size_t length) {
+ if (PyString_Check(obj)) {
+ if (strncpy((char*)value,PyString_AS_STRING(obj), length))
+ return 1;
+ }
+ if (!PyErr_Occurred()) {
+ PyErr_SetString(PyExc_TypeError, "Failed to convert python object to C f2py_string.");
+ }
+ return 0;
+}
Modified: trunk/numpy/f2py/lib/statements.py
===================================================================
--- trunk/numpy/f2py/lib/statements.py 2006-09-16 02:08:59 UTC (rev 3169)
+++ trunk/numpy/f2py/lib/statements.py 2006-09-16 05:56:18 UTC (rev 3170)
@@ -52,6 +52,7 @@
match = re.compile(r'\w[^=]*\s*=\>?').match
item_re = re.compile(r'(?P<variable>\w[^=]*)\s*(?P<sign>=\>?)\s*(?P<expr>.*)\Z',re.I).match
+ _repr_attr_names = ['variable','sign','expr'] + Statement._repr_attr_names
def process_item(self):
m = self.item_re(self.item.get_line())
@@ -525,6 +526,7 @@
def analyze(self):
module_procedures = self.parent.a.module_procedures
module_procedures.extend(self.items)
+ # XXX: add names to parent_provides
return
class Access(Statement):
@@ -560,7 +562,7 @@
var = self.get_variable(name)
var.update(clsname)
else:
- self.parent.a.attributes.append(clsname)
+ self.parent.update_attributes(clsname)
return
class Public(Access):
@@ -847,8 +849,11 @@
return tab + s
def analyze(self):
+ use = self.parent.a.use
+ if use.has_key(self.name):
+ return
+
modules = self.top.a.module
-
if not modules.has_key(self.name):
fn = None
for d in self.reader.include_dirs:
@@ -867,9 +872,10 @@
modules.update(parser.block.a.module)
if not modules.has_key(self.name):
- self.warning('no information about the use module %r' % (self.name))
+ self.warning('no information about the module %r in use statement' % (self.name))
return
+ module = modules[self.name]
use_provides = self.parent.a.use_provides
@@ -1111,7 +1117,7 @@
return
def __str__(self): return self.get_indent_tab() + 'SEQUENCE'
def analyze(self):
- self.parent.a.attributes.append('SEQUENCE')
+ self.parent.update_attributes('SEQUENCE')
return
class External(StatementWithNamelist):
@@ -1218,6 +1224,7 @@
var = self.get_variable(name)
if shape is not None:
var.set_bounds(shape)
+ # XXX: add name,var to parent_provides
return
class Optional(StatementWithNamelist):
Modified: trunk/numpy/f2py/lib/typedecl_statements.py
===================================================================
--- trunk/numpy/f2py/lib/typedecl_statements.py 2006-09-16 02:08:59 UTC (rev 3169)
+++ trunk/numpy/f2py/lib/typedecl_statements.py 2006-09-16 05:56:18 UTC (rev 3170)
@@ -1,9 +1,14 @@
+__all__ = ['Integer', 'Real', 'DoublePrecision', 'Complex', 'DoubleComplex',
+ 'Character', 'Logical', 'Byte', 'TypeStmt','Class',
+ 'intrinsic_type_spec', 'declaration_type_spec',
+ 'Implicit']
+
import re
import string
from base_classes import Statement, BeginStatement, EndStatement,\
AttributeHolder, Variable
-from utils import split_comma, AnalyzeError, name_re, is_entity_decl
+from utils import split_comma, AnalyzeError, name_re, is_entity_decl, is_name, CHAR_BIT
# Intrinsic type specification statements
@@ -27,6 +32,10 @@
| LOGICAL [<kind-selector>]
<kind-selector> = ( [ KIND = ] <scalar-int-initialization-expr> )
+ EXTENSION:
+ <kind-selector> = ( [ KIND = ] <scalar-int-initialization-expr> )
+ | * <length>
+
<char-selector> = <length-selector>
| ( LEN = <type-param-value>, KIND = <scalar-int-initialization-expr> )
| ( <type-param-value>, [ KIND = ] <scalar-int-initialization-expr> )
@@ -61,6 +70,7 @@
<digit-string> = <digit> [ <digit> ]..
<kind-param> = <digit-string> | <scalar-int-constant-name>
"""
+ _repr_attr_names = ['selector','attrspec','entity_decls'] + Statement._repr_attr_names
def process_item(self):
item = self.item
@@ -146,13 +156,19 @@
assert self.parent.typedecl is None,`self.parent.typedecl`
self.parent.typedecl = self
self.ignore = True
+ if isinstance(self, Type):
+ self.name = self.selector[1].lower()
+ assert is_name(self.name),`self.name`
+ else:
+ self.name = clsname
return
def _parse_kind_selector(self, selector):
if not selector:
- return ''
+ return '',''
+ length,kind = '',''
if selector.startswith('*'):
- kind = selector[1:].lstrip()
+ length = selector[1:].lstrip()
else:
assert selector[0]+selector[-1]=='()',`selector`
l = selector[1:-1].strip()
@@ -162,7 +178,7 @@
kind = l[1:].lstrip()
else:
kind = l
- return kind
+ return length,kind
def _parse_char_selector(self, selector):
if not selector:
@@ -213,8 +229,8 @@
def tostr(self):
clsname = self.__class__.__name__.upper()
s = ''
+ length, kind = self.selector
if isinstance(self, Character):
- length, kind = self.selector
if length and kind:
s += '(LEN=%s, KIND=%s)' % (length,kind)
elif length:
@@ -222,9 +238,14 @@
elif kind:
s += '(KIND=%s)' % (kind)
else:
- kind = self.selector
- if kind:
- s += '(KIND=%s)' % (kind)
+ if isinstance(self, Type):
+ s += '(%s)' % (kind)
+ else:
+ if length:
+ s += '*%s' % (length)
+ if kind:
+ s += '(KIND=%s)' % (kind)
+
return clsname + s
def __str__(self):
@@ -244,7 +265,9 @@
return self.selector==other.selector
def astypedecl(self):
- return self.__class__(self.parent, self.item.copy(self.tostr()))
+ if self.entity_decls or self.attrspec:
+ return self.__class__(self.parent, self.item.copy(self.tostr()))
+ return self
def analyze(self):
if not self.entity_decls:
@@ -253,11 +276,8 @@
typedecl = self.astypedecl()
for item in self.entity_decls:
name, array_spec, char_length, value = self._parse_entity(item)
- if not variables.has_key(name):
- variables[name] = var = Variable(self, name)
- else:
- var = variables[name]
- var.add_parent(self)
+ var = self.parent.get_variable(name)
+ var.add_parent(self)
if char_length:
var.set_length(char_length)
else:
@@ -267,6 +287,7 @@
var.set_bounds(array_spec)
if value:
var.set_init(value)
+ var.analyze()
return
def _parse_entity(self, line):
@@ -296,34 +317,170 @@
value = item.apply_map(line[1:].lstrip())
return name, array_spec, char_length, value
+ def get_zero_value(self):
+ raise NotImplementedError,`self.__class__.__name__`
+
+ def assign_expression(self, name, value):
+ return '%s = %s' % (name, value)
+
+ def get_kind(self):
+ return self.selector[1] or self.default_kind
+
+ def get_length(self):
+ return self.selector[0] or 1
+
+ def get_bit_size(self):
+ return CHAR_BIT * int(self.get_kind())
+
+ def get_byte_size(self):
+ return self.get_bit_size() / CHAR_BIT
+
+ def is_intrinsic(self): return not isinstance(self,(Type,Class))
+ def is_derived(self): return isinstance(self,Type)
+
+ def is_numeric(self): return isinstance(self,(Integer,Real, DoublePrecision,Complex,DoubleComplex,Byte))
+ def is_nonnumeric(self): return isinstance(self,(Character,Logical))
+
+
class Integer(TypeDeclarationStatement):
match = re.compile(r'integer\b',re.I).match
+ default_kind = 4
+ def get_c_type(self):
+ return 'npy_int%s' % (self.get_bit_size())
+
+ def get_zero_value(self):
+ kind = self.get_kind()
+ if kind==self.default_kind: return '0'
+ return '0_%s' % (kind)
+
class Real(TypeDeclarationStatement):
match = re.compile(r'real\b',re.I).match
+ default_kind = 4
+ def get_c_type(self):
+ return 'npy_float%s' % (self.get_bit_size())
+
+ def get_zero_value(self):
+ kind = self.get_kind()
+ if kind==self.default_kind: return '0.0'
+ return '0_%s' % (kind)
+
class DoublePrecision(TypeDeclarationStatement):
match = re.compile(r'double\s*precision\b',re.I).match
+ default_kind = 8
+
+ def get_zero_value(self):
+ return '0.0D0'
+ def get_c_type(self):
+ return 'npy_float%s' % (self.get_bit_size())
+
class Complex(TypeDeclarationStatement):
match = re.compile(r'complex\b',re.I).match
+ default_kind = 4
+ def get_kind(self):
+ length, kind = self.selector
+ if kind:
+ return kind
+ if length:
+ return int(length)/2
+ return self.default_kind
+
+ def get_length(self):
+ return 2 * int(self.get_kind())
+
+ def get_bit_size(self):
+ return CHAR_BIT * self.get_length()
+
+ def get_zero_value(self):
+ kind = self.get_kind()
+ if kind==self.default_kind: return '(0.0, 0.0)'
+ return '(0.0_%s, 0.0_%s)' % (kind, kind)
+
+ def get_c_type(self):
+ return 'npy_complex%s' % (self.get_bit_size())
+
class DoubleComplex(TypeDeclarationStatement):
# not in standard
match = re.compile(r'double\s*complex\b',re.I).match
+ default_kind = 8
+ def get_kind(self): return self.default_kind
+ def get_length(self): return 2 * self.get_kind()
+ def get_bit_size(self):
+ return CHAR_BIT * self.get_length()
+
+ def get_zero_value(self):
+ return '(0.0D0,0.0D0)'
+
+ def get_c_type(self):
+ return 'npy_complex%s' % (self.get_bit_size())
+
class Logical(TypeDeclarationStatement):
match = re.compile(r'logical\b',re.I).match
+ default_kind = 4
+ def get_zero_value(self):
+ return ".FALSE."
+
+ def get_c_type(self):
+ return 'npy_int%s' % (self.get_bit_size())
+
class Character(TypeDeclarationStatement):
match = re.compile(r'character\b',re.I).match
+ default_kind = 1
+ def get_bit_size(self):
+ return CHAR_BIT * int(self.get_length()) * int(self.get_kind())
+
+ def get_c_type(self):
+ return 'f2py_string%s' % (self.get_bit_size())
+
+ def get_zero_value(self):
+ return "''"
+
class Byte(TypeDeclarationStatement):
# not in standard
match = re.compile(r'byte\b',re.I).match
+ default_kind = 1
+ def get_zero_value(self):
+ return '0'
+
+ def get_c_type(self):
+ return 'npy_int%s' % (self.get_bit_size())
+
class Type(TypeDeclarationStatement):
match = re.compile(r'type\s*\(', re.I).match
+
+ def get_zero_value(self):
+ kind = self.selector
+ assert is_name(kind),`kind`
+ type_decl = self.get_type_decl(kind)
+ component_names = type_decl.a.component_names
+ components = type_decl.a.components
+ l = []
+ for name in component_names:
+ var = components[name]
+ l.append(var.typedecl.get_zero_value())
+ return '%s(%s)' % (type_decl.name, ', '.join(l))
+
+ def get_kind(self):
+ # See 4.5.2, page 48
+ raise NotImplementedError,`self.__class__.__name__`
+
+ def get_bit_size(self):
+ type_decl = self.get_type_decl(self.name)
+ s = 0
+ for name,var in type_decl.a.components.items():
+ s += var.get_bit_size()
+ return s
+
+ def get_c_type(self):
+ return 'f2py_type_%s_%s' % (self.name, self.get_bit_size())
+
TypeStmt = Type
class Class(TypeDeclarationStatement):
Modified: trunk/numpy/f2py/lib/utils.py
===================================================================
--- trunk/numpy/f2py/lib/utils.py 2006-09-16 02:08:59 UTC (rev 3169)
+++ trunk/numpy/f2py/lib/utils.py 2006-09-16 05:56:18 UTC (rev 3170)
@@ -74,6 +74,8 @@
return name, line[i+1:].lstrip()
def filter_stmts(content, classes):
+ """ Pop and return classes instances from content.
+ """
stmts = []
indices = []
for i in range(len(content)):
@@ -123,3 +125,30 @@
return fn
f.close()
return
+
+def str2stmt(string, isfree=True, isstrict=False):
+ """ Convert Fortran code to Statement tree.
+ """
+ from readfortran import Line, FortranStringReader
+ from parsefortran import FortranParser
+ reader = FortranStringReader(string, isfree, isstrict)
+ parser = FortranParser(reader)
+ parser.parse()
+ parser.analyze()
+ block = parser.block
+ while len(block.content)==1:
+ block = block.content[0]
+ return block
+
+def get_char_bit():
+ import numpy
+ one = numpy.ubyte(1)
+ two = numpy.ubyte(2)
+ n = numpy.ubyte(2)
+ i = 1
+ while n>=two:
+ n <<= one
+ i += 1
+ return i
+
+CHAR_BIT = get_char_bit()
More information about the Numpy-svn
mailing list