diff options
Diffstat (limited to 'numpy/f2py/lib')
32 files changed, 18718 insertions, 0 deletions
diff --git a/numpy/f2py/lib/__init__.py b/numpy/f2py/lib/__init__.py new file mode 100644 index 000000000..c3b40cb76 --- /dev/null +++ b/numpy/f2py/lib/__init__.py @@ -0,0 +1,14 @@ +""" +F2PY G3 --- The third generation of Fortran to Python Interface Generator. + +Use api module for importing public symbols. + +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: Oct 2006 +----- +""" diff --git a/numpy/f2py/lib/api.py b/numpy/f2py/lib/api.py new file mode 100644 index 000000000..0d21da28c --- /dev/null +++ b/numpy/f2py/lib/api.py @@ -0,0 +1,14 @@ +""" +Public API for F2PY G3. + +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: Oct 2006 +----- +""" + +from main import main diff --git a/numpy/f2py/lib/main.py b/numpy/f2py/lib/main.py new file mode 100644 index 000000000..6c2e1415e --- /dev/null +++ b/numpy/f2py/lib/main.py @@ -0,0 +1,534 @@ +""" +Tools for building F2PY generated extension modules. + +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: Oct 2006 +----- +""" + +import os +import re +import sys +import tempfile + +try: + from numpy import __version__ as numpy_version +except ImportError: + numpy_version = 'N/A' + +__all__ = ['main', 'compile'] + +__usage__ = """ +F2PY G3 --- The third generation of Fortran to Python Interface Generator +========================================================================= + +Description +----------- + +f2py program generates a Python C/API file (<modulename>module.c) that +contains wrappers for given Fortran functions and data so that they +can be accessed from Python. With the -c option the corresponding +extension modules are built. + +Options +------- + + --g3-numpy Use numpy.f2py.lib tool, the 3rd generation of F2PY, + with NumPy support. + --2d-numpy Use numpy.f2py tool with NumPy support. [DEFAULT] + --2d-numeric Use f2py2e tool with Numeric support. + --2d-numarray Use f2py2e tool with Numarray support. + + -m <modulename> Name of the module; f2py generates a Python/C API + file <modulename>module.c or extension module <modulename>. + For wrapping Fortran 90 modules, f2py will use Fortran + module names. + --parse Parse Fortran files and print result to stdout. + + +Options effective only with -h +------------------------------ + + -h <filename> Write signatures of the fortran routines to file <filename> + and exit. You can then edit <filename> and use it instead + of <fortran files> for generating extension module source. + If <filename> is stdout or stderr then the signatures are + printed to the corresponding stream. + + --overwrite-signature Overwrite existing signature file. + +Options effective only with -c +------------------------------ + + -c Compile fortran sources and build extension module. + + --build-dir <dirname> All f2py generated files are created in <dirname>. + Default is tempfile.mktemp() and it will be removed after + f2py stops unless <dirname> is specified via --build-dir + option. + +numpy.distutils options effective only with -c +---------------------------------------------- + + --fcompiler=<name> Specify Fortran compiler type by vendor + + + +Extra options effective only with -c +------------------------------------ + + -L/path/to/lib/ -l<libname> + -D<name[=define]> -U<name> + -I/path/to/include/ + <filename>.o <filename>.(so|dynlib|dll) <filename>.a + + Using the following macros may be required with non-gcc Fortran + compilers: + -DPREPEND_FORTRAN -DNO_APPEND_FORTRAN -DUPPERCASE_FORTRAN + -DUNDERSCORE_G77 + + -DF2PY_DEBUG_PYOBJ_TOFROM --- pyobj_(to|from)_<ctype> functions will + print debugging messages to stderr. + +""" + +import re +import shutil +import parser.api +from parser.api import parse, PythonModule, EndStatement, Module, Subroutine, Function,\ + get_reader + +def get_values(sys_argv, prefix='', suffix='', strip_prefix=False, strip_suffix=False): + """ + Return a list of values with pattern + <prefix><value><suffix>. + The corresponding items will be removed from sys_argv. + """ + match = re.compile(prefix + r'.*' + suffix + '\Z').match + ret = [item for item in sys_argv if match(item)] + [sys_argv.remove(item) for item in ret] + if strip_prefix and prefix: + i = len(prefix) + ret = [item[i:] for item in ret] + if strip_suffix and suffix: + i = len(suffix) + ret = [item[:-i] for item in ret] + return ret + +def get_option(sys_argv, option, default_return = None): + """ + Return True if sys_argv has <option>. + If <option> is not in sys_argv, return default_return. + <option> (when present) will be removed from sys_argv. + """ + try: + i = sys_argv.index(option) + except ValueError: + return default_return + del sys_argv[i] + return True + +def get_option_value(sys_argv, option, default_value = None, default_return = None): + """ + Return <value> from + sys_argv = [...,<option>,<value>,...] + list. + If <option> is the last element, return default_value. + If <option> is not in sys_argv, return default_return. + Both <option> and <value> (when present) will be removed from sys_argv. + """ + try: + i = sys_argv.index(option) + except ValueError: + return default_return + if len(sys_argv)-1==i: + del sys_argv[i] + return default_value + value = sys_argv[i+1] + del sys_argv[i+1] + del sys_argv[i] + return value + +def get_signature_output(sys_argv): + return get_option_value(sys_argv,'-h','stdout') + + +def parse_files(sys_argv): + flag = 'file' + file_names = [] + only_names = [] + skip_names = [] + options = [] + for word in sys_argv: + if word=='': pass + elif word=='only:': flag = 'only' + elif word=='skip:': flag = 'skip' + elif word==':': flag = 'file' + elif word.startswith('--'): options.append(word) + else: + {'file': file_names,'only': only_names, 'skip': skip_names}[flag].append(word) + + if options: + sys.stderr.write('Unused options: %s\n' % (', '.join(options))) + for filename in file_names: + if not os.path.isfile(filename): + sys.stderr.write('No or not a file %r. Skipping.\n' % (filename)) + continue + sys.stderr.write('Parsing %r..\n' % (filename)) + reader = parser.api.get_reader(filename) + print parser.api.Fortran2003.Program(reader) + return + +def dump_signature(sys_argv): + """ Read Fortran files and dump the signatures to file or stdout. + XXX: Not well tested. + """ + signature_output = get_signature_output(sys_argv) + + # initialize output stream + if signature_output in ['stdout','stderr']: + output_stream = getattr(sys, signature_output) + modulename = get_option_value(sys_argv,'-m','untitled','unknown') + else: + name,ext = os.path.splitext(signature_output) + if ext != '.pyf': + signature_output += '.pyf' + if os.path.isfile(signature_output): + overwrite = get_option(sys_argv, '--overwrite-signature', False) + if not overwrite: + print >> sys.stderr, 'Signature file %r exists. '\ + 'Use --overwrite-signature to overwrite.' % (signature_output) + sys.exit() + modulename = get_option_value(sys_argv,'-m',os.path.basename(name), + os.path.basename(name)) + output_stream = open(signature_output,'w') + + flag = 'file' + file_names = [] + only_names = [] + skip_names = [] + options = [] + for word in sys_argv: + if word=='': pass + elif word=='only:': flag = 'only' + elif word=='skip:': flag = 'skip' + elif word==':': flag = 'file' + elif word.startswith('--'): options.append(word) + else: + {'file': file_names,'only': only_names, + 'skip': skip_names}[flag].append(word) + + if options: + sys.stderr.write('Unused options: %s\n' % (', '.join(options))) + + output_stream.write('''! -*- f90 -*- +! Note: the context of this file is case sensitive. +''') + output_stream.write('PYTHON MODULE %s\n' % (modulename)) + output_stream.write(' INTERFACE\n\n') + for filename in file_names: + if not os.path.isfile(filename): + sys.stderr.write('No or not a file %r. Skipping.\n' % (filename)) + continue + sys.stderr.write('Parsing %r..\n' % (filename)) + block = parse(filename) + if block is None: + sys.exit(1) + output_stream.write('! File: %s, source mode = %r\n' % (filename, block.reader.mode)) + if block.content and isinstance(block.content[0],PythonModule): + for subblock in block.content[0].content[0].content: + if isinstance(subblock, EndStatement): + break + output_stream.write(subblock.topyf(' ')+'\n') + else: + output_stream.write(block.topyf(' ')+'\n') + output_stream.write(' END INTERFACE\n') + output_stream.write('END PYTHON MODULE %s\n' % (modulename)) + + if signature_output not in ['stdout','stderr']: + output_stream.close() + return + +def construct_extension_sources(modulename, parse_files, include_dirs, build_dir): + """ + Construct wrapper sources. + """ + from py_wrap import PythonWrapperModule + + f90_modules = [] + external_subprograms = [] + for filename in parse_files: + if not os.path.isfile(filename): + sys.stderr.write('No or not a file %r. Skipping.\n' % (filename)) + continue + sys.stderr.write('Parsing %r..\n' % (filename)) + for block in parse(filename, include_dirs=include_dirs).content: + if isinstance(block, Module): + f90_modules.append(block) + elif isinstance(block, (Subroutine, Function)): + external_subprograms.append(block) + else: + sys.stderr.write("Unhandled structure: %r\n" % (block.__class__)) + + module_infos = [] + + for block in f90_modules: + wrapper = PythonWrapperModule(block.name) + wrapper.add(block) + c_code = wrapper.c_code() + f_code = '! -*- f90 -*-\n' + wrapper.fortran_code() + c_fn = os.path.join(build_dir,'%smodule.c' % (block.name)) + f_fn = os.path.join(build_dir,'%s_f_wrappers_f2py.f90' % (block.name)) + f = open(c_fn,'w') + f.write(c_code) + f.close() + f = open(f_fn,'w') + f.write(f_code) + f.close() + #f_lib = '%s_f_wrappers_f2py' % (block.name) + module_info = {'name':block.name, 'c_sources':[c_fn], + 'f_sources':[f_fn], 'language':'f90'} + module_infos.append(module_info) + + if external_subprograms: + wrapper = PythonWrapperModule(modulename) + for block in external_subprograms: + wrapper.add(block) + c_code = wrapper.c_code() + f_code = wrapper.fortran_code() + c_fn = os.path.join(build_dir,'%smodule.c' % (modulename)) + ext = '.f' + language = 'f77' + if wrapper.isf90: + f_code = '! -*- f90 -*-\n' + f_code + ext = '.f90' + language = 'f90' + f_fn = os.path.join(build_dir,'%s_f_wrappers_f2py%s' % (modulename, ext)) + f = open(c_fn,'w') + f.write(c_code) + f.close() + f = open(f_fn,'w') + f.write(f_code) + f.close() + module_info = {'name':modulename, 'c_sources':[c_fn], + 'f_sources':[f_fn], 'language':language} + module_infos.append(module_info) + + return module_infos + +def build_extension(sys_argv, sources_only = False): + """ + Build wrappers to Fortran 90 modules and external subprograms. + """ + modulename = get_option_value(sys_argv,'-m','untitled','unspecified') + + if sources_only: + build_dir = get_option_value(sys_argv,'--build-dir','.','') + else: + build_dir = get_option_value(sys_argv,'--build-dir','.',None) + if build_dir is None: + build_dir = tempfile.mktemp() + clean_build_dir = True + else: + clean_build_dir = False + if build_dir and not os.path.exists(build_dir): os.makedirs(build_dir) + + include_dirs = get_values(sys_argv,'-I',strip_prefix=True) + library_dirs = get_values(sys_argv,'-L',strip_prefix=True) + libraries = get_values(sys_argv,'-l',strip_prefix=True) + _define_macros = get_values(sys_argv,'-D',strip_prefix=True) + undef_macros = get_values(sys_argv,'-U',strip_prefix=True) + extra_objects = get_values(sys_argv,'','[.](o|a|so|dll|dylib|sl)') + + define_macros = [] + for item in _define_macros: + name_value = item.split('=',1) + if len(name_value)==1: + name_value.append(None) + if len(name_value)==2: + define_macros.append(tuple(name_value)) + else: + print 'Invalid use of -D:',name_value + + pyf_files = get_values(sys_argv,'','[.]pyf') + fortran_files = get_values(sys_argv,'','[.](f|f90|F90|F)') + c_files = get_values(sys_argv,'','[.](c|cpp|C|CPP|c[+][+])') + + fc_flags = get_values(sys_argv,'--fcompiler=') + + options = get_values(sys_argv,'-') + if options: + sys.stderr.write('Unused options: %s\n' % (', '.join(options))) + + if pyf_files: + parse_files = pyf_files + else: + parse_files = fortran_files + c_files + + module_infos = construct_extension_sources(modulename, parse_files, include_dirs, build_dir) + + if sources_only: + return + + def configuration(parent_package='', top_path=None or ''): + from numpy.distutils.misc_util import Configuration + config = Configuration('',parent_package,top_path) + flibname = modulename + '_fortran_f2py' + if fortran_files: + config.add_library(flibname, + sources = fortran_files) + libraries.insert(0,flibname) + + for module_info in module_infos: + name = module_info['name'] + c_sources = module_info['c_sources'] + f_sources = module_info['f_sources'] + language = module_info['language'] + if f_sources: + f_lib = '%s_f_wrappers_f2py' % (name) + config.add_library(f_lib, sources = f_sources) + libs = [f_lib] + libraries + else: + libs = libraries + config.add_extension(name, + sources=c_sources + c_files, + libraries = libs, + define_macros = define_macros, + undef_macros = undef_macros, + include_dirs = include_dirs, + extra_objects = extra_objects, + language = language, + ) + return config + + old_sys_argv = sys.argv[:] + build_dir_ext_temp = os.path.join(build_dir,'ext_temp') + build_dir_clib_temp = os.path.join(build_dir,'clib_temp') + build_dir_clib_clib = os.path.join(build_dir,'clib_clib') + new_sys_argv = [sys.argv[0]] + ['build_ext', + '--build-temp',build_dir_ext_temp, + '--build-lib',build_dir, + 'build_clib', + '--build-temp',build_dir_clib_temp, + '--build-clib',build_dir_clib_clib, + ] + temp_dirs = [build_dir_ext_temp, build_dir_clib_temp, build_dir_clib_clib] + + if fc_flags: + new_sys_argv += ['config_fc'] + fc_flags + sys.argv[:] = new_sys_argv + + sys.stderr.write('setup arguments: %r\n' % (' '.join(sys.argv))) + + from numpy.distutils.core import setup + setup(configuration=configuration) + + sys.argv[:] = old_sys_argv + + if 1 or clean_build_dir: + for d in temp_dirs: + if os.path.exists(d): + sys.stderr.write('Removing build directory %s\n'%(d)) + shutil.rmtree(d) + return + +def main(sys_argv = None): + """ Main function of f2py script. + """ + if sys_argv is None: + sys_argv = sys.argv[1:] + if '--help-link' in sys_argv: + sys_argv.remove('--help-link') + from numpy.distutils.system_info import show_all + show_all() + return + if '-c' in sys_argv: + sys_argv.remove('-c') + build_extension(sys_argv) + return + if '--parse' in sys_argv: + sys_argv.remove('--parse') + parse_files(sys_argv) + return + if '-h' in sys_argv: + dump_signature(sys_argv) + return + if not sys_argv or '--help' in sys_argv: + print >> sys.stdout, __usage__ + + build_extension(sys_argv, sources_only = True) + return + +def compile(source, + jobname = 'untitled', + extra_args = [], + source_ext = None, + modulenames = None + ): + """ + Build extension module from processing source with f2py. + + jobname - the name of compile job. For non-module source + this will be also the name of extension module. + modulenames - the list of extension module names that + the given compilation job should create. + extra_args - a list of extra arguments for numpy style + setup.py command line. + source_ext - extension of the Fortran source file: .f90 or .f + + Extension modules are saved to current working directory. + Returns a list of module objects according to modulenames + input. + """ + from nary import encode + tempdir = tempfile.gettempdir() + s = 'f2pyjob_%s_%s' % (jobname, encode(source)) + tmpdir = os.path.join(tempdir, s) + if source_ext is None: + reader = get_reader(source) + source_ext = {'free90':'.f90','fix90':'.f90','fix77':'.f','pyf':'.pyf'}[reader.mode] + + if modulenames is None: + modulenames = jobname, + if os.path.isdir(tmpdir): + sys.path.insert(0, tmpdir) + try: + modules = [] + for modulename in modulenames: + exec('import %s as m' % (modulename)) + modules.append(m) + sys.path.pop(0) + return modules + except ImportError: + pass + sys.path.pop(0) + else: + os.mkdir(tmpdir) + + fname = os.path.join(tmpdir,'%s_src%s' % (jobname, source_ext)) + + f = open(fname,'w') + f.write(source) + f.close() + + sys_argv = [] + sys_argv.extend(['--build-dir',tmpdir]) + #sys_argv.extend(['-DF2PY_DEBUG_PYOBJ_TOFROM']) + sys_argv.extend(['-m',jobname, fname]) + + build_extension(sys_argv + extra_args) + + sys.path.insert(0, tmpdir) + modules = [] + for modulename in modulenames: + exec('import %s as m' % (modulename)) + modules.append(m) + sys.path.pop(0) + return modules + +#EOF diff --git a/numpy/f2py/lib/nary.py b/numpy/f2py/lib/nary.py new file mode 100644 index 000000000..948672b8c --- /dev/null +++ b/numpy/f2py/lib/nary.py @@ -0,0 +1,32 @@ +""" +nary - convert integer to a number with an arbitrary base. +""" + +__all__ = ['nary'] + +_alphabet='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' +def _getalpha(r): + if r>=len(_alphabet): + return '_'+nary(r-len(_alphabet),len(_alphabet)) + return _alphabet[r] + +def nary(number, base=64): + """ + Return string representation of a number with a given base. + """ + if isinstance(number, str): + number = eval(number) + n = number + s = '' + while n: + n1 = n // base + r = n - n1*base + n = n1 + s = _getalpha(r) + s + return s + +def encode(string): + import md5 + return nary('0x'+md5.new(string).hexdigest()) + +#print nary(12345124254252525522512324,64) diff --git a/numpy/f2py/lib/parser/Fortran2003.py b/numpy/f2py/lib/parser/Fortran2003.py new file mode 100644 index 000000000..bfdb8cbba --- /dev/null +++ b/numpy/f2py/lib/parser/Fortran2003.py @@ -0,0 +1,5889 @@ +#!/usr/bin/env python +""" +Fortran 2003 Syntax Rules. + +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: Oct 2006 +----- +""" + +import re +from splitline import string_replace_map +import pattern_tools as pattern +from readfortran import FortranReaderBase + +############################################################################### +############################## BASE CLASSES ################################### +############################################################################### + +class NoMatchError(Exception): + pass + +class ParseError(Exception): + pass + +class Base(object): + """ Base class for Fortran 2003 syntax rules. + + All Base classes have the following attributes: + .string - original argument to construct a class instance, it's type + is either str or FortranReaderBase. + .item - Line instance (holds label) or None. + """ + subclasses = {} + + def __new__(cls, string, parent_cls = None): + """ + """ + if parent_cls is None: + parent_cls = [cls] + elif cls not in parent_cls: + parent_cls.append(cls) + #print '__new__:',cls.__name__,`string` + match = cls.__dict__.get('match', None) + if isinstance(string, FortranReaderBase) and not issubclass(cls, BlockBase) \ + and match is not None: + reader = string + item = reader.get_item() + if item is None: return + try: + obj = cls(item.line, parent_cls = parent_cls) + except NoMatchError: + obj = None + if obj is None: + reader.put_item(item) + return + obj.item = item + return obj + errmsg = '%s: %r' % (cls.__name__, string) + if match is not None: + try: + result = cls.match(string) + except NoMatchError, msg: + if str(msg)==errmsg: # avoid recursion 1. + raise + result = None + else: + result = None + + #print '__new__:result:',cls.__name__,`string,result` + if isinstance(result, tuple): + obj = object.__new__(cls) + obj.string = string + obj.item = None + if hasattr(cls, 'init'): obj.init(*result) + return obj + elif isinstance(result, Base): + return result + elif result is None: + for subcls in Base.subclasses.get(cls.__name__,[]): + if subcls in parent_cls: # avoid recursion 2. + continue + #print '%s:%s: %r' % (cls.__name__,subcls.__name__,string) + try: + obj = subcls(string, parent_cls = parent_cls) + except NoMatchError, msg: + obj = None + if obj is not None: + return obj + else: + raise AssertionError,`result` + raise NoMatchError,errmsg + +## def restore_reader(self): +## self._item.reader.put_item(self._item) +## return + + def init(self, *items): + self.items = items + return + def torepr(self): + return '%s(%s)' % (self.__class__.__name__, ', '.join(map(repr,self.items))) + def compare(self, other): + return cmp(self.items,other.items) + + def __str__(self): return self.tostr() + + def __repr__(self): return self.torepr() + + def __cmp__(self, other): + if self is other: return 0 + if not isinstance(other, self.__class__): return cmp(self.__class__, other.__class__) + return self.compare(other) + + def tofortran(self, tab='', isfix=None): + return tab + str(self) + + +class BlockBase(Base): + """ + <block-base> = [ <startcls> ] + [ <subcls> ]... + ... + [ <subcls> ]... + [ <endcls> ] + """ + def match(startcls, subclasses, endcls, reader): + assert isinstance(reader,FortranReaderBase),`reader` + content = [] + if startcls is not None: + try: + obj = startcls(reader) + except NoMatchError: + obj = None + if obj is None: return + content.append(obj) + if endcls is not None: + classes = subclasses + [endcls] + else: + classes = subclasses[:] + i = 0 + while 1: + cls = classes[i] + try: + obj = cls(reader) + except NoMatchError: + obj = None + if obj is None: + j = i + for cls in classes[i+1:]: + j += 1 + try: + obj = cls(reader) + except NoMatchError: + obj = None + if obj is not None: + break + if obj is not None: + i = j + if obj is not None: + content.append(obj) + if endcls is not None and isinstance(obj, endcls): break + continue + if endcls is not None: + item = reader.get_item() + if item is not None: + reader.error('failed to parse with %s, skipping.' % ('|'.join([c.__name__ for c in classes[i:]])), item) + continue + if hasattr(content[0],'name'): + reader.error('unexpected eof file while looking line for <%s> of %s.'\ + % (classes[-1].__name__.lower().replace('_','-'), content[0].name)) + else: + reader.error('unexpected eof file while looking line for <%s>.'\ + % (classes[-1].__name__.lower().replace('_','-'))) + break + if not content: return + if startcls is not None and endcls is not None: + # check names of start and end statements: + start_stmt = content[0] + end_stmt = content[-1] + if isinstance(end_stmt, endcls) and hasattr(end_stmt, 'get_name') and hasattr(start_stmt, 'get_name'): + if end_stmt.get_name() is not None: + if start_stmt.get_name() != end_stmt.get_name(): + end_stmt._item.reader.error('expected <%s-name> is %s but got %s. Ignoring.'\ + % (end_stmt.get_type().lower(), start_stmt.get_name(), end_stmt.get_name())) + else: + end_stmt.set_name(start_stmt.get_name()) + return content, + match = staticmethod(match) + + def init(self, content): + self.content = content + return + def compare(self, other): + return cmp(self.content,other.content) + + def tostr(self): + return self.tofortran() + def torepr(self): + return '%s(%s)' % (self.__class__.__name__,', '.join(map(repr, self.content))) + + def tofortran(self, tab='', isfix=None): + l = [] + start = self.content[0] + end = self.content[-1] + extra_tab = '' + if isinstance(end, EndStmtBase): + extra_tab = ' ' + l.append(start.tofortran(tab=tab,isfix=isfix)) + for item in self.content[1:-1]: + l.append(item.tofortran(tab=tab+extra_tab,isfix=isfix)) + if len(self.content)>1: + l.append(end.tofortran(tab=tab,isfix=isfix)) + return '\n'.join(l) + +## def restore_reader(self): +## content = self.content[:] +## content.reverse() +## for obj in content: +## obj.restore_reader() +## return + +class SequenceBase(Base): + """ + <sequence-base> = <obj>, <obj> [ , <obj> ]... + """ + def match(separator, subcls, string): + line, repmap = string_replace_map(string) + if isinstance(separator, str): + splitted = line.split(separator) + else: + splitted = separator[1].split(line) + separator = separator[0] + if len(splitted)<=1: return + lst = [] + for p in splitted: + lst.append(subcls(repmap(p.strip()))) + return separator, tuple(lst) + match = staticmethod(match) + def init(self, separator, items): + self.separator = separator + self.items = items + return + def tostr(self): + s = self.separator + if s==',': s = s + ' ' + elif s==' ': pass + else: s = ' ' + s + ' ' + return s.join(map(str, self.items)) + def torepr(self): return '%s(%r, %r)' % (self.__class__.__name__, self.separator, self.items) + def compare(self, other): + return cmp((self.separator,self.items),(other.separator,self.items)) + +class UnaryOpBase(Base): + """ + <unary-op-base> = <unary-op> <rhs> + """ + def tostr(self): + return '%s %s' % tuple(self.items) + def match(op_pattern, rhs_cls, string): + m = op_pattern.match(string) + if not m: return + #if not m: return rhs_cls(string) + rhs = string[m.end():].lstrip() + if not rhs: return + op = string[:m.end()].rstrip().upper() + return op, rhs_cls(rhs) + match = staticmethod(match) + + +class BinaryOpBase(Base): + """ + <binary-op-base> = <lhs> <op> <rhs> + <op> is searched from right by default. + """ + def match(lhs_cls, op_pattern, rhs_cls, string, right=True): + line, repmap = string_replace_map(string) + if isinstance(op_pattern, str): + if right: + t = line.rsplit(op_pattern,1) + else: + t = line.split(op_pattern,1) + if len(t)!=2: return + lhs, rhs = t[0].rstrip(), t[1].lstrip() + op = op_pattern + else: + if right: + t = op_pattern.rsplit(line) + else: + t = op_pattern.lsplit(line) + if t is None or len(t)!=3: return + lhs, op, rhs = t + lhs = lhs.rstrip() + rhs = rhs.lstrip() + op = op.upper() + if not lhs: return + if not rhs: return + lhs_obj = lhs_cls(repmap(lhs)) + rhs_obj = rhs_cls(repmap(rhs)) + return lhs_obj, op, rhs_obj + match = staticmethod(match) + def tostr(self): + return '%s %s %s' % tuple(self.items) + +class SeparatorBase(Base): + """ + <separator-base> = [ <lhs> ] : [ <rhs> ] + """ + def match(lhs_cls, rhs_cls, string, require_lhs=False, require_rhs=False): + line, repmap = string_replace_map(string) + if ':' not in line: return + lhs,rhs = line.split(':',1) + lhs = lhs.rstrip() + rhs = rhs.lstrip() + lhs_obj, rhs_obj = None, None + if lhs: + if lhs_cls is None: return + lhs_obj = lhs_cls(repmap(lhs)) + elif require_lhs: + return + if rhs: + if rhs_cls is None: return + rhs_obj = rhs_cls(repmap(rhs)) + elif require_rhs: + return + return lhs_obj, rhs_obj + match = staticmethod(match) + def tostr(self): + s = '' + if self.items[0] is not None: + s += '%s :' % (self.items[0]) + else: + s += ':' + if self.items[1] is not None: + s += ' %s' % (self.items[1]) + return s + +class KeywordValueBase(Base): + """ + <keyword-value-base> = [ <lhs> = ] <rhs> + """ + def match(lhs_cls, rhs_cls, string, require_lhs = True, upper_lhs = False): + if require_lhs and '=' not in string: return + if isinstance(lhs_cls, (list, tuple)): + for s in lhs_cls: + try: + obj = KeywordValueBase.match(s, rhs_cls, string, require_lhs=require_lhs, upper_lhs=upper_lhs) + except NoMatchError: + obj = None + if obj is not None: return obj + return obj + lhs,rhs = string.split('=',1) + lhs = lhs.rstrip() + rhs = rhs.lstrip() + if not rhs: return + if not lhs: + if require_lhs: return + return None, rhs_cls(rhs) + if isinstance(lhs_cls, str): + if upper_lhs: + lhs = lhs.upper() + if lhs_cls!=lhs: return + return lhs, rhs_cls(rhs) + return lhs_cls(lhs),rhs_cls(rhs) + match = staticmethod(match) + def tostr(self): + if self.items[0] is None: return str(self.items[1]) + return '%s = %s' % tuple(self.items) + +class BracketBase(Base): + """ + <bracket-base> = <left-bracket-base> <something> <right-bracket> + """ + def match(brackets, cls, string, require_cls=True): + i = len(brackets)/2 + left = brackets[:i] + right = brackets[-i:] + if string.startswith(left) and string.endswith(right): + line = string[i:-i].strip() + if not line: + if require_cls: + return + return left,None,right + return left,cls(line),right + return + match = staticmethod(match) + def tostr(self): + if self.items[1] is None: + return '%s%s' % (self.items[0], self.items[2]) + return '%s%s%s' % tuple(self.items) + +class NumberBase(Base): + """ + <number-base> = <number> [ _ <kind-param> ] + """ + def match(number_pattern, string): + m = number_pattern.match(string) + if m is None: return + return m.group('value').upper(),m.group('kind_param') + match = staticmethod(match) + def tostr(self): + if self.items[1] is None: return str(self.items[0]) + return '%s_%s' % tuple(self.items) + def compare(self, other): + return cmp(self.items[0], other.items[0]) + +class CallBase(Base): + """ + <call-base> = <lhs> ( [ <rhs> ] ) + """ + def match(lhs_cls, rhs_cls, string, upper_lhs = False, require_rhs=False): + if not string.endswith(')'): return + line, repmap = string_replace_map(string) + i = line.find('(') + if i==-1: return + lhs = line[:i].rstrip() + if not lhs: return + rhs = line[i+1:-1].strip() + lhs = repmap(lhs) + if upper_lhs: + lhs = lhs.upper() + rhs = repmap(rhs) + if isinstance(lhs_cls, str): + if lhs_cls!=lhs: return + else: + lhs = lhs_cls(lhs) + if rhs: + if isinstance(rhs_cls, str): + if rhs_cls!=rhs: return + else: + rhs = rhs_cls(rhs) + return lhs, rhs + elif require_rhs: + return + return lhs, None + match = staticmethod(match) + def tostr(self): + if self.items[1] is None: return '%s()' % (self.items[0]) + return '%s(%s)' % (self.items[0], self.items[1]) + +class CALLBase(CallBase): + """ + <CALL-base> = <LHS> ( [ <rhs> ] ) + """ + def match(lhs_cls, rhs_cls, string, require_rhs = False): + return CallBase.match(lhs_cls, rhs_cls, string, upper_lhs=True, require_rhs = require_rhs) + match = staticmethod(match) + +class StringBase(Base): + """ + <string-base> = <xyz> + """ + def match(pattern, string): + if isinstance(pattern, (list,tuple)): + for p in pattern: + obj = StringBase.match(p, string) + if obj is not None: return obj + return + if isinstance(pattern, str): + if len(pattern)==len(string) and pattern==string: return string, + return + if pattern.match(string): return string, + return + match = staticmethod(match) + def init(self, string): + self.string = string + return + def tostr(self): return str(self.string) + def torepr(self): return '%s(%r)' % (self.__class__.__name__, self.string) + def compare(self, other): + return cmp(self.string,other.string) + +class STRINGBase(StringBase): + """ + <STRING-base> = <XYZ> + """ + match = staticmethod(StringBase.match) + def match(pattern, string): + if isinstance(pattern, (list,tuple)): + for p in pattern: + obj = STRINGBase.match(p, string) + if obj is not None: return obj + return + STRING = string.upper() + if isinstance(pattern, str): + if len(pattern)==len(string) and pattern==STRING: return STRING, + return + if pattern.match(STRING): return STRING, + return + match = staticmethod(match) + +class StmtBase(Base): + """ + [ <label> ] <stmt> + """ + def tofortran(self, tab='', isfix=None): + label = None + if self.item is not None: label = self.item.label + if isfix: + colon = '' + c = ' ' + else: + colon = ':' + c = '' + if label: + t = c + label + colon + if isfix: + while len(t)<6: t += ' ' + else: + tab = tab[len(t):] or ' ' + else: + t = '' + return t + tab + str(self) + +class EndStmtBase(StmtBase): + """ + <end-stmt-base> = END [ <stmt> [ <stmt-name>] ] + """ + def match(stmt_type, stmt_name, string, require_stmt_type=False): + start = string[:3].upper() + if start != 'END': return + line = string[3:].lstrip() + start = line[:len(stmt_type)].upper() + if start: + if start.replace(' ','') != stmt_type.replace(' ',''): return + line = line[len(stmt_type):].lstrip() + else: + if require_stmt_type: return + line = '' + if line: + if stmt_name is None: return + return stmt_type, stmt_name(line) + return stmt_type, None + match = staticmethod(match) + def init(self, stmt_type, stmt_name): + self.items = [stmt_type, stmt_name] + self.type, self.name = stmt_type, stmt_name + return + def get_name(self): return self.items[1] + def get_type(self): return self.items[0] + def set_name(self, name): + self.items[1] = name + def tostr(self): + if self.items[1] is not None: + return 'END %s %s' % tuple(self.items) + return 'END %s' % (self.items[0]) + def torepr(self): + return '%s(%r, %r)' % (self.__class__.__name__, self.type, self.name) + +def isalnum(c): return c.isalnum() or c=='_' + +class WORDClsBase(Base): + """ + <WORD-cls> = <WORD> [ [ :: ] <cls> ] + """ + def match(pattern, cls, string, check_colons=False, require_cls=False): + if isinstance(pattern, (tuple,list)): + for p in pattern: + try: + obj = WORDClsBase.match(p, cls, string, check_colons=check_colons, require_cls=require_cls) + except NoMatchError: + obj = None + if obj is not None: return obj + return + if isinstance(pattern, str): + if string[:len(pattern)].upper()!=pattern: return + line = string[len(pattern):] + if not line: return pattern, None + if isalnum(line[0]): return + line = line.lstrip() + if check_colons and line.startswith('::'): + line = line[2:].lstrip() + if not line: + if require_cls: return + return pattern, None + if cls is None: return + return pattern, cls(line) + m = pattern.match(string) + if m is None: return + line = string[len(m.group()):] + if pattern.value is not None: + pattern_value = pattern.value + else: + pattern_value = m.group().upper() + if not line: return pattern_value, None + if isalnum(line[0]): return + line = line.lstrip() + if check_colons and line.startswith('::'): + line = line[2:].lstrip() + if not line: + if require_cls: return + return pattern_value, None + if cls is None: return + return pattern_value, cls(line) + match = staticmethod(match) + def tostr(self): + if self.items[1] is None: return str(self.items[0]) + s = str(self.items[1]) + if s and s[0] in '(*': + return '%s%s' % (self.items[0], s) + return '%s %s' % (self.items[0], s) + def tostr_a(self): # colons version of tostr + if self.items[1] is None: return str(self.items[0]) + return '%s :: %s' % (self.items[0], self.items[1]) + +############################################################################### +############################### SECTION 1 #################################### +############################################################################### + +#R101: <xyz-list> = <xyz> [ , <xyz> ]... +#R102: <xyz-name> = <name> +#R103: <scalar-xyz> = <xyz> + +############################################################################### +############################### SECTION 2 #################################### +############################################################################### + +class Program(BlockBase): # R201 + """ + <program> = <program-unit> + [ <program-unit> ] ... + """ + subclass_names = [] + use_names = ['Program_Unit'] + def match(reader): + return BlockBase.match(Program_Unit, [Program_Unit], None, reader) + match = staticmethod(match) + +class Program_Unit(Base): # R202 + """ + <program-unit> = <main-program> + | <external-subprogram> + | <module> + | <block-data> + """ + subclass_names = ['Main_Program', 'External_Subprogram', 'Module', 'Block_Data'] + +class External_Subprogram(Base): # R203 + """ + <external-subprogram> = <function-subprogram> + | <subroutine-subprogram> + """ + subclass_names = ['Function_Subprogram', 'Subroutine_Subprogram'] + + +class Specification_Part(BlockBase): # R204 + """ + <specification-part> = [ <use-stmt> ]... + [ <import-stmt> ]... + [ <implicit-part> ] + [ <declaration-construct> ]... + """ + subclass_names = [] + use_names = ['Use_Stmt', 'Import_Stmt', 'Implicit_Part', 'Declaration_Construct'] + def match(reader): + return BlockBase.match(None, [Use_Stmt, Import_Stmt, Implicit_Part, Declaration_Construct], None, reader) + match = staticmethod(match) + +class Implicit_Part(Base): # R205 + """ + <implicit-part> = [ <implicit-part-stmt> ]... + <implicit-stmt> + """ + subclass_names = [] + use_names = ['Implicit_Part_Stmt', 'Implicit_Stmt'] + +class Implicit_Part_Stmt(Base): # R206 + """ + <implicit-part-stmt> = <implicit-stmt> + | <parameter-stmt> + | <format-stmt> + | <entry-stmt> + """ + subclass_names = ['Implicit_Stmt', 'Parameter_Stmt', 'Format_Stmt', 'Entry_Stmt'] + +class Declaration_Construct(Base): # R207 + """ + <declaration-construct> = <derived-type-def> + | <entry-stmt> + | <enum-def> + | <format-stmt> + | <interface-block> + | <parameter-stmt> + | <procedure-declaration-stmt> + | <specification-stmt> + | <type-declaration-stmt> + | <stmt-function-stmt> + """ + subclass_names = ['Derived_Type_Def', 'Entry_Stmt', 'Enum_Def', 'Format_Stmt', + 'Interface_Block', 'Parameter_Stmt', 'Procedure_Declaration_Stmt', + 'Specification_Stmt', 'Type_Declaration_Stmt', 'Stmt_Function_Stmt'] + +class Execution_Part(BlockBase): # R208 + """ + <execution-part> = <executable-construct> + | [ <execution-part-construct> ]... + + <execution-part> shall not contain <end-function-stmt>, <end-program-stmt>, <end-subroutine-stmt> + """ + subclass_names = [] + use_names = ['Executable_Construct_C201', 'Execution_Part_Construct_C201'] + def match(string): return BlockBase.match(Executable_Construct_C201, [Execution_Part_Construct_C201], None, string) + match = staticmethod(match) + +class Execution_Part_Construct(Base): # R209 + """ + <execution-part-construct> = <executable-construct> + | <format-stmt> + | <entry-stmt> + | <data-stmt> + """ + subclass_names = ['Executable_Construct', 'Format_Stmt', 'Entry_Stmt', 'Data_Stmt'] + +class Execution_Part_Construct_C201(Base): + subclass_names = ['Executable_Construct_C201', 'Format_Stmt', 'Entry_Stmt', 'Data_Stmt'] + +class Internal_Subprogram_Part(Base): # R210 + """ + <internal-subprogram-part> = <contains-stmt> + <internal-subprogram> + [ <internal-subprogram> ]... + """ + subclass_names = [] + use_names = ['Contains_Stmt', 'Internal_Subprogram'] + +class Internal_Subprogram(Base): # R211 + """ + <internal-subprogram> = <function-subprogram> + | <subroutine-subprogram> + """ + subclass_names = ['Function_Subprogram', 'Subroutine_Subprogram'] + +class Specification_Stmt(Base):# R212 + """ + <specification-stmt> = <access-stmt> + | <allocatable-stmt> + | <asynchronous-stmt> + | <bind-stmt> + | <common-stmt> + | <data-stmt> + | <dimension-stmt> + | <equivalence-stmt> + | <external-stmt> + | <intent-stmt> + | <intrinsic-stmt> + | <namelist-stmt> + | <optional-stmt> + | <pointer-stmt> + | <protected-stmt> + | <save-stmt> + | <target-stmt> + | <volatile-stmt> + | <value-stmt> + """ + subclass_names = ['Access_Stmt', 'Allocatable_Stmt', 'Asynchronous_Stmt','Bind_Stmt', + 'Common_Stmt', 'Data_Stmt', 'Dimension_Stmt', 'Equivalence_Stmt', + 'External_Stmt', 'Intent_Stmt', 'Intrinsic_Stmt', 'Namelist_Stmt', + 'Optional_Stmt','Pointer_Stmt','Protected_Stmt','Save_Stmt', + 'Target_Stmt','Volatile_Stmt', 'Value_Stmt'] + +class Executable_Construct(Base):# R213 + """ + <executable-construct> = <action-stmt> + | <associate-stmt> + | <case-construct> + | <do-construct> + | <forall-construct> + | <if-construct> + | <select-type-construct> + | <where-construct> + """ + subclass_names = ['Action_Stmt', 'Associate_Stmt', 'Case_Construct', 'Do_Construct', + 'Forall_Construct', 'If_Construct', 'Select_Type_Construct', 'Where_Construct'] + +class Executable_Construct_C201(Base): + subclass_names = Executable_Construct.subclass_names[:] + subclass_names[subclass_names.index('Action_Stmt')] = 'Action_Stmt_C201' + + +class Action_Stmt(Base):# R214 + """ + <action-stmt> = <allocate-stmt> + | <assignment-stmt> + | <backspace-stmt> + | <call-stmt> + | <close-stmt> + | <continue-stmt> + | <cycle-stmt> + | <deallocate-stmt> + | <endfile-stmt> + | <end-function-stmt> + | <end-program-stmt> + | <end-subroutine-stmt> + | <exit-stmt> + | <flush-stmt> + | <forall-stmt> + | <goto-stmt> + | <if-stmt> + | <inquire-stmt> + | <nullify-stmt> + | <open-stmt> + | <pointer-assignment-stmt> + | <print-stmt> + | <read-stmt> + | <return-stmt> + | <rewind-stmt> + | <stop-stmt> + | <wait-stmt> + | <where-stmt> + | <write-stmt> + | <arithmetic-if-stmt> + | <computed-goto-stmt> + """ + subclass_names = ['Allocate_Stmt', 'Assignment_Stmt', 'Backspace_Stmt', 'Call_Stmt', + 'Close_Stmt', 'Continue_Stmt', 'Cycle_Stmt', 'Deallocate_Stmt', + 'Endfile_Stmt', 'End_Function_Stmt', 'End_Subroutine_Stmt', 'Exit_Stmt', + 'Flush_Stmt', 'Forall_Stmt', 'Goto_Stmt', 'If_Stmt', 'Inquire_Stmt', + 'Nullify_Stmt', 'Open_Stmt', 'Pointer_Assignment_Stmt', 'Print_Stmt', + 'Read_Stmt', 'Return_Stmt', 'Rewind_Stmt', 'Stop_Stmt', 'Wait_Stmt', + 'Where_Stmt', 'Write_Stmt', 'Arithmetic_If_Stmt', 'Computed_Goto_Stmt'] + +class Action_Stmt_C201(Base): + """ + <action-stmt-c201> = <action-stmt> + C201 is applied. + """ + subclass_names = Action_Stmt.subclass_names[:] + subclass_names.remove('End_Function_Stmt') + subclass_names.remove('End_Subroutine_Stmt') + #subclass_names.remove('End_Program_Stmt') + +class Action_Stmt_C802(Base): + """ + <action-stmt-c802> = <action-stmt> + C802 is applied. + """ + subclass_names = Action_Stmt.subclass_names[:] + subclass_names.remove('End_Function_Stmt') + subclass_names.remove('End_Subroutine_Stmt') + subclass_names.remove('If_Stmt') + +class Action_Stmt_C824(Base): + """ + <action-stmt-c824> = <action-stmt> + C824 is applied. + """ + subclass_names = Action_Stmt.subclass_names[:] + subclass_names.remove('End_Function_Stmt') + subclass_names.remove('End_Subroutine_Stmt') + subclass_names.remove('Continue_Stmt') + subclass_names.remove('Goto_Stmt') + subclass_names.remove('Return_Stmt') + subclass_names.remove('Stop_Stmt') + subclass_names.remove('Exit_Stmt') + subclass_names.remove('Cycle_Stmt') + subclass_names.remove('Arithmetic_If_Stmt') + +class Keyword(Base): # R215 + """ + <keyword> = <name> + """ + subclass_names = ['Name'] + +############################################################################### +############################### SECTION 3 #################################### +############################################################################### + +#R301: <character> = <alphanumeric-character> | <special-character> +#R302: <alphanumeric-character> = <letter> | <digit> | <underscore> +#R303: <underscore> = _ + +class Name(StringBase): # R304 + """ + <name> = <letter> [ <alphanumeric_character> ]... + """ + subclass_names = [] + def match(string): return StringBase.match(pattern.abs_name, string) + match = staticmethod(match) + +class Constant(Base): # R305 + """ + <constant> = <literal-constant> + | <named-constant> + """ + subclass_names = ['Literal_Constant','Named_Constant'] + +class Literal_Constant(Base): # R306 + """ + <literal-constant> = <int-literal-constant> + | <real-literal-constant> + | <complex-literal-constant> + | <logical-literal-constant> + | <char-literal-constant> + | <boz-literal-constant> + """ + subclass_names = ['Int_Literal_Constant', 'Real_Literal_Constant','Complex_Literal_Constant', + 'Logical_Literal_Constant','Char_Literal_Constant','Boz_Literal_Constant'] + +class Named_Constant(Base): # R307 + """ + <named-constant> = <name> + """ + subclass_names = ['Name'] + +class Int_Constant(Base): # R308 + """ + <int-constant> = <constant> + """ + subclass_names = ['Constant'] + +class Char_Constant(Base): # R309 + """ + <char-constant> = <constant> + """ + subclass_names = ['Constant'] + +#R310: <intrinsic-operator> = <power-op> | <mult-op> | <add-op> | <concat-op> | <rel-op> | <not-op> | <and-op> | <or-op> | <equiv-op> +#R311: <defined-operator> = <defined-unary-op> | <defined-binary-op> | <extended-intrinsic-op> +#R312: <extended-intrinsic-op> = <intrinsic-op> + +class Label(StringBase): # R313 + """ + <label> = <digit> [ <digit> [ <digit> [ <digit> [ <digit> ] ] ] ] + """ + subclass_names = [] + def match(string): return StringBase.match(pattern.abs_label, string) + match = staticmethod(match) + +############################################################################### +############################### SECTION 4 #################################### +############################################################################### + +class Type_Spec(Base): # R401 + """ + <type-spec> = <intrinsic-type-spec> + | <derived-type-spec> + """ + subclass_names = ['Intrinsic_Type_Spec', 'Derived_Type_Spec'] + +class Type_Param_Value(StringBase): # R402 + """ + <type-param-value> = <scalar-int-expr> + | * + | : + """ + subclass_names = ['Scalar_Int_Expr'] + use_names = [] + def match(string): return StringBase.match(['*',':'], string) + match = staticmethod(match) + +class Intrinsic_Type_Spec(WORDClsBase): # R403 + """ + <intrinsic-type-spec> = INTEGER [ <kind-selector> ] + | REAL [ <kind-selector> ] + | DOUBLE COMPLEX + | COMPLEX [ <kind-selector> ] + | CHARACTER [ <char-selector> ] + | LOGICAL [ <kind-selector> ] + Extensions: + | DOUBLE PRECISION + | BYTE + """ + subclass_names = [] + use_names = ['Kind_Selector','Char_Selector'] + + def match(string): + for w,cls in [('INTEGER',Kind_Selector), + ('REAL',Kind_Selector), + ('COMPLEX',Kind_Selector), + ('LOGICAL',Kind_Selector), + ('CHARACTER',Char_Selector), + (pattern.abs_double_complex_name, None), + (pattern.abs_double_precision_name, None), + ('BYTE', None), + ]: + try: + obj = WORDClsBase.match(w,cls,string) + except NoMatchError: + obj = None + if obj is not None: return obj + return + match = staticmethod(match) + + +class Kind_Selector(Base): # R404 + """ + <kind-selector> = ( [ KIND = ] <scalar-int-initialization-expr> ) + Extensions: + | * <char-length> + """ + subclass_names = [] + use_names = ['Char_Length','Scalar_Int_Initialization_Expr'] + + def match(string): + if string[0]+string[-1] != '()': + if not string.startswith('*'): return + return '*',Char_Length(string[1:].lstrip()) + line = string[1:-1].strip() + if line[:4].upper()=='KIND': + line = line[4:].lstrip() + if not line.startswith('='): return + line = line[1:].lstrip() + return '(',Scalar_Int_Initialization_Expr(line),')' + match = staticmethod(match) + def tostr(self): + if len(self.items)==2: return '%s%s' % tuple(self.items) + return '%sKIND = %s%s' % tuple(self.items) + +class Signed_Int_Literal_Constant(NumberBase): # R405 + """ + <signed-int-literal-constant> = [ <sign> ] <int-literal-constant> + """ + subclass_names = ['Int_Literal_Constant'] # never used because sign is included in pattern + def match(string): + return NumberBase.match(pattern.abs_signed_int_literal_constant_named, string) + match = staticmethod(match) + +class Int_Literal_Constant(NumberBase): # R406 + """ + <int-literal-constant> = <digit-string> [ _ <kind-param> ] + """ + subclass_names = [] + def match(string): + return NumberBase.match(pattern.abs_int_literal_constant_named, string) + match = staticmethod(match) + +#R407: <kind-param> = <digit-string> | <scalar-int-constant-name> +#R408: <signed-digit-string> = [ <sign> ] <digit-string> +#R409: <digit-string> = <digit> [ <digit> ]... +#R410: <sign> = + | - + +class Boz_Literal_Constant(Base): # R411 + """ + <boz-literal-constant> = <binary-constant> + | <octal-constant> + | <hex-constant> + """ + subclass_names = ['Binary_Constant','Octal_Constant','Hex_Constant'] + +class Binary_Constant(STRINGBase): # R412 + """ + <binary-constant> = B ' <digit> [ <digit> ]... ' + | B \" <digit> [ <digit> ]... \" + """ + subclass_names = [] + def match(string): return STRINGBase.match(pattern.abs_binary_constant, string) + match = staticmethod(match) + +class Octal_Constant(STRINGBase): # R413 + """ + <octal-constant> = O ' <digit> [ <digit> ]... ' + | O \" <digit> [ <digit> ]... \" + """ + subclass_names = [] + def match(string): return STRINGBase.match(pattern.abs_octal_constant, string) + match = staticmethod(match) + +class Hex_Constant(STRINGBase): # R414 + """ + <hex-constant> = Z ' <digit> [ <digit> ]... ' + | Z \" <digit> [ <digit> ]... \" + """ + subclass_names = [] + def match(string): return STRINGBase.match(pattern.abs_hex_constant, string) + match = staticmethod(match) + +#R415: <hex-digit> = <digit> | A | B | C | D | E | F + +class Signed_Real_Literal_Constant(NumberBase): # R416 + """ + <signed-real-literal-constant> = [ <sign> ] <real-literal-constant> + """ + subclass_names = ['Real_Literal_Constant'] # never used + def match(string): + return NumberBase.match(pattern.abs_signed_real_literal_constant_named, string) + match = staticmethod(match) + +class Real_Literal_Constant(NumberBase): # R417 + """ + """ + subclass_names = [] + def match(string): + return NumberBase.match(pattern.abs_real_literal_constant_named, string) + match = staticmethod(match) + +#R418: <significand> = <digit-string> . [ <digit-string> ] | . <digit-string> +#R419: <exponent-letter> = E | D +#R420: <exponent> = <signed-digit-string> + +class Complex_Literal_Constant(Base): # R421 + """ + <complex-literal-constant> = ( <real-part>, <imag-part> ) + """ + subclass_names = [] + use_names = ['Real_Part','Imag_Part'] + def match(string): + if not string or string[0]+string[-1]!='()': return + if not pattern.abs_complex_literal_constant.match(string): + return + r,i = string[1:-1].split(',') + return Real_Part(r.strip()), Imag_Part(i.strip()) + match = staticmethod(match) + def tostr(self): return '(%s, %s)' % tuple(self.items) + +class Real_Part(Base): # R422 + """ + <real-part> = <signed-int-literal-constant> + | <signed-real-literal-constant> + | <named-constant> + """ + subclass_names = ['Signed_Int_Literal_Constant','Signed_Real_Literal_Constant','Named_Constant'] + +class Imag_Part(Base): # R423 + """ + <imag-part> = <real-part> + """ + subclass_names = ['Signed_Int_Literal_Constant','Signed_Real_Literal_Constant','Named_Constant'] + +class Char_Selector(Base): # R424 + """ + <char-selector> = <length-selector> + | ( LEN = <type-param-value> , KIND = <scalar-int-initialization-expr> ) + | ( <type-param-value> , [ KIND = ] <scalar-int-initialization-expr> ) + | ( KIND = <scalar-int-initialization-expr> [ , LEN = <type-param-value> ] ) + """ + subclass_names = ['Length_Selector'] + use_names = ['Type_Param_Value','Scalar_Int_Initialization_Expr'] + def match(string): + if string[0]+string[-1] != '()': return + line, repmap = string_replace_map(string[1:-1].strip()) + if line[:3].upper()=='LEN': + line = line[3:].lstrip() + if not line.startswith('='): return + line = line[1:].lstrip() + i = line.find(',') + if i==-1: return + v = line[:i].rstrip() + line = line[i+1:].lstrip() + if line[:4].upper()!='KIND': return + line = line[4:].lstrip() + if not line.startswith('='): return + line = line[1:].lstrip() + v = repmap(v) + line = repmap(line) + return Type_Param_Value(v), Scalar_Int_Initialization_Expr(line) + elif line[:4].upper()=='KIND': + line = line[4:].lstrip() + if not line.startswith('='): return + line = line[1:].lstrip() + i = line.find(',') + if i==-1: return None,Scalar_Int_Initialization_Expr(line) + v = line[i+1:].lstrip() + line = line[:i].rstrip() + if v[:3].upper()!='LEN': return + v = v[3:].lstrip() + if not v.startswith('='): return + v = v[1:].lstrip() + return Type_Param_Value(v), Scalar_Int_Initialization_Expr(line) + else: + i = line.find(',') + if i==-1: return + v = line[:i].rstrip() + line = line[i+1:].lstrip() + if line[:4].upper()=='KIND': + line = line[4:].lstrip() + if not line.startswith('='): return + line = line[1:].lstrip() + return Type_Param_Value(v), Scalar_Int_Initialization_Expr(line) + return + match = staticmethod(match) + def tostr(self): + if self.items[0] is None: + return '(KIND = %s)' % (self.items[1]) + return '(LEN = %s, KIND = %s)' % (self.items[0],self.items[1]) + +class Length_Selector(Base): # R425 + """ + <length -selector> = ( [ LEN = ] <type-param-value> ) + | * <char-length> [ , ] + """ + subclass_names = [] + use_names = ['Type_Param_Value','Char_Length'] + def match(string): + if string[0]+string[-1] == '()': + line = string[1:-1].strip() + if line[:3].upper()=='LEN': + line = line[3:].lstrip() + if not line.startswith('='): return + line = line[1:].lstrip() + return '(',Type_Param_Value(line),')' + if not string.startswith('*'): return + line = string[1:].lstrip() + if string[-1]==',': line = line[:-1].rstrip() + return '*',Char_Length(line) + match = staticmethod(match) + def tostr(self): + if len(self.items)==2: return '%s%s' % tuple(self.items) + return '%sLEN = %s%s' % tuple(self.items) + +class Char_Length(BracketBase): # R426 + """ + <char-length> = ( <type-param-value> ) + | <scalar-int-literal-constant> + """ + subclass_names = ['Scalar_Int_Literal_Constant'] + use_names = ['Type_Param_Value'] + def match(string): return BracketBase.match('()',Type_Param_Value, string) + match = staticmethod(match) + +class Char_Literal_Constant(Base): # R427 + """ + <char-literal-constant> = [ <kind-param> _ ] ' <rep-char> ' + | [ <kind-param> _ ] \" <rep-char> \" + """ + subclass_names = [] + rep = pattern.char_literal_constant + def match(string): + if string[-1] not in '"\'': return + if string[-1]=='"': + abs_a_n_char_literal_constant_named = pattern.abs_a_n_char_literal_constant_named2 + else: + abs_a_n_char_literal_constant_named = pattern.abs_a_n_char_literal_constant_named1 + line, repmap = string_replace_map(string) + m = abs_a_n_char_literal_constant_named.match(line) + if not m: return + kind_param = m.group('kind_param') + line = m.group('value') + line = repmap(line) + return line, kind_param + match = staticmethod(match) + def tostr(self): + if self.items[1] is None: return str(self.items[0]) + return '%s_%s' % (self.items[1], self.items[0]) + +class Logical_Literal_Constant(NumberBase): # R428 + """ + <logical-literal-constant> = .TRUE. [ _ <kind-param> ] + | .FALSE. [ _ <kind-param> ] + """ + subclass_names = [] + def match(string): + return NumberBase.match(pattern.abs_logical_literal_constant_named, string) + match = staticmethod(match) + +class Derived_Type_Def(Base): # R429 + """ + <derived-type-def> = <derived-type-stmt> + [ <type-param-def-stmt> ]... + [ <private-or-sequence> ]... + [ <component-part> ] + [ <type-bound-procedure-part> ] + <end-type-stmt> + """ + subclass_names = [] + use_names = ['Derived_Type_Stmt', 'Type_Param_Def_Stmt', 'Private_Or_Sequence', + 'Component_Part', 'Type_Bound_Procedure_Part', 'End_Type_Stmt'] + +class Derived_Type_Stmt(StmtBase): # R430 + """ + <derived-type-stmt> = TYPE [ [ , <type-attr-spec-list> ] :: ] <type-name> [ ( <type-param-name-list> ) ] + """ + subclass_names = [] + use_names = ['Type_Attr_Spec_List', 'Type_Name', 'Type_Param_Name_List'] + def match(string): + if string[:4].upper()!='TYPE': return + line = string[4:].lstrip() + i = line.find('::') + attr_specs = None + if i!=-1: + if line.startswith(','): + l = line[1:i].strip() + if not l: return + attr_specs = Type_Attr_Spec_List(l) + line = line[i+2:].lstrip() + m = pattern.name.match(line) + if m is None: return + name = Type_Name(m.group()) + line = line[m.end():].lstrip() + if not line: return attr_specs, name, None + if line[0]+line[-1]!='()': return + return attr_specs, name, Type_Param_Name_List(line[1:-1].strip()) + match = staticmethod(match) + def tostr(self): + s = 'TYPE' + if self.items[0] is not None: + s += ', %s :: %s' % (self.items[0], self.items[1]) + else: + s += ' :: %s' % (self.items[1]) + if self.items[2] is not None: + s += '(%s)' % (self.items[2]) + return s + +class Type_Name(Name): # C424 + """ + <type-name> = <name> + <type-name> shall not be DOUBLEPRECISION or the name of intrinsic type + """ + subclass_names = [] + use_names = [] + def match(string): + if pattern.abs_intrinsic_type_name.match(string): return + return Name.match(string) + match = staticmethod(match) + +class Type_EXTENDS_Parent_Type_Name(CALLBase): + """ + <..> = EXTENDS ( <parent-type-name> ) + """ + subclass_names = [] + use_names = ['Parent_Type_Name'] + def match(string): return CALLBase.match('EXTENDS', Parent_Type_Name, string) + match = staticmethod(match) + +class Type_Attr_Spec(STRINGBase): # R431 + """ + <type-attr-spec> = <access-spec> + | EXTENDS ( <parent-type-name> ) + | ABSTRACT + | BIND (C) + """ + subclass_names = ['Access_Spec', 'Type_EXTENDS_Parent_Type_Name', 'Language_Binding_Spec'] + def match(string): return STRINGBase.match('ABSTRACT', string) + match = staticmethod(match) + +class Private_Or_Sequence(Base): # R432 + """ + <private-or-sequence> = <private-components-stmt> + | <sequence-stmt> + """ + subclass_names = ['Private_Components_Stmt', 'Sequence_Stmt'] + +class End_Type_Stmt(EndStmtBase): # R433 + """ + <end-type-stmt> = END TYPE [ <type-name> ] + """ + subclass_names = [] + use_names = ['Type_Name'] + def match(string): return EndStmtBase.match('TYPE',Type_Name, string, require_stmt_type=True) + match = staticmethod(match) + +class Sequence_Stmt(STRINGBase): # R434 + """ + <sequence-stmt> = SEQUENCE + """ + subclass_names = [] + def match(string): return STRINGBase.match('SEQUENCE', string) + match = staticmethod(match) + +class Type_Param_Def_Stmt(StmtBase): # R435 + """ + <type-param-def-stmt> = INTEGER [ <kind-selector> ] , <type-param-attr-spec> :: <type-param-decl-list> + """ + subclass_names = [] + use_names = ['Kind_Selector', 'Type_Param_Attr_Spec', 'Type_Param_Decl_List'] + def match(string): + if string[:7].upper()!='INTEGER': return + line, repmap = string_replace_map(string[7:].lstrip()) + if not line: return + i = line.find(',') + if i==-1: return + kind_selector = repmap(line[:i].rstrip()) or None + line = repmap(line[i+1:].lstrip()) + i = line.find('::') + if i==-1: return + l1 = line[:i].rstrip() + l2 = line[i+2:].lstrip() + if not l1 or not l2: return + if kind_selector: kind_selector = Kind_Selector(kind_selector) + return kind_selector, Type_Param_Attr_Spec(l1), Type_Param_Decl_List(l2) + match = staticmethod(match) + def tostr(self): + s = 'INTEGER' + if self.items[0] is not None: + s += '%s, %s :: %s' % tuple(self.items) + else: + s += ', %s :: %s' % tuple(self.items[1:]) + return s + +class Type_Param_Decl(BinaryOpBase): # R436 + """ + <type-param-decl> = <type-param-name> [ = <scalar-int-initialization-expr> ] + """ + subclass_names = ['Type_Param_Name'] + use_names = ['Scalar_Int_Initialization_Expr'] + def match(string): + if '=' not in string: return + lhs,rhs = string.split('=',1) + lhs = lhs.rstrip() + rhs = rhs.lstrip() + if not lhs or not rhs: return + return Type_Param_Name(lhs),'=',Scalar_Int_Initialization_Expr(rhs) + match = staticmethod(match) + +class Type_Param_Attr_Spec(STRINGBase): # R437 + """ + <type-param-attr-spec> = KIND + | LEN + """ + subclass_names = [] + def match(string): return STRINGBase.match(['KIND', 'LEN'], string) + match = staticmethod(match) + + +class Component_Part(BlockBase): # R438 + """ + <component-part> = [ <component-def-stmt> ]... + """ + subclass_names = [] + use_names = ['Component_Def_Stmt'] + def match(reader): + content = [] + while 1: + try: + obj = Component_Def_Stmt(reader) + except NoMatchError: + obj = None + if obj is None: + break + content.append(obj) + if content: + return content, + return + match = staticmethod(match) + + def tofortran(self, tab='', isfix=None): + l = [] + for item in self.content: + l.append(item.tofortran(tab=tab,isfix=isfix)) + return '\n'.join(l) + +class Component_Def_Stmt(Base): # R439 + """ + <component-def-stmt> = <data-component-def-stmt> + | <proc-component-def-stmt> + """ + subclass_names = ['Data_Component_Def_Stmt', 'Proc_Component_Def_Stmt'] + +class Data_Component_Def_Stmt(StmtBase): # R440 + """ + <data-component-def-stmt> = <declaration-type-spec> [ [ , <component-attr-spec-list> ] :: ] <component-decl-list> + """ + subclass_names = [] + use_names = ['Declaration_Type_Spec', 'Component_Attr_Spec_List', 'Component_Decl_List'] + +class Dimension_Component_Attr_Spec(CALLBase): + """ + <dimension-component-attr-spec> = DIMENSION ( <component-array-spec> ) + """ + subclass_names = [] + use_names = ['Component_Array_Spec'] + def match(string): return CALLBase.match('DIMENSION', Component_Array_Spec, string) + match = staticmethod(match) + +class Component_Attr_Spec(STRINGBase): # R441 + """ + <component-attr-spec> = POINTER + | DIMENSION ( <component-array-spec> ) + | ALLOCATABLE + | <access-spec> + """ + subclass_names = ['Access_Spec', 'Dimension_Component_Attr_Spec'] + use_names = [] + def match(string): return STRINGBase.match(['POINTER', 'ALLOCATABLE'], string) + match = staticmethod(match) + +class Component_Decl(Base): # R442 + """ + <component-decl> = <component-name> [ ( <component-array-spec> ) ] [ * <char-length> ] [ <component-initialization> ] + """ + subclass_names = [] + use_names = ['Component_Name', 'Component_Array_Spec', 'Char_Length', 'Component_Initialization'] + def match(string): + m = pattern.name.match(string) + if m is None: return + name = Component_Name(m.group()) + newline = string[m.end():].lstrip() + if not newline: return name, None, None, None + array_spec = None + char_length = None + init = None + if newline.startswith('('): + line, repmap = string_replace_map(newline) + i = line.find(')') + if i==-1: return + array_spec = Component_Array_Spec(repmap(line[1:i].strip())) + newline = repmap(line[i+1:].lstrip()) + if newline.startswith('*'): + line, repmap = string_replace_map(newline) + i = line.find('=') + if i!=-1: + char_length = repmap(line[1:i].strip()) + newline = repmap(newline[i:].lstrip()) + else: + char_length = repmap(newline[1:].strip()) + newline = '' + char_length = Char_Length(char_length) + if newline.startswith('='): + init = Component_Initialization(newline) + else: + assert newline=='',`newline` + return name, array_spec, char_length, init + match = staticmethod(match) + def tostr(self): + s = str(self.items[0]) + if self.items[1] is not None: + s += '(' + str(self.items[1]) + ')' + if self.items[2] is not None: + s += '*' + str(self.items[2]) + if self.items[3] is not None: + s += ' ' + str(self.items[3]) + return s + +class Component_Array_Spec(Base): # R443 + """ + <component-array-spec> = <explicit-shape-spec-list> + | <deferred-shape-spec-list> + """ + subclass_names = ['Explicit_Shape_Spec_List', 'Deferred_Shape_Spec_List'] + +class Component_Initialization(Base): # R444 + """ + <component-initialization> = = <initialization-expr> + | => <null-init> + """ + subclass_names = [] + use_names = ['Initialization_Expr', 'Null_Init'] + def match(string): + if string.startswith('=>'): + return '=>', Null_Init(string[2:].lstrip()) + if string.startswith('='): + return '=', Initialization_Expr(string[2:].lstrip()) + return + match = staticmethod(match) + def tostr(self): return '%s %s' % tuple(self.items) + + +class Proc_Component_Def_Stmt(StmtBase): # R445 + """ + <proc-component-def-stmt> = PROCEDURE ( [ <proc-interface> ] ) , <proc-component-attr-spec-list> :: <proc-decl-list> + """ + subclass_names = [] + use_names = ['Proc_Interface', 'Proc_Component_Attr_Spec_List', 'Proc_Decl_List'] + +class Proc_Component_PASS_Arg_Name(CALLBase): + """ + <proc-component-PASS-arg-name> = PASS ( <arg-name> ) + """ + subclass_names = [] + use_names = ['Arg_Name'] + def match(string): return CALLBase.match('PASS', Arg_Name, string) + match = staticmethod(match) + +class Proc_Component_Attr_Spec(STRINGBase): # R446 + """ + <proc-component-attr-spec> = POINTER + | PASS [ ( <arg-name> ) ] + | NOPASS + | <access-spec> + """ + subclass_names = ['Access_Spec', 'Proc_Component_PASS_Arg_Name'] + def match(string): return STRINGBase.match(['POINTER','PASS','NOPASS'], string) + match = staticmethod(match) + +class Private_Components_Stmt(StmtBase): # R447 + """ + <private-components-stmt> = PRIVATE + """ + subclass_names = [] + def match(string): return StringBase.match('PRIVATE', string) + match = staticmethod(match) + +class Type_Bound_Procedure_Part(Base): # R448 + """ + <type-bound-procedure-part> = <contains-stmt> + [ <binding-private-stmt> ] + <proc-binding-stmt> + [ <proc-binding-stmt> ]... + """ + subclass_names = [] + use_names = ['Contains_Stmt', 'Binding_Private_Stmt', 'Proc_Binding_Stmt'] + +class Binding_Private_Stmt(StmtBase, STRINGBase): # R449 + """ + <binding-private-stmt> = PRIVATE + """ + subclass_names = [] + def match(string): return StringBase.match('PRIVATE', string) + match = staticmethod(match) + +class Proc_Binding_Stmt(Base): # R450 + """ + <proc-binding-stmt> = <specific-binding> + | <generic-binding> + | <final-binding> + """ + subclass_names = ['Specific_Binding', 'Generic_Binding', 'Final_Binding'] + +class Specific_Binding(StmtBase): # R451 + """ + <specific-binding> = PROCEDURE [ ( <interface-name> ) ] [ [ , <binding-attr-list> ] :: ] <binding-name> [ => <procedure-name> ] + """ + subclass_names = [] + use_names = ['Interface_Name', 'Binding_Attr_List', 'Binding_Name', 'Procedure_Name'] + +class Generic_Binding(StmtBase): # R452 + """ + <generic-binding> = GENERIC [ , <access-spec> ] :: <generic-spec> => <binding-name-list> + """ + subclass_names = [] + use_names = ['Access_Spec', 'Generic_Spec', 'Binding_Name_List'] + +class Binding_PASS_Arg_Name(CALLBase): + """ + <binding-PASS-arg-name> = PASS ( <arg-name> ) + """ + subclass_names = [] + use_names = ['Arg_Name'] + def match(string): return CALLBase.match('PASS', Arg_Name, string) + match = staticmethod(match) + +class Binding_Attr(STRINGBase): # R453 + """ + <binding-attr> = PASS [ ( <arg-name> ) ] + | NOPASS + | NON_OVERRIDABLE + | <access-spec> + """ + subclass_names = ['Access_Spec', 'Binding_PASS_Arg_Name'] + def match(string): return STRINGBase.match(['PASS', 'NOPASS', 'NON_OVERRIDABLE'], string) + match = staticmethod(match) + +class Final_Binding(StmtBase, WORDClsBase): # R454 + """ + <final-binding> = FINAL [ :: ] <final-subroutine-name-list> + """ + subclass_names = [] + use_names = ['Final_Subroutine_Name_List'] + def match(string): return WORDClsBase.match('FINAL',Final_Subroutine_Name_List,string,check_colons=True, require_cls=True) + match = staticmethod(match) + tostr = WORDClsBase.tostr_a + +class Derived_Type_Spec(CallBase): # R455 + """ + <derived-type-spec> = <type-name> [ ( <type-param-spec-list> ) ] + """ + subclass_names = ['Type_Name'] + use_names = ['Type_Param_Spec_List'] + def match(string): return CallBase.match(Type_Name, Type_Param_Spec_List, string) + match = staticmethod(match) + +class Type_Param_Spec(KeywordValueBase): # R456 + """ + <type-param-spec> = [ <keyword> = ] <type-param-value> + """ + subclass_names = ['Type_Param_Value'] + use_names = ['Keyword'] + def match(string): return KeywordValueBase.match(Keyword, Type_Param_Value, string) + match = staticmethod(match) + +class Structure_Constructor_2(KeywordValueBase): # R457.b + """ + <structure-constructor-2> = [ <keyword> = ] <component-data-source> + """ + subclass_names = ['Component_Data_Source'] + use_names = ['Keyword'] + def match(string): return KeywordValueBase.match(Keyword, Component_Data_Source, string) + match = staticmethod(match) + +class Structure_Constructor(CallBase): # R457 + """ + <structure-constructor> = <derived-type-spec> ( [ <component-spec-list> ] ) + | <structure-constructor-2> + """ + subclass_names = ['Structure_Constructor_2'] + use_names = ['Derived_Type_Spec', 'Component_Spec_List'] + def match(string): return CallBase.match(Derived_Type_Spec, Component_Spec_List, string) + match = staticmethod(match) + +class Component_Spec(KeywordValueBase): # R458 + """ + <component-spec> = [ <keyword> = ] <component-data-source> + """ + subclass_names = ['Component_Data_Source'] + use_names = ['Keyword'] + def match(string): return KeywordValueBase.match(Keyword, Component_Data_Source, string) + match = staticmethod(match) + +class Component_Data_Source(Base): # R459 + """ + <component-data-source> = <expr> + | <data-target> + | <proc-target> + """ + subclass_names = ['Proc_Target', 'Data_Target', 'Expr'] + +class Enum_Def(Base): # R460 + """ + <enum-def> = <enum-def-stmt> + <enumerator-def-stmt> + [ <enumerator-def-stmt> ]... + <end-enum-stmt> + """ + subclass_names = [] + use_names = ['Enum_Def_Stmt', 'Enumerator_Def_Stmt', 'End_Enum_Stmt'] + +class Enum_Def_Stmt(STRINGBase): # R461 + """ + <enum-def-stmt> = ENUM, BIND(C) + """ + subclass_names = [] + def match(string): + if string[:4].upper()!='ENUM': return + line = string[4:].lstrip() + if not line.startswith(','): return + line = line[1:].lstrip() + if line[:4].upper()!='BIND': return + line = line[4:].lstrip() + if not line or line[0]+line[-1]!='()': return + line = line[1:-1].strip() + if line!='C' or line!='c': return + return 'ENUM, BIND(C)', + match = staticmethod(match) + +class Enumerator_Def_Stmt(StmtBase, WORDClsBase): # R462 + """ + <enumerator-def-stmt> = ENUMERATOR [ :: ] <enumerator-list> + """ + subclass_names = [] + use_names = ['Enumerator_List'] + def match(string): return WORDClsBase.match('ENUMERATOR',Enumerator_List,string,check_colons=True, require_cls=True) + match = staticmethod(match) + tostr = WORDClsBase.tostr_a + +class Enumerator(BinaryOpBase): # R463 + """ + <enumerator> = <named-constant> [ = <scalar-int-initialization-expr> ] + """ + subclass_names = ['Named_Constant'] + use_names = ['Scalar_Int_Initialization_Expr'] + def match(string): + if '=' not in string: return + lhs,rhs = string.split('=',1) + return Named_Constant(lhs.rstrip()),'=',Scalar_Int_Initialization_Expr(rhs.lstrip()) + match = staticmethod(match) + +class End_Enum_Stmt(EndStmtBase): # R464 + """ + <end-enum-stmt> = END ENUM + """ + subclass_names = [] + def match(string): return EndStmtBase.match('ENUM',None, string, requite_stmt_type=True) + match = staticmethod(match) + +class Array_Constructor(BracketBase): # R465 + """ + <array-constructor> = (/ <ac-spec> /) + | <left-square-bracket> <ac-spec> <right-square-bracket> + + """ + subclass_names = [] + use_names = ['Ac_Spec'] + def match(string): + try: + obj = BracketBase.match('(//)', Ac_Spec, string) + except NoMatchError: + obj = None + if obj is None: + obj = BracketBase.match('[]', Ac_Spec, string) + return obj + match = staticmethod(match) + +class Ac_Spec(Base): # R466 + """ + <ac-spec> = <type-spec> :: + | [ <type-spec> :: ] <ac-value-list> + """ + subclass_names = ['Ac_Value_List'] + use_names = ['Type_Spec'] + def match(string): + if string.endswith('::'): + return Type_Spec(string[:-2].rstrip()),None + line, repmap = string_replace_map(string) + i = line.find('::') + if i==-1: return + ts = line[:i].rstrip() + line = line[i+2:].lstrip() + ts = repmap(ts) + line = repmap(line) + return Type_Spec(ts),Ac_Value_List(line) + match = staticmethod(match) + def tostr(self): + if self.items[0] is None: + return str(self.items[1]) + if self.items[1] is None: + return str(self.items[0]) + ' ::' + return '%s :: %s' % self.items + +# R467: <left-square-bracket> = [ +# R468: <right-square-bracket> = ] + +class Ac_Value(Base): # R469 + """ + <ac-value> = <expr> + | <ac-implied-do> + """ + subclass_names = ['Ac_Implied_Do','Expr'] + +class Ac_Implied_Do(Base): # R470 + """ + <ac-implied-do> = ( <ac-value-list> , <ac-implied-do-control> ) + """ + subclass_names = [] + use_names = ['Ac_Value_List','Ac_Implied_Do_Control'] + def match(string): + if string[0]+string[-1] != '()': return + line, repmap = string_replace_map(string[1:-1].strip()) + i = line.rfind('=') + if i==-1: return + j = line[:i].rfind(',') + assert j!=-1 + s1 = repmap(line[:j].rstrip()) + s2 = repmap(line[j+1:].lstrip()) + return Ac_Value_List(s1),Ac_Implied_Do_Control(s2) + match = staticmethod(match) + def tostr(self): return '(%s, %s)' % tuple(self.items) + +class Ac_Implied_Do_Control(Base): # R471 + """ + <ac-implied-do-control> = <ac-do-variable> = <scalar-int-expr> , <scalar-int-expr> [ , <scalar-int-expr> ] + """ + subclass_names = [] + use_names = ['Ac_Do_Variable','Scalar_Int_Expr'] + def match(string): + i = string.find('=') + if i==-1: return + s1 = string[:i].rstrip() + line, repmap = string_replace_map(string[i+1:].lstrip()) + t = line.split(',') + if not (2<=len(t)<=3): return + t = [Scalar_Int_Expr(s.strip()) for s in t] + return Ac_Do_Variable(s1), t + match = staticmethod(match) + def tostr(self): return '%s = %s' % (self.items[0], ', '.join(map(str,self.items[1]))) + +class Ac_Do_Variable(Base): # R472 + """ + <ac-do-variable> = <scalar-int-variable> + <ac-do-variable> shall be a named variable + """ + subclass_names = ['Scalar_Int_Variable'] + +############################################################################### +############################### SECTION 5 #################################### +############################################################################### + +class Type_Declaration_Stmt(Base): # R501 + """ + <type-declaration-stmt> = <declaration-type-spec> [ [ , <attr-spec> ]... :: ] <entity-decl-list> + """ + subclass_names = [] + use_names = ['Declaration_Type_Spec', 'Attr_Spec_List', 'Entity_Decl_List'] + + def match(string): + line, repmap = string_replace_map(string) + i = line.find('::') + if i!=-1: + j = line[:i].find(',') + if j!=-1: + i = j + else: + if line[:6].upper()=='DOUBLE': + m = re.search(r'\s[a-z_]',line[6:].lstrip(),re.I) + if m is None: return + i = m.start() + len(line)-len(line[6:].lstrip()) + else: + m = re.search(r'\s[a-z_]',line,re.I) + if m is None: return + i = m.start() + type_spec = Declaration_Type_Spec(repmap(line[:i].rstrip())) + if type_spec is None: return + line = line[i:].lstrip() + if line.startswith(','): + i = line.find('::') + if i==-1: return + attr_specs = Attr_Spec_List(repmap(line[1:i].strip())) + if attr_specs is None: return + line = line[i:] + else: + attr_specs = None + if line.startswith('::'): + line = line[2:].lstrip() + entity_decls = Entity_Decl_List(repmap(line)) + if entity_decls is None: return + return type_spec, attr_specs, entity_decls + match = staticmethod(match) + def tostr(self): + if self.items[1] is None: + return '%s :: %s' % (self.items[0], self.items[2]) + else: + return '%s, %s :: %s' % self.items + +class Declaration_Type_Spec(Base): # R502 + """ + <declaration-type-spec> = <intrinsic-type-spec> + | TYPE ( <derived-type-spec> ) + | CLASS ( <derived-type-spec> ) + | CLASS ( * ) + """ + subclass_names = ['Intrinsic_Type_Spec'] + use_names = ['Derived_Type_Spec'] + + def match(string): + if string[-1] != ')': return + start = string[:4].upper() + if start == 'TYPE': + line = string[4:].lstrip() + if not line.startswith('('): return + return 'TYPE',Derived_Type_Spec(line[1:-1].strip()) + start = string[:5].upper() + if start == 'CLASS': + line = string[5:].lstrip() + if not line.startswith('('): return + line = line[1:-1].strip() + if line=='*': return 'CLASS','*' + return 'CLASS', Derived_Type_Spec(line) + return + match = staticmethod(match) + def tostr(self): return '%s(%s)' % self.items + +class Dimension_Attr_Spec(CALLBase): # R503.d + """ + <dimension-attr-spec> = DIMENSION ( <array-spec> ) + """ + subclass_names = [] + use_names = ['Array_Spec'] + def match(string): return CALLBase.match('DIMENSION', Array_Spec, string) + match = staticmethod(match) + +class Intent_Attr_Spec(CALLBase): # R503.f + """ + <intent-attr-spec> = INTENT ( <intent-spec> ) + """ + subclass_names = [] + use_names = ['Intent_Spec'] + def match(string): return CALLBase.match('INTENT', Intent_Spec, string) + match = staticmethod(match) + +class Attr_Spec(STRINGBase): # R503 + """ + <attr-spec> = <access-spec> + | ALLOCATABLE + | ASYNCHRONOUS + | DIMENSION ( <array-spec> ) + | EXTERNAL + | INTENT ( <intent-spec> ) + | INTRINSIC + | <language-binding-spec> + | OPTIONAL + | PARAMETER + | POINTER + | PROTECTED + | SAVE + | TARGET + | VALUE + | VOLATILE + """ + subclass_names = ['Access_Spec', 'Language_Binding_Spec', + 'Dimension_Attr_Spec', 'Intent_Attr_Spec'] + use_names = [] + def match(string): return STRINGBase.match(pattern.abs_attr_spec, string) + match = staticmethod(match) + +class Entity_Decl(Base): # R504 + """ + <entity-decl> = <object-name> [ ( <array-spec> ) ] [ * <char-length> ] [ <initialization> ] + | <function-name> [ * <char-length> ] + """ + subclass_names = [] + use_names = ['Object_Name', 'Array_Spec', 'Char_Length', 'Initialization', 'Function_Name'] + def match(string): + m = pattern.name.match(string) + if m is None: return + name = Name(m.group()) + newline = string[m.end():].lstrip() + if not newline: return name, None, None, None + array_spec = None + char_length = None + init = None + if newline.startswith('('): + line, repmap = string_replace_map(newline) + i = line.find(')') + if i==-1: return + array_spec = Array_Spec(repmap(line[1:i].strip())) + newline = repmap(line[i+1:].lstrip()) + if newline.startswith('*'): + line, repmap = string_replace_map(newline) + i = line.find('=') + if i!=-1: + char_length = repmap(line[1:i].strip()) + newline = repmap(newline[i:].lstrip()) + else: + char_length = repmap(newline[1:].strip()) + newline = '' + char_length = Char_Length(char_length) + if newline.startswith('='): + init = Initialization(newline) + else: + assert newline=='',`newline` + return name, array_spec, char_length, init + match = staticmethod(match) + def tostr(self): + s = str(self.items[0]) + if self.items[1] is not None: + s += '(' + str(self.items[1]) + ')' + if self.items[2] is not None: + s += '*' + str(self.items[2]) + if self.items[3] is not None: + s += ' ' + str(self.items[3]) + return s + +class Object_Name(Base): # R505 + """ + <object-name> = <name> + """ + subclass_names = ['Name'] + +class Initialization(Base): # R506 + """ + <initialization> = = <initialization-expr> + | => <null-init> + """ + subclass_names = [] + use_names = ['Initialization_Expr', 'Null_Init'] + def match(string): + if string.startswith('=>'): + return '=>', Null_Init(string[2:].lstrip()) + if string.startswith('='): + return '=', Initialization_Expr(string[2:].lstrip()) + return + match = staticmethod(match) + def tostr(self): return '%s %s' % self.items + +class Null_Init(STRINGBase): # R507 + """ + <null-init> = <function-reference> + + <function-reference> shall be a reference to the NULL intrinsic function with no arguments. + """ + subclass_names = ['Function_Reference'] + def match(string): return STRINGBase.match('NULL', string) + match = staticmethod(match) + +class Access_Spec(STRINGBase): # R508 + """ + <access-spec> = PUBLIC + | PRIVATE + """ + subclass_names = [] + def match(string): return STRINGBase.match(['PUBLIC','PRIVATE'], string) + match = staticmethod(match) + +class Language_Binding_Spec(Base): # R509 + """ + <language-binding-spec> = BIND ( C [ , NAME = <scalar-char-initialization-expr> ] ) + """ + subclass_names = [] + use_names = ['Scalar_Char_Initialization_Expr'] + def match(string): + start = string[:4].upper() + if start != 'BIND': return + line = string[4:].lstrip() + if not line or line[0]+line[-1]!='()': return + line = line[1:-1].strip() + if not line: return + start = line[0].upper() + if start!='C': return + line = line[1:].lstrip() + if not line: return None, + if not line.startswith(','): return + line = line[1:].lstrip() + start = line[:4].upper() + if start!='NAME': return + line=line[4:].lstrip() + if not line.startswith('='): return + return Scalar_Char_Initialization_Expr(line[1:].lstrip()), + match = staticmethod(match) + def tostr(self): + if self.items[0] is None: return 'BIND(C)' + return 'BIND(C, NAME = %s)' % (self.items[0]) + +class Array_Spec(Base): # R510 + """ + <array-spec> = <explicit-shape-spec-list> + | <assumed-shape-spec-list> + | <deferred-shape-spec-list> + | <assumed-size-spec> + """ + subclass_names = ['Assumed_Size_Spec', 'Explicit_Shape_Spec_List', 'Assumed_Shape_Spec_List', + 'Deferred_Shape_Spec_List'] + +class Explicit_Shape_Spec(SeparatorBase): # R511 + """ + <explicit-shape-spec> = [ <lower-bound> : ] <upper-bound> + """ + subclass_names = [] + use_names = ['Lower_Bound', 'Upper_Bound'] + def match(string): + line, repmap = string_replace_map(string) + if ':' not in line: + return None, Upper_Bound(string) + lower,upper = line.split(':',1) + lower = lower.rstrip() + upper = upper.lstrip() + if not upper: return + if not lower: return + return Lower_Bound(repmap(lower)), Upper_Bound(repmap(upper)) + match = staticmethod(match) + def tostr(self): + if self.items[0] is None: return str(self.items[1]) + return SeparatorBase.tostr(self) + +class Lower_Bound(Base): # R512 + """ + <lower-bound> = <specification-expr> + """ + subclass_names = ['Specification_Expr'] + +class Upper_Bound(Base): # R513 + """ + <upper-bound> = <specification-expr> + """ + subclass_names = ['Specification_Expr'] + +class Assumed_Shape_Spec(SeparatorBase): # R514 + """ + <assumed-shape-spec> = [ <lower-bound> ] : + """ + subclass_names = [] + use_names = ['Lower_Bound'] + def match(string): return SeparatorBase.match(Lower_Bound, None, string) + match = staticmethod(match) + +class Deferred_Shape_Spec(SeparatorBase): # R515 + """ + <deferred_shape_spec> = : + """ + subclass_names = [] + def match(string): + if string==':': return None,None + return + match = staticmethod(match) + +class Assumed_Size_Spec(Base): # R516 + """ + <assumed-size-spec> = [ <explicit-shape-spec-list> , ] [ <lower-bound> : ] * + """ + subclass_names = [] + use_names = ['Explicit_Shape_Spec_List', 'Lower_Bound'] + def match(string): + if not string.endswith('*'): return + line = string[:-1].rstrip() + if not line: return None,None + if line.endswith(':'): + line, repmap = string_replace_map(line[:-1].rstrip()) + i = line.rfind(',') + if i==-1: + return None, Lower_Bound(repmap(line)) + return Explicit_Shape_Spec_List(repmap(line[:i].rstrip())), Lower_Bound(repmap(line[i+1:].lstrip())) + if not line.endswith(','): return + line = line[:-1].rstrip() + return Explicit_Shape_Spec_List(line), None + match = staticmethod(match) + def tostr(self): + s = '' + if self.items[0] is not None: + s += str(self.items[0]) + ', ' + if self.items[1] is not None: + s += str(self.items[1]) + ' : ' + s += '*' + return s + +class Intent_Spec(STRINGBase): # R517 + """ + <intent-spec> = IN + | OUT + | INOUT + """ + subclass_names = [] + def match(string): return STRINGBase.match(pattern.abs_intent_spec, string) + match = staticmethod(match) + +class Access_Stmt(StmtBase, WORDClsBase): # R518 + """ + <access-stmt> = <access-spec> [ [ :: ] <access-id-list> ] + """ + subclass_names = [] + use_names = ['Access_Spec', 'Access_Id_List'] + def match(string): return WORDClsBase.match(['PUBLIC', 'PRIVATE'],Access_Id_List,string,check_colons=True, require_cls=False) + match = staticmethod(match) + tostr = WORDClsBase.tostr_a + +class Access_Id(Base): # R519 + """ + <access-id> = <use-name> + | <generic-spec> + """ + subclass_names = ['Use_Name', 'Generic_Spec'] + +class Object_Name_Deferred_Shape_Spec_List_Item(CallBase): + """ + <..> = <object-name> [ ( <deferred-shape-spec-list> ) ] + """ + subclass_names = ['Object_Name'] + use_names = ['Deferred_Shape_Spec_List'] + def match(string): return CallBase.match(Object_Name, Deferred_Shape_Spec_List, string, require_rhs=True) + match = staticmethod(match) + +class Allocatable_Stmt(StmtBase, WORDClsBase): # R520 + """ + <allocateble-stmt> = ALLOCATABLE [ :: ] <object-name> [ ( <deferred-shape-spec-list> ) ] [ , <object-name> [ ( <deferred-shape-spec-list> ) ] ]... + """ + subclass_names = [] + use_names = ['Object_Name_Deferred_Shape_Spec_List_Item_List'] + def match(string): + return WORDClsBase.match('ALLOCATABLE', Object_Name_Deferred_Shape_Spec_List_Item_List, string, + check_colons=True, require_cls=True) + match = staticmethod(match) + +class Asynchronous_Stmt(StmtBase, WORDClsBase): # R521 + """ + <asynchronous-stmt> = ASYNCHRONOUS [ :: ] <object-name-list> + """ + subclass_names = [] + use_names = ['Object_Name_List'] + def match(string): return WORDClsBase.match('ASYNCHRONOUS',Object_Name_List,string,check_colons=True, require_cls=True) + match = staticmethod(match) + + +class Bind_Stmt(StmtBase): # R522 + """ + <bind-stmt> = <language-binding-spec> [ :: ] <bind-entity-list> + """ + subclass_names = [] + use_names = ['Language_Binding_Spec', 'Bind_Entity_List'] + def match(string): + i = string.find('::') + if i==-1: + i = string.find(')') + if i==-1: return + lhs. rhs = string[:i], string[i+1:] + else: + lhs, rhs = string.split('::',1) + lhs = lhs.rstrip() + rhs = rhs.lstrip() + if not lhs or not rhs: return + return Language_Binding_Spec(lhs), Bind_Entity_List(rhs) + match = staticmethod(match) + def tostr(self): + return '%s :: %s' % self.items + + +class Bind_Entity(BracketBase): # R523 + """ + <bind-entity> = <entity-name> + | / <common-block-name> / + """ + subclass_names = ['Entity_Name'] + use_names = ['Common_Block_Name'] + def match(string): return BracketBase.match('//',Common_Block_Name, string) + match = staticmethod(match) + +class Data_Stmt(StmtBase): # R524 + """ + <data-stmt> = DATA <data-stmt-set> [ [ , ] <data-stmt-set> ]... + """ + subclass_names = [] + use_names = ['Data_Stmt_Set'] + +class Data_Stmt_Set(Base): # R525 + """ + <data-stmt-set> = <data-stmt-object-list> / <data-stmt-value-list> / + """ + subclass_names = [] + use_names = ['Data_Stmt_Object_List', 'Data_Stmt_Value_List'] + +class Data_Stmt_Object(Base): # R526 + """ + <data-stmt-object> = <variable> + | <data-implied-do> + """ + subclass_names = ['Variable', 'Data_Implied_Do'] + +class Data_Implied_Do(Base): # R527 + """ + <data-implied-do> = ( <data-i-do-object-list> , <data-i-do-variable> = <scalar-int-expr > , <scalar-int-expr> [ , <scalar-int-expr> ] ) + """ + subclass_names = [] + use_names = ['Data_I_Do_Object_List', 'Data_I_Do_Variable', 'Scalar_Int_Expr'] + +class Data_I_Do_Object(Base): # R528 + """ + <data-i-do-object> = <array-element> + | <scalar-structure-component> + | <data-implied-do> + """ + subclass_names = ['Array_Element', 'Scalar_Structure_Component', 'Data_Implied_Do'] + +class Data_I_Do_Variable(Base): # R529 + """ + <data-i-do-variable> = <scalar-int-variable> + """ + subclass_names = ['Scalar_Int_Variable'] + +class Data_Stmt_Value(Base): # R530 + """ + <data-stmt-value> = [ <data-stmt-repeat> * ] <data-stmt-constant> + """ + subclass_names = ['Data_Stmt_Constant'] + use_names = ['Data_Stmt_Repeat'] + def match(string): + line, repmap = string_replace_map(string) + s = line.split('*') + if len(s)!=2: return + lhs = repmap(s[0].rstrip()) + rhs = repmap(s[1].lstrip()) + if not lhs or not rhs: return + return Data_Stmt_Repeat(lhs), Data_Stmt_Constant(rhs) + match = staticmethod(match) + def tostr(self): + return '%s * %s' % self.items + +class Data_Stmt_Repeat(Base): # R531 + """ + <data-stmt-repeat> = <scalar-int-constant> + | <scalar-int-constant-subobject> + """ + subclass_names = ['Scalar_Int_Constant', 'Scalar_Int_Constant_Subobject'] + +class Data_Stmt_Constant(Base): # R532 + """ + <data-stmt-constant> = <scalar-constant> + | <scalar-constant-subobject> + | <signed-int-literal-constant> + | <signed-real-literal-constant> + | <null-init> + | <structure-constructor> + """ + subclass_names = ['Scalar_Constant', 'Scalar_Constant_Subobject', + 'Signed_Int_Literal_Constant', 'Signed_Real_Literal_Constant', + 'Null_Init', 'Structure_Constructor'] + +class Int_Constant_Subobject(Base): # R533 + """ + <int-constant-subobject> = <constant-subobject> + """ + subclass_names = ['Constant_Subobject'] + +class Constant_Subobject(Base): # R534 + """ + <constant-subobject> = <designator> + """ + subclass_names = ['Designator'] + +class Dimension_Stmt(StmtBase): # R535 + """ + <dimension-stmt> = DIMENSION [ :: ] <array-name> ( <array-spec> ) [ , <array-name> ( <array-spec> ) ]... + """ + subclass_names = [] + use_names = ['Array_Name', 'Array_Spec'] + def match(string): + if string[:9].upper()!='DIMENSION': return + line, repmap = string_replace_map(string[9:].lstrip()) + if line.startswith('::'): line = line[2:].lstrip() + decls = [] + for s in line.split(','): + s = s.strip() + if not s.endswith(')'): return + i = s.find('(') + if i==-1: return + decls.append((Array_Name(repmap(s[:i].rstrip())), Array_Spec(repmap(s[i+1:-1].strip())))) + if not decls: return + return decls, + match = staticmethod(match) + def tostr(self): + return 'DIMENSION :: ' + ', '.join(['%s(%s)' % ns for ns in self.items[0]]) + +class Intent_Stmt(StmtBase): # R536 + """ + <intent-stmt> = INTENT ( <intent-spec> ) [ :: ] <dummy-arg-name-list> + """ + subclass_names = [] + use_names = ['Intent_Spec', 'Dummy_Arg_Name_List'] + def match(string): + if string[:6].upper()!='INTENT': return + line = string[6:].lstrip() + if not line or not line.startswith('('): return + i = line.rfind(')') + if i==-1: return + spec = line[1:i].strip() + if not spec: return + line = line[i+1:].lstrip() + if line.startswith('::'): + line = line[2:].lstrip() + if not line: return + return Intent_Spec(spec), Dummy_Arg_Name_List(line) + match = staticmethod(match) + def tostr(self): + return 'INTENT(%s) :: %s' % self.items + +class Optional_Stmt(StmtBase, WORDClsBase): # R537 + """ + <optional-stmt> = OPTIONAL [ :: ] <dummy-arg-name-list> + """ + subclass_names = [] + use_names = ['Dummy_Arg_Name_List'] + def match(string): return WORDClsBase.match('OPTIONAL',Dummy_Arg_Name_List,string,check_colons=True, require_cls=True) + match = staticmethod(match) + tostr = WORDClsBase.tostr_a + +class Parameter_Stmt(StmtBase, CALLBase): # R538 + """ + <parameter-stmt> = PARAMETER ( <named-constant-def-list> ) + """ + subclass_names = [] + use_names = ['Named_Constant_Def_List'] + def match(string): return CALLBase.match('PARAMETER', Named_Constant_Def_List, string, require_rhs=True) + match = staticmethod(match) + +class Named_Constant_Def(KeywordValueBase): # R539 + """ + <named-constant-def> = <named-constant> = <initialization-expr> + """ + subclass_names = [] + use_names = ['Named_Constant', 'Initialization_Expr'] + def match(string): return KeywordValueBase.match(Named_Constant, Initialization_Expr, string) + match = staticmethod(match) + +class Pointer_Stmt(StmtBase, WORDClsBase): # R540 + """ + <pointer-stmt> = POINTER [ :: ] <pointer-decl-list> + """ + subclass_names = [] + use_names = ['Pointer_Decl_List'] + def match(string): return WORDClsBase.match('POINTER',Pointer_Decl_List,string,check_colons=True, require_cls=True) + match = staticmethod(match) + tostr = WORDClsBase.tostr_a + +class Pointer_Decl(CallBase): # R541 + """ + <pointer-decl> = <object-name> [ ( <deferred-shape-spec-list> ) ] + | <proc-entity-name> + """ + subclass_names = ['Proc_Entity_Name', 'Object_Name'] + use_names = ['Deferred_Shape_Spec_List'] + def match(string): return CallBase.match(Object_Name, Deferred_Shape_Spec_List, string, require_rhs=True) + match = staticmethod(match) + +class Protected_Stmt(StmtBase, WORDClsBase): # R542 + """ + <protected-stmt> = PROTECTED [ :: ] <entity-name-list> + """ + subclass_names = [] + use_names = ['Entity_Name_List'] + def match(string): return WORDClsBase.match('PROTECTED',Entity_Name_List,string,check_colons=True, require_cls=True) + match = staticmethod(match) + tostr = WORDClsBase.tostr_a + +class Save_Stmt(StmtBase, WORDClsBase): # R543 + """ + <save-stmt> = SAVE [ [ :: ] <saved-entity-list> ] + """ + subclass_names = [] + use_names = ['Saved_Entity_List'] + def match(string): return WORDClsBase.match('SAVE',Saved_Entity_List,string,check_colons=True, require_cls=False) + match = staticmethod(match) + tostr = WORDClsBase.tostr_a + +class Saved_Entity(BracketBase): # R544 + """ + <saved-entity> = <object-name> + | <proc-pointer-name> + | / <common-block-name> / + """ + subclass_names = ['Object_Name', 'Proc_Pointer_Name'] + use_names = ['Common_Block_Name'] + def match(string): return BracketBase.match('//',CommonBlockName, string) + match = staticmethod(match) + +class Proc_Pointer_Name(Base): # R545 + """ + <proc-pointer-name> = <name> + """ + subclass_names = ['Name'] + +class Target_Stmt(StmtBase): # R546 + """ + <target-stmt> = TARGET [ :: ] <object-name> [ ( <array-spec> ) ] [ , <object-name> [ ( <array-spec> ) ] ]... + """ + subclass_names = [] + use_names = ['Object_Name', 'Array_Spec'] + +class Value_Stmt(StmtBase, WORDClsBase): # R547 + """ + <value-stmt> = VALUE [ :: ] <dummy-arg-name-list> + """ + subclass_names = [] + use_names = ['Dummy_Arg_Name_List'] + def match(string): return WORDClsBase.match('VALUE',Dummy_Arg_Name_List,string,check_colons=True, require_cls=True) + match = staticmethod(match) + tostr = WORDClsBase.tostr_a + +class Volatile_Stmt(StmtBase, WORDClsBase): # R548 + """ + <volatile-stmt> = VOLATILE [ :: ] <object-name-list> + """ + subclass_names = [] + use_names = ['Object_Name_List'] + def match(string): return WORDClsBase.match('VOLATILE',Object_Name_List,string,check_colons=True, require_cls=True) + match = staticmethod(match) + tostr = WORDClsBase.tostr_a + +class Implicit_Stmt(StmtBase, WORDClsBase): # R549 + """ + <implicit-stmt> = IMPLICIT <implicit-spec-list> + | IMPLICIT NONE + """ + subclass_names = [] + use_names = ['Implicit_Spec_List'] + def match(string): + for w,cls in [(pattern.abs_implicit_none, None), + ('IMPLICIT', Implicit_Spec_List)]: + try: + obj = WORDClsBase.match(w, cls, string) + except NoMatchError: + obj = None + if obj is not None: return obj + return + match = staticmethod(match) + +class Implicit_Spec(CallBase): # R550 + """ + <implicit-spec> = <declaration-type-spec> ( <letter-spec-list> ) + """ + subclass_names = [] + use_names = ['Declaration_Type_Spec', 'Letter_Spec_List'] + def match(string): + if not string.endswith(')'): return + i = string.rfind('(') + if i==-1: return + s1 = string[:i].rstrip() + s2 = string[i+1:-1].strip() + if not s1 or not s2: return + return Declaration_Type_Spec(s1), Letter_Spec_List(s2) + match = staticmethod(match) + +class Letter_Spec(Base): # R551 + """ + <letter-spec> = <letter> [ - <letter> ] + """ + subclass_names = [] + def match(string): + if len(string)==1: + lhs = string.upper() + if 'A'<=lhs<='Z': return lhs, None + return + if '-' not in string: return + lhs,rhs = string.split('-',1) + lhs = lhs.strip().upper() + rhs = rhs.strip().upper() + if not len(lhs)==len(rhs)==1: return + if not ('A'<=lhs<=rhs<='Z'): return + return lhs,rhs + match = staticmethod(match) + def tostr(self): + if self.items[1] is None: return str(self.items[0]) + return '%s - %s' % tuple(self.items) + +class Namelist_Stmt(StmtBase): # R552 + """ + <namelist-stmt> = NAMELIST / <namelist-group-name> / <namelist-group-object-list> [ [ , ] / <namelist-group-name> / <namelist-group-object-list> ] + """ + subclass_names = [] + use_names = ['Namelist_Group_Name', 'Namelist_Group_Object_List'] + +class Namelist_Group_Object(Base): # R553 + """ + <namelist-group-object> = <variable-name> + """ + subclass_names = ['Variable_Name'] + +class Equivalence_Stmt(StmtBase, WORDClsBase): # R554 + """ + <equivalence-stmt> = EQUIVALENCE <equivalence-set-list> + """ + subclass_names = [] + use_names = ['Equivalence_Set_List'] + def match(string): return WORDClsBase.match('EQUIVALENCE', Equivalence_Set_List, string) + match = staticmethod(match) + +class Equivalence_Set(Base): # R555 + """ + <equivalence-set> = ( <equivalence-object> , <equivalence-object-list> ) + """ + subclass_names = [] + use_names = ['Equivalence_Object', 'Equivalence_Object_List'] + def match(string): + if not string or string[0]+string[-1]!='()': return + line = string[1:-1].strip() + if not line: return + l = Equivalence_Object_List(line) + obj = l.items[0] + l.items = l.items[1:] + if not l.items: return + return obj, l + match = staticmethod(match) + def tostr(self): return '(%s, %s)' % tuple(self.items) + +class Equivalence_Object(Base): # R556 + """ + <equivalence-object> = <variable-name> + | <array-element> + | <substring> + """ + subclass_names = ['Variable_Name', 'Array_Element', 'Substring'] + +class Common_Stmt(StmtBase): # R557 + """ + <common-stmt> = COMMON [ / [ <common-block-name> ] / ] <common-block-object-list> [ [ , ] / [ <common-block-name> ] / <common-block-object-list> ]... + """ + subclass_names = [] + use_names = ['Common_Block_Name', 'Common_Block_Object_List'] + def match(string): + if string[:6].upper()!='COMMON': return + line = string[6:] + if not line or 'A'<=line[0].upper()<='Z' or line[0]=='_': return + line, repmap = string_replace_map(line.lstrip()) + items = [] + if line.startswith('/'): + i = line.find('/',1) + if i==-1: return + name = line[1:i].strip() or None + if name is not None: name = Common_Block_Name(name) + line = line[i+1:].lstrip() + i = line.find('/') + if i==-1: + lst = Common_Block_Object_List(repmap(line)) + line = '' + else: + l = line[:i].rstrip() + if l.endswith(','): l = l[:-1].rstrip() + if not l: return + lst = Common_Block_Object_List(repmap(l)) + line = line[i:].lstrip() + else: + name = None + i = line.find('/') + if i==-1: + lst = Common_Block_Object_List(repmap(line)) + line = '' + else: + l = line[:i].rstrip() + if l.endswith(','): l = l[:-1].rstrip() + if not l: return + lst = Common_Block_Object_List(repmap(l)) + line = line[i:].lstrip() + items.append((name, lst)) + while line: + if line.startswith(','): line = line[1:].lstrip() + if not line.startswith('/'): return + i = line.find('/',1) + name = line[1:i].strip() or None + if name is not None: name = Common_Block_Name(name) + line = line[i+1:].lstrip() + i = line.find('/') + if i==-1: + lst = Common_Block_Object_List(repmap(line)) + line = '' + else: + l = line[:i].rstrip() + if l.endswith(','): l = l[:-1].rstrip() + if not l: return + lst = Common_Block_Object_List(repmap(l)) + line = line[i:].lstrip() + items.append((name, lst)) + return items, + match = staticmethod(match) + def tostr(self): + s = 'COMMON' + for (name, lst) in self.items[0]: + if name is not None: + s += ' /%s/ %s' % (name, lst) + else: + s += ' // %s' % (lst) + return s + +class Common_Block_Object(CallBase): # R558 + """ + <common-block-object> = <variable-name> [ ( <explicit-shape-spec-list> ) ] + | <proc-pointer-name> + """ + subclass_names = ['Proc_Pointer_Name','Variable_Name'] + use_names = ['Variable_Name', 'Explicit_Shape_Spec_List'] + def match(string): return CallBase.match(Variable_Name, Explicit_Shape_Spec_List, string, require_rhs=True) + match = staticmethod(match) + +############################################################################### +############################### SECTION 6 #################################### +############################################################################### + +class Variable(Base): # R601 + """ + <variable> = <designator> + """ + subclass_names = ['Designator'] + +class Variable_Name(Base): # R602 + """ + <variable-name> = <name> + """ + subclass_names = ['Name'] + +class Designator(Base): # R603 + """ + <designator> = <object-name> + | <array-element> + | <array-section> + | <structure-component> + | <substring> + <substring-range> = [ <scalar-int-expr> ] : [ <scalar-int-expr> ] + <structure-component> = <data-ref> + """ + subclass_names = ['Object_Name','Array_Section','Array_Element','Structure_Component', + 'Substring' + ] + +class Logical_Variable(Base): # R604 + """ + <logical-variable> = <variable> + """ + subclass_names = ['Variable'] + +class Default_Logical_Variable(Base): # R605 + """ + <default-logical-variable> = <variable> + """ + subclass_names = ['Variable'] + +class Char_Variable(Base): # R606 + """ + <char-variable> = <variable> + """ + subclass_names = ['Variable'] + +class Default_Char_Variable(Base): # R607 + """ + <default-char-variable> = <variable> + """ + subclass_names = ['Variable'] + + +class Int_Variable(Base): # R608 + """ + <int-variable> = <variable> + """ + subclass_names = ['Variable'] + + +class Substring(CallBase): # R609 + """ + <substring> = <parent-string> ( <substring-range> ) + """ + subclass_names = [] + use_names = ['Parent_String','Substring_Range'] + def match(string): return CallBase.match(Parent_String, Substring_Range, string, require_rhs=True) + match = staticmethod(match) + +class Parent_String(Base): # R610 + """ + <parent-string> = <scalar-variable-name> + | <array-element> + | <scalar-structure-component> + | <scalar-constant> + """ + subclass_names = ['Scalar_Variable_Name', 'Array_Element', 'Scalar_Structure_Component', 'Scalar_Constant'] + +class Substring_Range(SeparatorBase): # R611 + """ + <substring-range> = [ <scalar-int-expr> ] : [ <scalar-int-expr> ] + """ + subclass_names = [] + use_names = ['Scalar_Int_Expr'] + def match(string): + return SeparatorBase.match(Scalar_Int_Expr, Scalar_Int_Expr, string) + match = staticmethod(match) + +class Data_Ref(SequenceBase): # R612 + """ + <data-ref> = <part-ref> [ % <part-ref> ]... + """ + subclass_names = ['Part_Ref'] + use_names = [] + def match(string): return SequenceBase.match(r'%', Part_Ref, string) + match = staticmethod(match) + +class Part_Ref(CallBase): # R613 + """ + <part-ref> = <part-name> [ ( <section-subscript-list> ) ] + """ + subclass_names = ['Part_Name'] + use_names = ['Section_Subscript_List'] + def match(string): + return CallBase.match(Part_Name, Section_Subscript_List, string, require_rhs=True) + match = staticmethod(match) + +class Structure_Component(Base): # R614 + """ + <structure-component> = <data-ref> + """ + subclass_names = ['Data_Ref'] + +class Type_Param_Inquiry(BinaryOpBase): # R615 + """ + <type-param-inquiry> = <designator> % <type-param-name> + """ + subclass_names = [] + use_names = ['Designator','Type_Param_Name'] + def match(string): + return BinaryOpBase.match(\ + Designator, pattern.percent_op.named(), Type_Param_Name, string) + match = staticmethod(match) + +class Array_Element(Base): # R616 + """ + <array-element> = <data-ref> + """ + subclass_names = ['Data_Ref'] + +class Array_Section(CallBase): # R617 + """ + <array-section> = <data-ref> [ ( <substring-range> ) ] + """ + subclass_names = ['Data_Ref'] + use_names = ['Substring_Range'] + def match(string): return CallBase.match(Data_Ref, Substring_Range, string, require_rhs=True) + match = staticmethod(match) + +class Subscript(Base): # R618 + """ + <subscript> = <scalar-int-expr> + """ + subclass_names = ['Scalar_Int_Expr'] + +class Section_Subscript(Base): # R619 + """ + <section-subscript> = <subscript> + | <subscript-triplet> + | <vector-subscript> + """ + subclass_names = ['Subscript_Triplet', 'Vector_Subscript', 'Subscript'] + +class Subscript_Triplet(Base): # R620 + """ + <subscript-triplet> = [ <subscript> ] : [ <subscript> ] [ : <stride> ] + """ + subclass_names = [] + use_names = ['Subscript','Stride'] + def match(string): + line, repmap = string_replace_map(string) + t = line.split(':') + if len(t)<=1 or len(t)>3: return + lhs_obj,rhs_obj, stride_obj = None, None, None + if len(t)==2: + lhs,rhs = t[0].rstrip(),t[1].lstrip() + else: + lhs,rhs,stride = t[0].rstrip(),t[1].strip(),t[2].lstrip() + if stride: + stride_obj = Stride(repmap(stride)) + if lhs: + lhs_obj = Subscript(repmap(lhs)) + if rhs: + rhs_obj = Subscript(repmap(rhs)) + return lhs_obj, rhs_obj, stride_obj + match = staticmethod(match) + def tostr(self): + s = '' + if self.items[0] is not None: + s += str(self.items[0]) + ' :' + else: + s += ':' + if self.items[1] is not None: + s += ' ' + str(self.items[1]) + if self.items[2] is not None: + s += ' : ' + str(self.items[2]) + return s + +class Stride(Base): # R621 + """ + <stride> = <scalar-int-expr> + """ + subclass_names = ['Scalar_Int_Expr'] + +class Vector_Subscript(Base): # R622 + """ + <vector-subscript> = <int-expr> + """ + subclass_names = ['Int_Expr'] + +class Allocate_Stmt(StmtBase): # R623 + """ + <allocate-stmt> = ALLOCATE ( [ <type-spec> :: ] <allocation-list> [ , <alloc-opt-list> ] ) + """ + subclass_names = [] + use_names = ['Type_Spec', 'Allocation_List', 'Alloc_Opt_List'] + +class Alloc_Opt(KeywordValueBase):# R624 + """ + <alloc-opt> = STAT = <stat-variable> + | ERRMSG = <errmsg-variable> + | SOURCE = <source-expr> + """ + subclass_names = [] + use_names = ['Stat_Variable', 'Errmsg_Variable', 'Source_Expr'] + def match(string): + for (k,v) in [('STAT', Stat_Variable), + ('ERRMSG', Errmsg_Variable), + ('SOURCE', Source_Expr) + ]: + try: + obj = KeywordValueBase.match(k, v, string, upper_lhs = True) + except NoMatchError: + obj = None + if obj is not None: return obj + return + match = staticmethod(match) + + +class Stat_Variable(Base):# R625 + """ + <stat-variable> = <scalar-int-variable> + """ + subclass_names = ['Scalar_Int_Variable'] + +class Errmsg_Variable(Base):# R626 + """ + <errmsg-variable> = <scalar-default-char-variable> + """ + subclass_names = ['Scalar_Default_Char_Variable'] + +class Source_Expr(Base):# R627 + """ + <source-expr> = <expr> + """ + subclass_names = ['Expr'] + +class Allocation(CallBase):# R628 + """ + <allocation> = <allocate-object> [ ( <allocate-shape-spec-list> ) ] + | <variable-name> + """ + subclass_names = ['Variable_Name', 'Allocate_Object'] + use_names = ['Allocate_Shape_Spec_List'] + def match(string): + return CallBase.match(Allocate_Object, Allocate_Shape_Spec_List, string, require_rhs = True) + match = staticmethod(match) + +class Allocate_Object(Base): # R629 + """ + <allocate-object> = <variable-name> + | <structure-component> + """ + subclass_names = ['Variable_Name', 'Structure_Component'] + +class Allocate_Shape_Spec(SeparatorBase): # R630 + """ + <allocate-shape-spec> = [ <lower-bound-expr> : ] <upper-bound-expr> + """ + subclass_names = [] + use_names = ['Lower_Bound_Expr', 'Upper_Bound_Expr'] + def match(string): + line, repmap = string_replace_map(string) + if ':' not in line: return None, Upper_Bound_Expr(string) + lower,upper = line.split(':',1) + lower = lower.rstrip() + upper = upper.lstrip() + if not upper: return + if not lower: return + return Lower_Bound_Expr(repmap(lower)), Upper_Bound_Expr(repmap(upper)) + match = staticmethod(match) + def tostr(self): + if self.items[0] is None: return str(self.items[1]) + return SeparatorBase.tostr(self) + + +class Lower_Bound_Expr(Base): # R631 + """ + <lower-bound-expr> = <scalar-int-expr> + """ + subclass_names = ['Scalar_Int_Expr'] + +class Upper_Bound_Expr(Base): # R632 + """ + <upper-bound-expr> = <scalar-int-expr> + """ + subclass_names = ['Scalar_Int_Expr'] + +class Nullify_Stmt(StmtBase, CALLBase): # R633 + """ + <nullify-stmt> = NULLIFY ( <pointer-object-list> ) + """ + subclass_names = [] + use_names = ['Pointer_Object_List'] + def match(string): return CALLBase.match('NULLIFY', Pointer_Object_List, string, require_rhs=True) + match = staticmethod(match) + +class Pointer_Object(Base): # R634 + """ + <pointer-object> = <variable-name> + | <structure-component> + | <proc-pointer-name> + """ + subclass_names = ['Variable_Name', 'Structure_Component', 'Proc_Pointer_Name'] + +class Deallocate_Stmt(StmtBase): # R635 + """ + <deallocate-stmt> = DEALLOCATE ( <allocate-object-list> [ , <dealloc-opt-list> ] ) + """ + subclass_names = [] + use_names = ['Allocate_Object_List', 'Dealloc_Opt_List'] + +class Dealloc_Opt(KeywordValueBase): # R636 + """ + <dealloc-opt> = STAT = <stat-variable> + | ERRMSG = <errmsg-variable> + """ + subclass_names = [] + use_names = ['Stat_Variable', 'Errmsg_Variable'] + def match(string): + for (k,v) in [('STAT', Stat_Variable), + ('ERRMSG', Errmsg_Variable), + ]: + try: + obj = KeywordValueBase.match(k, v, string, upper_lhs = True) + except NoMatchError: + obj = None + if obj is not None: return obj + return + match = staticmethod(match) + +class Scalar_Char_Initialization_Expr(Base): + subclass_names = ['Char_Initialization_Expr'] + +############################################################################### +############################### SECTION 7 #################################### +############################################################################### + +class Primary(Base): # R701 + """ + <primary> = <constant> + | <designator> + | <array-constructor> + | <structure-constructor> + | <function-reference> + | <type-param-inquiry> + | <type-param-name> + | ( <expr> ) + """ + subclass_names = ['Constant', 'Parenthesis', 'Designator','Array_Constructor', + 'Structure_Constructor', + 'Function_Reference', 'Type_Param_Inquiry', 'Type_Param_Name', + ] + +class Parenthesis(BracketBase): # R701.h + """ + <parenthesis> = ( <expr> ) + """ + subclass_names = [] + use_names = ['Expr'] + def match(string): return BracketBase.match('()', Expr, string) + match = staticmethod(match) + +class Level_1_Expr(UnaryOpBase): # R702 + """ + <level-1-expr> = [ <defined-unary-op> ] <primary> + <defined-unary-op> = . <letter> [ <letter> ]... . + """ + subclass_names = ['Primary'] + use_names = [] + def match(string): + if pattern.non_defined_binary_op.match(string): + raise NoMatchError,'%s: %r' % (Level_1_Expr.__name__, string) + return UnaryOpBase.match(\ + pattern.defined_unary_op.named(),Primary,string) + match = staticmethod(match) + +class Defined_Unary_Op(STRINGBase): # R703 + """ + <defined-unary-op> = . <letter> [ <letter> ]... . + """ + subclass_names = ['Defined_Op'] + + +class Defined_Op(STRINGBase): # R703, 723 + """ + <defined-op> = . <letter> [ <letter> ]... . + """ + subclass_names = [] + def match(string): + if pattern.non_defined_binary_op.match(string): + raise NoMatchError,'%s: %r' % (Defined_Unary_Op.__name__, string) + return STRINGBase.match(pattern.abs_defined_op, string) + match = staticmethod(match) + +class Mult_Operand(BinaryOpBase): # R704 + """ + <mult-operand> = <level-1-expr> [ <power-op> <mult-operand> ] + <power-op> = ** + """ + subclass_names = ['Level_1_Expr'] + use_names = ['Mult_Operand'] + def match(string): + return BinaryOpBase.match(\ + Level_1_Expr,pattern.power_op.named(),Mult_Operand,string,right=False) + match = staticmethod(match) + +class Add_Operand(BinaryOpBase): # R705 + """ + <add-operand> = [ <add-operand> <mult-op> ] <mult-operand> + <mult-op> = * + | / + """ + subclass_names = ['Mult_Operand'] + use_names = ['Add_Operand','Mult_Operand'] + def match(string): + return BinaryOpBase.match(Add_Operand,pattern.mult_op.named(),Mult_Operand,string) + match = staticmethod(match) + +class Level_2_Expr(BinaryOpBase): # R706 + """ + <level-2-expr> = [ [ <level-2-expr> ] <add-op> ] <add-operand> + <level-2-expr> = [ <level-2-expr> <add-op> ] <add-operand> + | <level-2-unary-expr> + <add-op> = + + | - + """ + subclass_names = ['Level_2_Unary_Expr'] + use_names = ['Level_2_Expr'] + def match(string): + return BinaryOpBase.match(\ + Level_2_Expr,pattern.add_op.named(),Add_Operand,string) + match = staticmethod(match) + +class Level_2_Unary_Expr(UnaryOpBase): # R706.c + """ + <level-2-unary-expr> = [ <add-op> ] <add-operand> + """ + subclass_names = ['Add_Operand'] + use_names = [] + def match(string): return UnaryOpBase.match(pattern.add_op.named(),Add_Operand,string) + match = staticmethod(match) + +#R707: <power-op> = ** +#R708: <mult-op> = * | / +#R709: <add-op> = + | - + +class Level_3_Expr(BinaryOpBase): # R710 + """ + <level-3-expr> = [ <level-3-expr> <concat-op> ] <level-2-expr> + <concat-op> = // + """ + subclass_names = ['Level_2_Expr'] + use_names =['Level_3_Expr'] + def match(string): + return BinaryOpBase.match(\ + Level_3_Expr,pattern.concat_op.named(),Level_2_Expr,string) + match = staticmethod(match) + +#R711: <concat-op> = // + +class Level_4_Expr(BinaryOpBase): # R712 + """ + <level-4-expr> = [ <level-3-expr> <rel-op> ] <level-3-expr> + <rel-op> = .EQ. | .NE. | .LT. | .LE. | .GT. | .GE. | == | /= | < | <= | > | >= + """ + subclass_names = ['Level_3_Expr'] + use_names = [] + def match(string): + return BinaryOpBase.match(\ + Level_3_Expr,pattern.rel_op.named(),Level_3_Expr,string) + match = staticmethod(match) + +#R713: <rel-op> = .EQ. | .NE. | .LT. | .LE. | .GT. | .GE. | == | /= | < | <= | > | >= + +class And_Operand(UnaryOpBase): # R714 + """ + <and-operand> = [ <not-op> ] <level-4-expr> + <not-op> = .NOT. + """ + subclass_names = ['Level_4_Expr'] + use_names = [] + def match(string): + return UnaryOpBase.match(\ + pattern.not_op.named(),Level_4_Expr,string) + match = staticmethod(match) + +class Or_Operand(BinaryOpBase): # R715 + """ + <or-operand> = [ <or-operand> <and-op> ] <and-operand> + <and-op> = .AND. + """ + subclass_names = ['And_Operand'] + use_names = ['Or_Operand','And_Operand'] + def match(string): + return BinaryOpBase.match(\ + Or_Operand,pattern.and_op.named(),And_Operand,string) + match = staticmethod(match) + +class Equiv_Operand(BinaryOpBase): # R716 + """ + <equiv-operand> = [ <equiv-operand> <or-op> ] <or-operand> + <or-op> = .OR. + """ + subclass_names = ['Or_Operand'] + use_names = ['Equiv_Operand'] + def match(string): + return BinaryOpBase.match(\ + Equiv_Operand,pattern.or_op.named(),Or_Operand,string) + match = staticmethod(match) + + +class Level_5_Expr(BinaryOpBase): # R717 + """ + <level-5-expr> = [ <level-5-expr> <equiv-op> ] <equiv-operand> + <equiv-op> = .EQV. + | .NEQV. + """ + subclass_names = ['Equiv_Operand'] + use_names = ['Level_5_Expr'] + def match(string): + return BinaryOpBase.match(\ + Level_5_Expr,pattern.equiv_op.named(),Equiv_Operand,string) + match = staticmethod(match) + +#R718: <not-op> = .NOT. +#R719: <and-op> = .AND. +#R720: <or-op> = .OR. +#R721: <equiv-op> = .EQV. | .NEQV. + +class Expr(BinaryOpBase): # R722 + """ + <expr> = [ <expr> <defined-binary-op> ] <level-5-expr> + <defined-binary-op> = . <letter> [ <letter> ]... . + TODO: defined_binary_op must not be intrinsic_binary_op!! + """ + subclass_names = ['Level_5_Expr'] + use_names = ['Expr'] + def match(string): + return BinaryOpBase.match(Expr, pattern.defined_binary_op.named(), Level_5_Expr, + string) + match = staticmethod(match) + +class Defined_Unary_Op(STRINGBase): # R723 + """ + <defined-unary-op> = . <letter> [ <letter> ]... . + """ + subclass_names = ['Defined_Op'] + +class Logical_Expr(Base): # R724 + """ + <logical-expr> = <expr> + """ + subclass_names = ['Expr'] + +class Char_Expr(Base): # R725 + """ + <char-expr> = <expr> + """ + subclass_names = ['Expr'] + +class Default_Char_Expr(Base): # R726 + """ + <default-char-expr> = <expr> + """ + subclass_names = ['Expr'] + +class Int_Expr(Base): # R727 + """ + <int-expr> = <expr> + """ + subclass_names = ['Expr'] + +class Numeric_Expr(Base): # R728 + """ + <numeric-expr> = <expr> + """ + subclass_names = ['Expr'] + +class Specification_Expr(Base): # R729 + """ + <specification-expr> = <scalar-int-expr> + """ + subclass_names = ['Scalar_Int_Expr'] + +class Initialization_Expr(Base): # R730 + """ + <initialization-expr> = <expr> + """ + subclass_names = ['Expr'] + +class Char_Initialization_Expr(Base): # R731 + """ + <char-initialization-expr> = <char-expr> + """ + subclass_names = ['Char_Expr'] + +class Int_Initialization_Expr(Base): # R732 + """ + <int-initialization-expr> = <int-expr> + """ + subclass_names = ['Int_Expr'] + +class Logical_Initialization_Expr(Base): # R733 + """ + <logical-initialization-expr> = <logical-expr> + """ + subclass_names = ['Logical_Expr'] + +class Assignment_Stmt(StmtBase, BinaryOpBase): # R734 + """ + <assignment-stmt> = <variable> = <expr> + """ + subclass_names = [] + use_names = ['Variable', 'Expr'] + def match(string): + return BinaryOpBase.match(Variable, '=', Expr, string, right=False) + match = staticmethod(match) + +class Pointer_Assignment_Stmt(StmtBase): # R735 + """ + <pointer-assignment-stmt> = <data-pointer-object> [ ( <bounds-spec-list> ) ] => <data-target> + | <data-pointer-object> ( <bounds-remapping-list> ) => <data-target> + | <proc-pointer-object> => <proc-target> + """ + subclass_names = [] + use_names = ['Data_Pointer_Object', 'Bounds_Spec_List', 'Data_Target', 'Bounds_Remapping_List', + 'Proc_Pointer_Object', 'Proc_Target'] + +class Data_Pointer_Object(BinaryOpBase): # R736 + """ + <data-pointer-object> = <variable-name> + | <variable> % <data-pointer-component-name> + """ + subclass_names = ['Variable_Name'] + use_names = ['Variable', 'Data_Pointer_Component_Name'] + def match(string): + return BinaryOpBase.match(Variable, r'%', Data_Pointer_Component_Name, string) + match = staticmethod(match) + +class Bounds_Spec(SeparatorBase): # R737 + """ + <bounds-spec> = <lower-bound-expr> : + """ + subclass_names = [] + use_names = ['Lower_Bound_Expr'] + def match(string): return SeparatorBase.match(Lower_Bound_Expr, None, string, require_lhs=True) + match = staticmethod(match) + +class Bounds_Remapping(SeparatorBase): # R738 + """ + <bounds-remapping> = <lower-bound-expr> : <upper-bound-expr> + """ + subclass_names = [] + use_classes = ['Lower_Bound_Expr', 'Upper_Bound_Expr'] + def match(string): return SeparatorBase.match(Lower_Bound_Expr, Upper_Bound_Expr, string, require_lhs=True, require_rhs=True) + match = staticmethod(match) + +class Data_Target(Base): # R739 + """ + <data-target> = <variable> + | <expr> + """ + subclass_names = ['Variable','Expr'] + +class Proc_Pointer_Object(Base): # R740 + """ + <proc-pointer-object> = <proc-pointer-name> + | <proc-component-ref> + """ + subclass_names = ['Proc_Pointer_Name', 'Proc_Component_Ref'] + +class Proc_Component_Ref(BinaryOpBase): # R741 + """ + <proc-component-ref> = <variable> % <procedure-component-name> + """ + subclass_names = [] + use_names = ['Variable','Procedure_Component_Name'] + def match(string): + return BinaryOpBase.match(Variable, r'%', Procedure_Component_Name, string) + match = staticmethod(match) + +class Proc_Target(Base): # R742 + """ + <proc-target> = <expr> + | <procedure-name> + | <proc-component-ref> + """ + subclass_names = ['Proc_Component_Ref', 'Procedure_Name', 'Expr'] + + +class Where_Stmt(StmtBase): # R743 + """ + <where-stmt> = WHERE ( <mask-expr> ) <where-assignment-stmt> + """ + subclass_names = [] + use_names = ['Mask_Expr', 'Where_Assignment_Stmt'] + def match(string): + if string[:5].upper()!='WHERE': return + line, repmap = string_replace_map(string[5:].lstrip()) + if not line.startswith('('): return + i = line.find(')') + if i==-1: return + stmt = repmap(line[i+1:].lstrip()) + if not stmt: return + expr = repmap(line[1:i].strip()) + if not expr: return + return Mask_Expr(expr), Where_Assignment_Stmt(stmt) + match = staticmethod(match) + def tostr(self): return 'WHERE (%s) %s' % tuple(self.items) + + +class Where_Construct(Base): # R744 + """ + <where-construct> = <where-construct-stmt> + [ <where-body-construct> ]... + [ <masked-elsewhere-stmt> + [ <where-body-construct> ]... + ]... + [ <elsewhere-stmt> + [ <where-body-construct> ]... ] + <end-where-stmt> + """ + subclass_names = [] + use_names = ['Where_Construct_Stmt', 'Where_Body_Construct', + 'Elsewhere_Stmt', 'End_Where_Stmt' + ] + +class Where_Construct_Stmt(StmtBase): # R745 + """ + <where-construct-stmt> = [ <where-construct-name> : ] WHERE ( <mask-expr> ) + """ + subclass_names = [] + use_names = ['Where_Construct_Name', 'Mask_Expr'] + + def match(string): + if string[:5].upper()!='WHERE': return + line = string[5:].lstrip() + if not line: return + if line[0]+line[-1] != '()': return + line = line[1:-1].strip() + if not line: return + return Mask_Expr(line), + match = staticmethod(match) + def tostr(self): return 'WHERE (%s)' % tuple(self.items) + +class Where_Body_Construct(Base): # R746 + """ + <where-body-construct> = <where-assignment-stmt> + | <where-stmt> + | <where-construct> + """ + subclass_names = ['Where_Assignment_Stmt', 'Where_Stmt', 'Where_Construct'] + +class Where_Assignment_Stmt(Base): # R747 + """ + <where-assignment-stmt> = <assignment-stmt> + """ + subclass_names = ['Assignment_Stmt'] + +class Mask_Expr(Base): # R748 + """ + <mask-expr> = <logical-expr> + """ + subclass_names = ['Logical_Expr'] + +class Masked_Elsewhere_Stmt(StmtBase): # R749 + """ + <masked-elsewhere-stmt> = ELSEWHERE ( <mask-expr> ) [ <where-construct-name> ] + """ + subclass_names = [] + use_names = ['Mask_Expr', 'Where_Construct_Name'] + def match(string): + if string[:9].upper()!='ELSEWHERE': return + line = string[9:].lstrip() + if not line.startswith('('): return + i = line.rfind(')') + if i==-1: return + expr = line[1:i].strip() + if not expr: return + line = line[i+1:].rstrip() + if line: + return Mask_Expr(expr), Where_Construct_Name(line) + return Mask_Expr(expr), None + match = staticmethod(match) + def tostr(self): + if self.items[1] is None: return 'ELSEWHERE(%s)' % (self.items[0]) + return 'ELSEWHERE(%s) %s' % self.items + +class Elsewhere_Stmt(StmtBase, WORDClsBase): # R750 + """ + <elsewhere-stmt> = ELSEWHERE [ <where-construct-name> ] + """ + subclass_names = [] + use_names = ['Where_Construct_Name'] + def match(string): return WORDClsBase.match('ELSEWHERE', Where_Construct_Name, string) + match = staticmethod(match) + +class End_Where_Stmt(EndStmtBase): # R751 + """ + <end-where-stmt> = END WHERE [ <where-construct-name> ] + """ + subclass_names = [] + use_names = ['Where_Construct_Name'] + def match(string): return EndStmtBase.match('WHERE',Where_Construct_Name, string, require_stmt_type=True) + match = staticmethod(match) + + +class Forall_Construct(Base): # R752 + """ + <forall-construct> = <forall-construct-stmt> + [ <forall-body-construct> ]... + <end-forall-stmt> + """ + subclass_names = [] + use_names = ['Forall_Construct_Stmt', 'Forall_Body_Construct', 'End_Forall_Stmt'] + +class Forall_Construct_Stmt(StmtBase, WORDClsBase): # R753 + """ + <forall-construct-stmt> = [ <forall-construct-name> : ] FORALL <forall-header> + """ + subclass_names = [] + use_names = ['Forall_Construct_Name', 'Forall_Header'] + def match(string): return WORDClsBase.match('FORALL', Forall_Header, string, require_cls = True) + match = staticmethod(match) + +class Forall_Header(Base): # R754 + """ + <forall-header> = ( <forall-triplet-spec-list> [ , <scalar-mask-expr> ] ) + """ + subclass_names = [] + use_names = ['Forall_Triplet_Spec_List', 'Scalar_Mask_Expr'] + +class Forall_Triplet_Spec(Base): # R755 + """ + <forall-triplet-spec> = <index-name> = <subscript> : <subscript> [ : <stride> ] + """ + subclass_names = [] + use_names = ['Index_Name', 'Subscript', 'Stride'] + +class Forall_Body_Construct(Base): # R756 + """ + <forall-body-construct> = <forall-assignment-stmt> + | <where-stmt> + | <where-construct> + | <forall-construct> + | <forall-stmt> + """ + subclass_names = ['Forall_Assignment_Stmt', 'Where_Stmt', 'Where_Construct', + 'Forall_Construct', 'Forall_Stmt'] + +class Forall_Assignment_Stmt(Base): # R757 + """ + <forall-assignment-stmt> = <assignment-stmt> + | <pointer-assignment-stmt> + """ + subclass_names = ['Assignment_Stmt', 'Pointer_Assignment_Stmt'] + +class End_Forall_Stmt(EndStmtBase): # R758 + """ + <end-forall-stmt> = END FORALL [ <forall-construct-name> ] + """ + subclass_names = [] + use_names = ['Forall_Construct_Name'] + def match(string): return EndStmtBase.match('FORALL',Forall_Construct_Name, string, require_stmt_type=True) + match = staticmethod(match) + +class Forall_Stmt(StmtBase): # R759 + """ + <forall-stmt> = FORALL <forall-header> <forall-assignment-stmt> + """ + subclass_names = [] + use_names = ['Forall_Header', 'Forall_Assignment_Stmt'] + def match(string): + if string[:6].upper()!='FORALL': return + line, repmap = string_replace_map(string[6:].lstrip()) + if not line.startswith(')'): return + i = line.find(')') + if i==-1: return + header = repmap(line[1:i].strip()) + if not header: return + line = repmap(line[i+1:].lstrip()) + if not line: return + return Forall_Header(header), Forall_Assignment_Stmt(line) + match = staticmethod(match) + def tostr(self): return 'FORALL %s %s' % self.items + +############################################################################### +############################### SECTION 8 #################################### +############################################################################### + +class Block(BlockBase): # R801 + """ + block = [ <execution-part-construct> ]... + """ + subclass_names = [] + use_names = ['Execution_Part_Construct'] + def match(string): return BlockBase.match(None, [Execution_Part_Construct], None, string) + match = staticmethod(match) + +class If_Construct(BlockBase): # R802 + """ + <if-construct> = <if-then-stmt> + <block> + [ <else-if-stmt> + <block> + ]... + [ <else-stmt> + <block> + ] + <end-if-stmt> + """ + subclass_names = [] + use_names = ['If_Then_Stmt', 'Block', 'Else_If_Stmt', 'Else_Stmt', 'End_If_Stmt'] + + def match(reader): + content = [] + try: + obj = If_Then_Stmt(reader) + except NoMatchError: + obj = None + if obj is None: return + content.append(obj) + obj = Block(reader) + if obj is None: return # todo: restore reader + content.append(obj) + while 1: + try: + obj = Else_If_Stmt(reader) + except NoMatchError: + obj = None + if obj is not None: + content.append(obj) + obj = Block(reader) + if obj is None: return # todo: restore reader + content.append(obj) + continue + try: + obj = Else_Stmt(reader) + except NoMatchError: + obj = None + if obj is not None: + content.append(obj) + obj = Block(reader) + if obj is None: return # todo: restore reader + content.append(obj) + break + try: + obj = End_If_Stmt(reader) + except NoMatchError: + obj = None + if obj is None: return # todo: restore reader + content.append(obj) + return content, + match = staticmethod(match) + + def tofortran(self, tab='', isfix=None): + l = [] + start = self.content[0] + end = self.content[-1] + l.append(start.tofortran(tab=tab,isfix=isfix)) + for item in self.content[1:-1]: + if isinstance(item, (Else_If_Stmt, Else_Stmt)): + l.append(item.tofortran(tab=tab,isfix=isfix)) + else: + l.append(item.tofortran(tab=tab+' ',isfix=isfix)) + l.append(end.tofortran(tab=tab,isfix=isfix)) + return '\n'.join(l) + + +class If_Then_Stmt(StmtBase): # R803 + """ + <if-then-stmt> = [ <if-construct-name> : ] IF ( <scalar-logical-expr> ) THEN + """ + subclass_names = [] + use_names = ['If_Construct_Name', 'Scalar_Logical_Expr'] + def match(string): + if string[:2].upper()!='IF': return + if string[-4:].upper()!='THEN': return + line = string[2:-4].strip() + if not line: return + if line[0]+line[-1]!='()': return + return Scalar_Logical_Expr(line[1:-1].strip()), + match = staticmethod(match) + def tostr(self): return 'IF (%s) THEN' % self.items + +class Else_If_Stmt(StmtBase): # R804 + """ + <else-if-stmt> = ELSE IF ( <scalar-logical-expr> ) THEN [ <if-construct-name> ] + """ + subclass_names = [] + use_names = ['Scalar_Logical_Expr', 'If_Construct_Name'] + + def match(string): + if string[:4].upper()!='ELSE': return + line = string[4:].lstrip() + if line[:2].upper()!='IF': return + line = line[2:].lstrip() + if not line.startswith('('): return + i = line.rfind(')') + if i==-1: return + expr = line[1:i].strip() + line = line[i+1:].lstrip() + if line[:4].upper()!='THEN': return + line = line[4:].lstrip() + if line: return Scalar_Logical_Expr(expr), If_Construct_Name(line) + return Scalar_Logical_Expr(expr), None + match = staticmethod(match) + def tostr(self): + if self.items[1] is None: + return 'ELSE IF (%s) THEN' % (self.items[0]) + return 'ELSE IF (%s) THEN %s' % self.items + +class Else_Stmt(StmtBase): # R805 + """ + <else-stmt> = ELSE [ <if-construct-name> ] + """ + subclass_names = [] + use_names = ['If_Construct_Name'] + def match(string): + if string[:4].upper()!='ELSE': return + line = string[4:].lstrip() + if line: return If_Construct_Name(line), + return None, + match = staticmethod(match) + def tostr(self): + if self.items[0] is None: + return 'ELSE' + return 'ELSE %s' % self.items + +class End_If_Stmt(EndStmtBase): # R806 + """ + <end-if-stmt> = END IF [ <if-construct-name> ] + """ + subclass_names = [] + use_names = ['If_Construct_Name'] + def match(string): return EndStmtBase.match('IF',If_Construct_Name, string, require_stmt_type=True) + match = staticmethod(match) + +class If_Stmt(StmtBase): # R807 + """ + <if-stmt> = IF ( <scalar-logical-expr> ) <action-stmt> + """ + subclass_names = [] + use_names = ['Scalar_Logical_Expr', 'Action_Stmt_C802'] + def match(string): + if string[:2].upper() != 'IF': return + line, repmap = string_replace_map(string) + line = line[2:].lstrip() + if not line.startswith('('): return + i = line.find(')') + if i==-1: return + expr = repmap(line[1:i].strip()) + stmt = repmap(line[i+1:].lstrip()) + return Scalar_Logical_Expr(expr), Action_Stmt_C802(stmt) + match = staticmethod(match) + def tostr(self): return 'IF (%s) %s' % self.items + +class Case_Construct(Base): # R808 + """ + <case-construct> = <select-case-stmt> + [ <case-stmt> + <block> + ].. + <end-select-stmt> + """ + subclass_names = [] + use_names = ['Select_Case_Stmt', 'Case_Stmt', 'End_Select_Stmt'] + +class Select_Case_Stmt(StmtBase, CALLBase): # R809 + """ + <select-case-stmt> = [ <case-construct-name> : ] SELECT CASE ( <case-expr> ) + """ + subclass_names = [] + use_names = ['Case_Construct_Name', 'Case_Expr'] + def match(string): return CALLBase.match(pattter.abs_select_case, Case_Expr, string) + match = staticmethod(match) + +class Case_Stmt(StmtBase): # R810 + """ + <case-stmt> = CASE <case-selector> [ <case-construct-name> ] + """ + subclass_names = [] + use_names = ['Case_Selector', 'Case_Construct_Name'] + +class End_Select_Stmt(EndStmtBase): # R811 + """ + <end-select-stmt> = END SELECT [ <case-construct-name> ] + """ + subclass_names = [] + use_names = ['Case_Construct_Name'] + def match(string): return EndStmtBase.match('SELECT',Case_Construct_Name, string, require_stmt_type=True) + match = staticmethod(match) + +class Case_Expr(Base): # R812 + """ + <case-expr> = <scalar-int-expr> + | <scalar-char-expr> + | <scalar-logical-expr> + """ + subclass_names = [] + subclass_names = ['Scalar_Int_Expr', 'Scalar_Char_Expr', 'Scalar_Logical_Expr'] + +class Case_Selector(Base): # R813 + """ + <case-selector> = ( <case-value-range-list> ) + | DEFAULT + """ + subclass_names = [] + use_names = ['Case_Value_Range_List'] + +class Case_Value_Range(SeparatorBase): # R814 + """ + <case-value-range> = <case-value> + | <case-value> : + | : <case-value> + | <case-value> : <case-value> + """ + subclass_names = ['Case_Value'] + def match(string): return SeparatorBase.match(Case_Value, Case_Value, string) + match = staticmethod(match) + +class Case_Value(Base): # R815 + """ + <case-value> = <scalar-int-initialization-expr> + | <scalar-char-initialization-expr> + | <scalar-logical-initialization-expr> + """ + subclass_names = ['Scalar_Int_Initialization_Expr', 'Scalar_Char_Initialization_Expr', 'Scalar_Logical_Initialization_Expr'] + + +class Associate_Construct(Base): # R816 + """ + <associate-construct> = <associate-stmt> + <block> + <end-associate-stmt> + """ + subclass_names = [] + use_names = ['Associate_Stmt', 'Block', 'End_Associate_Stmt'] + +class Associate_Stmt(StmtBase, CALLBase): # R817 + """ + <associate-stmt> = [ <associate-construct-name> : ] ASSOCIATE ( <association-list> ) + """ + subclass_names = [] + use_names = ['Associate_Construct_Name', 'Association_List'] + def match(string): return CALLBase.match('ASSOCIATE', Association_List, string) + match = staticmethod(match) + +class Association(BinaryOpBase): # R818 + """ + <association> = <associate-name> => <selector> + """ + subclass_names = [] + use_names = ['Associate_Name', 'Selector'] + def match(string): return BinaryOpBase.match(Assiciate_Name, '=>', Selector, string) + match = staticmethod(match) + +class Selector(Base): # R819 + """ + <selector> = <expr> + | <variable> + """ + subclass_names = ['Expr', 'Variable'] + +class End_Associate_Stmt(EndStmtBase): # R820 + """ + <end-associate-stmt> = END ASSOCIATE [ <associate-construct-name> ] + """ + subclass_names = [] + use_names = ['Associate_Construct_Name'] + def match(string): return EndStmtBase.match('ASSOCIATE',Associate_Construct_Name, string, require_stmt_type=True) + match = staticmethod(match) + +class Select_Type_Construct(Base): # R821 + """ + <select-type-construct> = <select-type-stmt> + [ <type-guard-stmt> + <block> + ]... + <end-select-type-stmt> + """ + subclass_names = [] + use_names = ['Select_Type_Stmt', 'Type_Guard_Stmt', 'Block', 'End_Select_Type_Stmt'] + +class Select_Type_Stmt(StmtBase): # R822 + """ + <select-type-stmt> = [ <select-construct-name> : ] SELECT TYPE ( [ <associate-name> => ] <selector> ) + """ + subclass_names = [] + use_names = ['Select_Construct_Name', 'Associate_Name', 'Selector'] + +class Type_Guard_Stmt(StmtBase): # R823 + """ + <type-guard-stmt> = TYPE IS ( <type-spec> ) [ <select-construct-name> ] + | CLASS IS ( <type-spec> ) [ <select-construct-name> ] + | CLASS DEFAULT [ <select-construct-name> ] + """ + subclass_names = [] + use_names = ['Type_Spec', 'Select_Construct_Name'] + def match(string): + if string[:4].upper()=='TYPE': + line = string[4:].lstrip() + if not line[:2].upper()=='IS': return + line = line[2:].lstrip() + kind = 'TYPE IS' + elif string[:5].upper()=='CLASS': + line = string[5:].lstrip() + if line[:2].upper()=='IS': + line = line[2:].lstrip() + kind = 'CLASS IS' + elif line[:7].upper()=='DEFAULT': + line = line[7:].lstrip() + if line: + if isalnum(line[0]): return + return 'CLASS DEFAULT', None, Select_Construct_Name(line) + return 'CLASS DEFAULT', None, None + else: + return + else: + return + if not line.startswith('('): return + i = line.rfind(')') + if i==-1: return + l = line[1:i].strip() + if not l: return + line = line[i+1:].lstrip() + if line: + return kind, Type_Spec(l), Select_Construct_Name(line) + return kind, Type_Spec(l), None + match = staticmethod(match) + def tostr(self): + s = str(self.items[0]) + if self.items[1] is not None: + s += ' (%s)' % (self.items[0]) + if self.items[2] is not None: + s += ' %s' % (self.items[2]) + return s + +class End_Select_Type_Stmt(EndStmtBase): # R824 + """ + <end-select-type-stmt> = END SELECT [ <select-construct-name> ] + """ + subclass_names = [] + use_names = ['Select_Construct_Name'] + def match(string): return EndStmtBase.match('SELECT',Select_Construct_Name, string, require_stmt_type=True) + match = staticmethod(match) + +class Do_Construct(Base): # R825 + """ + <do-construct> = <block-do-construct> + | <nonblock-do-construct> + """ + subclass_names = ['Block_Do_Construct', 'Nonblock_Do_Construct'] + +class Block_Do_Construct(BlockBase): # R826 + """ + <block-do-construct> = <do-stmt> + <do-block> + <end-do> + """ + subclass_names = [] + use_names = ['Do_Stmt', 'Do_Block', 'End_Do'] + def match(reader): + assert isinstance(reader,FortranReaderBase),`reader` + content = [] + try: + obj = Do_Stmt(reader) + except NoMatchError: + obj = None + if obj is None: return + content.append(obj) + if isinstance(obj, Label_Do_Stmt): + label = str(obj.dolabel) + while 1: + try: + obj = Execution_Part_Construct(reader) + except NoMatchError: + obj = None + if obj is None: break + content.append(obj) + if isinstance(obj, Continue_Stmt) and obj.item.label==label: + return content, + return + raise RuntimeError,'Expected continue stmt with specified label' + else: + obj = End_Do(reader) + content.append(obj) + raise NotImplementedError + return content, + match = staticmethod(match) + + def tofortran(self, tab='', isfix=None): + if not isinstance(self.content[0], Label_Do_Stmt): + return BlockBase.tofortran(tab, isfix) + l = [] + start = self.content[0] + end = self.content[-1] + extra_tab = ' ' + l.append(start.tofortran(tab=tab,isfix=isfix)) + for item in self.content[1:-1]: + l.append(item.tofortran(tab=tab+extra_tab,isfix=isfix)) + if len(self.content)>1: + l.append(end.tofortran(tab=tab,isfix=isfix)) + return '\n'.join(l) + +class Do_Stmt(Base): # R827 + """ + <do-stmt> = <label-do-stmt> + | <nonlabel-do-stmt> + """ + subclass_names = ['Label_Do_Stmt', 'Nonlabel_Do_Stmt'] + +class Label_Do_Stmt(StmtBase): # R828 + """ + <label-do-stmt> = [ <do-construct-name> : ] DO <label> [ <loop-control> ] + """ + subclass_names = [] + use_names = ['Do_Construct_Name', 'Label', 'Loop_Control'] + def match(string): + if string[:2].upper()!='DO': return + line = string[2:].lstrip() + m = pattern.label.match(line) + if m is None: return + label = m.group() + line = line[m.end():].lstrip() + if line: return Label(label), Loop_Control(line) + return Label(label), None + match = staticmethod(match) + def tostr(self): + if self.itens[1] is None: return 'DO %s' % (self.items[0]) + return 'DO %s %s' % self.items + +class Nonlabel_Do_Stmt(StmtBase, WORDClsBase): # R829 + """ + <nonlabel-do-stmt> = [ <do-construct-name> : ] DO [ <loop-control> ] + """ + subclass_names = [] + use_names = ['Do_Construct_Name', 'Loop_Control'] + def match(string): return WORDClsBase.match('DO', Loop_Control, string) + match = staticmethod(match) + +class Loop_Control(Base): # R830 + """ + <loop-control> = [ , ] <do-variable> = <scalar-int-expr> , <scalar-int-expr> [ , <scalar-int-expr> ] + | [ , ] WHILE ( <scalar-logical-expr> ) + """ + subclass_names = [] + use_names = ['Do_Variable', 'Scalar_Int_Expr', 'Scalar_Logical_Expr'] + def match(string): + if string.startswith(','): + line, repmap = string_replace_map(string[1:].lstrip()) + else: + line, repmap = string_replace_map(string) + if line[:5].upper()=='WHILE' and line[5:].lstrip().startswith('('): + l = line[5:].lstrip() + i = l.find(')') + if i!=-1 and i==len(l)-1: + return Scalar_Logical_Expr(repmap(l[1:i].strip())), + if line.count('=')!=1: return + var,rhs = line.split('=') + rhs = [s.strip() for s in rhs.lstrip().split(',')] + if not 2<=len(rhs)<=3: return + return Variable(repmap(var.rstrip())),map(Scalar_Int_Expr, map(repmap,rhs)) + match = staticmethod(match) + def tostr(self): + if len(self.items)==1: return ', WHILE (%s)' % (self.items[0]) + return ', %s = %s' % (self.items[0], ', '.join(map(str,self.items[1]))) + +class Do_Variable(Base): # R831 + """ + <do-variable> = <scalar-int-variable> + """ + subclass_names = ['Scalar_Int_Variable'] + +class Do_Block(Base): # R832 + """ + <do-block> = <block> + """ + subclass_names = ['Block'] + +class End_Do(Base): # R833 + """ + <end-do> = <end-do-stmt> + | <continue-stmt> + """ + subclass_names = ['End_Do_Stmt', 'Continue_Stmt'] + +class End_Do_Stmt(EndStmtBase): # R834 + """ + <end-do-stmt> = END DO [ <do-construct-name> ] + """ + subclass_names = [] + use_names = ['Do_Construct_Name'] + def match(string): return EndStmtBase.match('DO',Do_Construct_Name, string, require_stmt_type=True) + match = staticmethod(match) + +class Nonblock_Do_Construct(Base): # R835 + """ + <nonblock-do-stmt> = <action-term-do-construct> + | <outer-shared-do-construct> + """ + subclass_names = ['Action_Term_Do_Construct', 'Outer_Shared_Do_Construct'] + +class Action_Term_Do_Construct(BlockBase): # R836 + """ + <action-term-do-construct> = <label-do-stmt> + <do-body> + <do-term-action-stmt> + """ + subclass_names = [] + use_names = ['Label_Do_Stmt', 'Do_Body', 'Do_Term_Action_Stmt'] + def match(reader): + content = [] + for cls in [Label_Do_Stmt, Do_Body, Do_Term_Action_Stmt]: + obj = cls(reader) + if obj is None: # todo: restore reader + return + content.append(obj) + return content, + match = staticmethod(match) + +class Do_Body(BlockBase): # R837 + """ + <do-body> = [ <execution-part-construct> ]... + """ + subclass_names = [] + use_names = ['Execution_Part_Construct'] + def match(string): return BlockBase.match(None, [Execution_Part_Construct], None, string) + match = staticmethod(match) + +class Do_Term_Action_Stmt(StmtBase): # R838 + """ + <do-term-action-stmt> = <action-stmt> + C824: <do-term-action-stmt> shall not be <continue-stmt>, <goto-stmt>, <return-stmt>, <stop-stmt>, + <exit-stmt>, <cycle-stmt>, <end-function-stmt>, <end-subroutine-stmt>, + <end-program-stmt>, <arithmetic-if-stmt> + """ + subclass_names = ['Action_Stmt_C824'] + +class Outer_Shared_Do_Construct(BlockBase): # R839 + """ + <outer-shared-do-construct> = <label-do-stmt> + <do-body> + <shared-term-do-construct> + """ + subclass_names = [] + use_names = ['Label_Do_Stmt', 'Do_Body', 'Shared_Term_Do_Construct'] + def match(reader): + content = [] + for cls in [Label_Do_Stmt, Do_Body, Shared_Term_Do_Construct]: + obj = cls(reader) + if obj is None: # todo: restore reader + return + content.append(obj) + return content, + match = staticmethod(match) + +class Shared_Term_Do_Construct(Base): # R840 + """ + <shared-term-do-construct> = <outer-shared-do-construct> + | <inner-shared-do-construct> + """ + subclass_names = ['Outer_Shared_Do_Construct', 'Inner_Shared_Do_Construct'] + +class Inner_Shared_Do_Construct(BlockBase): # R841 + """ + <inner-shared-do-construct> = <label-do-stmt> + <do-body> + <do-term-shared-stmt> + """ + subclass_names = [] + use_names = ['Label_Do_Stmt', 'Do_Body', 'Do_Term_Shared_Stmt'] + + def match(reader): + content = [] + for cls in [Label_Do_Stmt, Do_Body, Do_Term_Shared_Stmt]: + obj = cls(reader) + if obj is None: # todo: restore reader + return + content.append(obj) + return content, + match = staticmethod(match) + +class Do_Term_Shared_Stmt(StmtBase): # R842 + """ + <do-term-shared-stmt> = <action-stmt> + C826: see C824 above. + """ + subclass_names = ['Action_Stmt'] + +class Cycle_Stmt(StmtBase, WORDClsBase): # R843 + """ + <cycle-stmt> = CYCLE [ <do-construct-name> ] + """ + subclass_names = [] + use_names = ['Do_Construct_Name'] + def match(string): return WORDClsBase.match('CYCLE', Do_Construct_Name, string) + match = staticmethod(match) + +class Exit_Stmt(StmtBase, WORDClsBase): # R844 + """ + <exit-stmt> = EXIT [ <do-construct-name> ] + """ + subclass_names = [] + use_names = ['Do_Construct_Name'] + def match(string): return WORDClsBase.match('EXIT', Do_Construct_Name, string) + match = staticmethod(match) + +class Goto_Stmt(StmtBase): # R845 + """ + <goto-stmt> = GO TO <label> + """ + subclass_names = [] + use_names = ['Label'] + def match(string): + if string[:2].upper() != 'GO': return + line = string[2:].lstrip() + if line[:2].upper() != 'TO': return + return Label(line[2:].lstrip()), + match = staticmethod(match) + def tostr(self): return 'GO TO %s' % (self.items[0]) + +class Computed_Goto_Stmt(StmtBase): # R846 + """ + <computed-goto-stmt> = GO TO ( <label-list> ) [ , ] <scalar-int-expr> + """ + subclass_names = [] + use_names = ['Label_List', 'Scalar_Int_Expr'] + def match(string): + if string[:2].upper()!='GO': return + line = string[2:].lstrip() + if line[:2].upper()!='TO': return + line = line[2:].lstrip() + if not line.startswith('('): return + i = line.find(')') + if i==-1: return + lst = line[1:i].strip() + if not lst: return + line = line[i+1:].lstrip() + if line.startswith(','): + line = line[1:].lstrip() + if not line: return + return Label_List(lst), Scalar_Int_Expr(line) + match = staticmethod(match) + def tostr(self): return 'GO TO (%s), %s' % self.items + +class Arithmetic_If_Stmt(StmtBase): # R847 + """ + <arithmetic-if-stmt> = IF ( <scalar-numeric-expr> ) <label> , <label> , <label> + """ + subclass_names = [] + use_names = ['Scalar_Numeric_Expr', 'Label'] + def match(string): + if string[:2].upper() != 'IF': return + line = string[2:].lstrip() + if not line.startswith('('): return + i = line.rfind(')') + if i==-1: return + labels = line[i+1:].lstrip().split(',') + if len(labels) != 3: return + labels = [Label(l.strip()) for l in labels] + return (Scalar_Numeric_Expr(line[1:i].strip()),) + tuple(labels) + match = staticmethod(match) + def tostr(self): return 'IF (%s) %s, %s, %s' % self.items + +class Continue_Stmt(StmtBase, STRINGBase): # R848 + """ + <continue-stmt> = CONTINUE + """ + subclass_names = [] + def match(string): return STRINGBase.match('CONTINUE', string) + match = staticmethod(match) + + +class Stop_Stmt(StmtBase, WORDClsBase): # R849 + """ + <stop-stmt> = STOP [ <stop-code> ] + """ + subclass_names = [] + use_names = ['Stop_Code'] + def match(string): return WORDClsBase.match('STOP', Stop_Code, string) + match = staticmethod(match) + +class Stop_Code(StringBase): # R850 + """ + <stop-code> = <scalar-char-constant> + | <digit> [ <digit> [ <digit> [ <digit> [ <digit> ] ] ] ] + """ + subclass_names = ['Scalar_Char_Constant'] + def match(string): return StringBase.match(pattern.abs_label, string) + match = staticmethod(match) + + +############################################################################### +############################### SECTION 9 #################################### +############################################################################### + +class Io_Unit(StringBase): # R901 + """ + <io-unit> = <file-unit-number> + | * + | <internal-file-variable> + """ + subclass_names = ['File_Unit_Number', 'Internal_File_Variable'] + def match(string): return StringBase.match('*', string) + match = staticmethod(match) + +class File_Unit_Number(Base): # R902 + """ + <file-unit-number> = <scalar-int-expr> + """ + subclass_names = ['Scalar_Int_Expr'] + +class Internal_File_Variable(Base): # R903 + """ + <internal-file-variable> = <char-variable> + C901: <char-variable> shall not be an array section with a vector subscript. + """ + subclass_names = ['Char_Variable'] + +class Open_Stmt(StmtBase, CALLBase): # R904 + """ + <open-stmt> = OPEN ( <connect-spec-list> ) + """ + subclass_names = [] + use_names = ['Connect_Spec_List'] + def match(string): CALLBase.match('OPEN', Connect_Spec_List, string, require_rhs=True) + match = staticmethod(match) + +class Connect_Spec(KeywordValueBase): # R905 + """ + <connect-spec> = [ UNIT = ] <file-unit-number> + | ACCESS = <scalar-default-char-expr> + | ACTION = <scalar-default-char-expr> + | ASYNCHRONOUS = <scalar-default-char-expr> + | BLANK = <scalar-default-char-expr> + | DECIMAL = <scalar-default-char-expr> + | DELIM = <scalar-default-char-expr> + | ENCODING = <scalar-default-char-expr> + | ERR = <label> + | FILE = <file-name-expr> + | FORM = <scalar-default-char-expr> + | IOMSG = <iomsg-variable> + | IOSTAT = <scalar-int-variable> + | PAD = <scalar-default-char-expr> + | POSITION = <scalar-default-char-expr> + | RECL = <scalar-int-expr> + | ROUND = <scalar-default-char-expr> + | SIGN = <scalar-default-char-expr> + | STATUS = <scalar-default-char-expr> + """ + subclass_names = [] + use_names = ['File_Unit_Number', 'Scalar_Default_Char_Expr', 'Label', 'File_Name_Expr', 'Iomsg_Variable', + 'Scalar_Int_Expr', 'Scalar_Int_Variable'] + def match(string): + for (k,v) in [\ + (['ACCESS','ACTION','ASYNCHRONOUS','BLANK','DECIMAL','DELIM','ENCODING', + 'FORM','PAD','POSITION','ROUND','SIGN','STATUS'], Scalar_Default_Char_Expr), + ('ERR', Label), + ('FILE',File_Name_Expr), + ('IOSTAT', Scalar_Int_Variable), + ('IOMSG', Iomsg_Variable), + ('RECL', Scalar_Int_Expr), + ('UNIT', File_Unit_Number), + ]: + try: + obj = KeywordValueBase.match(k, v, string, upper_lhs = True) + except NoMatchError: + obj = None + if obj is not None: return obj + return 'UNIT', File_Unit_Number + match = staticmethod(match) + + +class File_Name_Expr(Base): # R906 + """ + <file-name-expr> = <scalar-default-char-expr> + """ + subclass_names = ['Scalar_Default_Char_Expr'] + +class Iomsg_Variable(Base): # R907 + """ + <iomsg-variable> = <scalar-default-char-variable> + """ + subclass_names = ['Scalar_Default_Char_Variable'] + +class Close_Stmt(StmtBase, CALLBase): # R908 + """ + <close-stmt> = CLOSE ( <close-spec-list> ) + """ + subclass_names = [] + use_names = ['Close_Spec_List'] + def match(string): CALLBase.match('CLOSE', Close_Spec_List, string, require_rhs=True) + match = staticmethod(match) + +class Close_Spec(KeywordValueBase): # R909 + """ + <close-spec> = [ UNIT = ] <file-unit-number> + | IOSTAT = <scalar-int-variable> + | IOMSG = <iomsg-variable> + | ERR = <label> + | STATUS = <scalar-default-char-expr> + """ + subclass_names = [] + use_names = ['File_Unit_Number', 'Scalar_Default_Char_Expr', 'Label', 'Iomsg_Variable', + 'Scalar_Int_Variable'] + def match(string): + for (k,v) in [\ + ('ERR', Label), + ('IOSTAT', Scalar_Int_Variable), + ('IOMSG', Iomsg_Variable), + ('STATUS', Scalar_Default_Char_Expr), + ('UNIT', File_Unit_Number), + ]: + try: + obj = KeywordValueBase.match(k, v, string, upper_lhs = True) + except NoMatchError: + obj = None + if obj is not None: return obj + return 'UNIT', File_Unit_Number(string) + match = staticmethod(match) + +class Read_Stmt(StmtBase): # R910 + """ + <read-stmt> = READ ( <io-control-spec-list> ) [ <input-item-list> ] + | READ <format> [ , <input-item-list> ] + """ + subclass_names = [] + use_names = ['Io_Control_Spec_List', 'Input_Item_List', 'Format'] + +class Write_Stmt(StmtBase): # R911 + """ + <write-stmt> = WRITE ( <io-control-spec-list> ) [ <output-item-list> ] + """ + subclass_names = [] + use_names = ['Io_Control_Spec_List', 'Output_Item_List'] + def match(string): + if string[:5].upper()!='WRITE': return + line = string[5:].lstrip() + if not line.startswith('('): return + line, repmap = string_replace_map(line) + i = line.find(')') + if i==-1: return + l = line[1:i].strip() + if not l: return + l = repmap(l) + if i==len(line)-1: + return Io_Control_Spec_List(l),None + return Io_Control_Spec_List(l), Output_Item_List(repmap(line[i+1:].lstrip())) + match = staticmethod(match) + def tostr(self): + if self.items[1] is None: return 'WRITE(%s)' % (self.items[0]) + return 'WRITE(%s) %s' % tuple(self.items) + +class Print_Stmt(StmtBase): # R912 + """ + <print-stmt> = PRINT <format> [ , <output-item-list> ] + """ + subclass_names = [] + use_names = ['Format', 'Output_Item_List'] + def match(string): + if string[:5].upper()!='PRINT': return + line = string[5:] + if not line: return + c = line[0].upper() + if 'A'<=c<='Z' or c=='_' or '0'<=c<='9': return + line, repmap = string_replace_map(line.lstrip()) + i = line.find(',') + if i==-1: return Format(repmap(line)), None + l = repmap(line[i+1:].lstrip()) + if not l: return + return Format(repmap(line[:i].rstrip())), Output_Item_List(l) + match = staticmethod(match) + def tostr(self): + if self.items[1] is None: return 'PRINT %s' % (self.items[0]) + return 'PRINT %s, %s' % tuple(self.items) + +class Io_Control_Spec_List(SequenceBase): # R913-list + """ + <io-control-spec-list> is a list taking into account C910, C917, C918 + """ + subclass_names = [] + use_names = ['Io_Control_Spec'] + def match(string): + line, repmap = string_replace_map(string) + splitted = line.split(',') + if not splitted: return + lst = [] + for i in range(len(splitted)): + p = splitted[i].strip() + if i==0: + if '=' not in p: p = 'UNIT=%s' % (repmap(p)) + else: p = repmap(p) + elif i==1: + if '=' not in p: + p = repmap(p) + try: + f = Format(p) + # todo: make sure that f is char-expr, if not, raise NoMatchError + p = 'FMT=%s' % (Format(p)) + except NoMatchError: + p = 'NML=%s' % (Namelist_Group_Name(p)) + else: + p = repmap(p) + else: + p = repmap(p) + lst.append(Io_Control_Spec(p)) + return ',', tuple(lst) + match = staticmethod(match) + +class Io_Control_Spec(KeywordValueBase): # R913 + """ + <io-control-spec> = [ UNIT = ] <io-unit> + | [ FMT = ] <format> + | [ NML = ] <namelist-group-name> + | ADVANCE = <scalar-default-char-expr> + | ASYNCHRONOUS = <scalar-char-initialization-expr> + | BLANK = <scalar-default-char-expr> + | DECIMAL = <scalar-default-char-expr> + | DELIM = <scalar-default-char-expr> + | END = <label> + | EOR = <label> + | ERR = <label> + | ID = <scalar-int-variable> + | IOMSG = <iomsg-variable> + | IOSTAT = <scalar-int-variable> + | PAD = <scalar-default-char-expr> + | POS = <scalar-int-expr> + | REC = <scalar-int-expr> + | ROUND = <scalar-default-char-expr> + | SIGN = <scalar-default-char-expr> + | SIZE = <scalar-int-variable> + """ + subclass_names = [] + use_names = ['Io_Unit', 'Format', 'Namelist_Group_Name', 'Scalar_Default_Char_Expr', + 'Scalar_Char_Initialization_Expr', 'Label', 'Scalar_Int_Variable', + 'Iomsg_Variable', 'Scalar_Int_Expr'] + def match(string): + for (k,v) in [\ + (['ADVANCE', 'BLANK', 'DECIMAL', 'DELIM', 'PAD', 'ROUND', 'SIGN'], Scalar_Default_Char_Expr), + ('ASYNCHRONOUS', Scalar_Char_Initialization_Expr), + (['END','EOR','ERR'], Label), + (['ID','IOSTAT','SIZE'], Scalar_Int_Variable), + ('IOMSG', Iomsg_Variable), + (['POS', 'REC'], Scalar_Int_Expr), + ('UNIT', Io_Unit), + ('FMT', Format), + ('NML', Namelist_Group_Name) + ]: + try: + obj = KeywordValueBase.match(k, v, string, upper_lhs = True) + except NoMatchError: + obj = None + if obj is not None: return obj + return + match = staticmethod(match) + +class Format(StringBase): # R914 + """ + <format> = <default-char-expr> + | <label> + | * + """ + subclass_names = ['Label', 'Default_Char_Expr'] + def match(string): return StringBase.match('*', string) + match = staticmethod(match) + +class Input_Item(Base): # R915 + """ + <input-item> = <variable> + | <io-implied-do> + """ + subclass_names = ['Variable', 'Io_Implied_Do'] + +class Output_Item(Base): # R916 + """ + <output-item> = <expr> + | <io-implied-do> + """ + subclass_names = ['Expr', 'Io_Implied_Do'] + +class Io_Implied_Do(Base): # R917 + """ + <io-implied-do> = ( <io-implied-do-object-list> , <io-implied-do-control> ) + """ + subclass_names = [] + use_names = ['Io_Implied_Do_Object_List', 'Io_Implied_Do_Control'] + +class Io_Implied_Do_Object(Base): # R918 + """ + <io-implied-do-object> = <input-item> + | <output-item> + """ + subclass_names = ['Input_Item', 'Output_Item'] + +class Io_Implied_Do_Control(Base): # R919 + """ + <io-implied-do-control> = <do-variable> = <scalar-int-expr> , <scalar-int-expr> [ , <scalar-int-expr> ] + """ + subclass_names = [] + use_names = ['Do_Variable', 'Scalar_Int_Expr'] + +class Dtv_Type_Spec(CALLBase): # R920 + """ + <dtv-type-spec> = TYPE ( <derived-type-spec> ) + | CLASS ( <derived-type-spec> ) + """ + subclass_names = [] + use_names = ['Derived_Type_Spec'] + def match(string): CALLStmt.match(['TYPE', 'CLASS'], Derived_Type_Spec, string, require_rhs=True) + match = staticmethod(match) + +class Wait_Stmt(StmtBase, CALLBase): # R921 + """ + <wait-stmt> = WAIT ( <wait-spec-list> ) + """ + subclass_names = [] + use_names = ['Wait_Spec_List'] + def match(string): return CALLBase.match('WAIT', Wait_Spec_List, string, require_rhs=True) + match = staticmethod(match) + +class Wait_Spec(KeywordValueBase): # R922 + """ + <wait-spec> = [ UNIT = ] <file-unit-number> + | END = <label> + | EOR = <label> + | ERR = <label> + | ID = <scalar-int-expr> + | IOMSG = <iomsg-variable> + | IOSTAT = <scalar-int-variable> + """ + subclass_names = [] + use_names = ['File_Unit_Number', 'Label', 'Scalar_Int_Expr', 'Iomsg_Variable', 'Scalar_Int_Variable'] + def match(string): + for (k,v) in [\ + (['END','EOR','ERR'], Label), + ('IOSTAT', Scalar_Int_Variable), + ('IOMSG', Iomsg_Variable), + ('ID', Scalar_Int_Expr), + ('UNIT', File_Unit_Number), + ]: + try: + obj = KeywordValueBase.match(k, v, string, upper_lhs = True) + except NoMatchError: + obj = None + if obj is not None: return obj + return 'UNIT', File_Unit_Number(string) + + match = staticmethod(match) + +class Backspace_Stmt(StmtBase): # R923 + """ + <backspace-stmt> = BACKSPACE <file-unit-number> + | BACKSPACE ( <position-spec-list> ) + """ + subclass_names = [] + use_names = ['File_Unit_Number', 'Position_Spec_List'] + +class Endfile_Stmt(StmtBase): # R924 + """ + <endfile-stmt> = ENDFILE <file-unit-number> + | ENDFILE ( <position-spec-list> ) + """ + subclass_names = [] + use_names = ['File_Unit_Number', 'Position_Spec_List'] + +class Rewind_Stmt(StmtBase): # R925 + """ + <rewind-stmt> = REWIND <file-unit-number> + | REWIND ( <position-spec-list> ) + """ + subclass_names = [] + use_names = ['File_Unit_Number', 'Position_Spec_List'] + +class Position_Spec(KeywordValueBase): # R926 + """ + <position-spec> = [ UNIT = ] <file-unit-number> + | IOMSG = <iomsg-variable> + | IOSTAT = <scalar-int-variable> + | ERR = <label> + """ + subclass_names = [] + use_names = ['File_Unit_Number', 'Iomsg_Variable', 'Scalar_Int_Variable', 'Label'] + def match(string): + for (k,v) in [\ + ('ERR', Label), + ('IOSTAT', Scalar_Int_Variable), + ('IOMSG', Iomsg_Variable), + ('UNIT', File_Unit_Number), + ]: + try: + obj = KeywordValueBase.match(k, v, string, upper_lhs = True) + except NoMatchError: + obj = None + if obj is not None: return obj + return 'UNIT', File_Unit_Number(string) + match = staticmethod(match) + + +class Flush_Stmt(StmtBase): # R927 + """ + <flush-stmt> = FLUSH <file-unit-number> + | FLUSH ( <position-spec-list> ) + """ + subclass_names = [] + use_names = ['File_Unit_Number', 'Position_Spec_List'] + +class Flush_Spec(KeywordValueBase): # R928 + """ + <flush-spec> = [ UNIT = ] <file-unit-number> + | IOMSG = <iomsg-variable> + | IOSTAT = <scalar-int-variable> + | ERR = <label> + """ + subclass_names = [] + use_names = ['File_Unit_Number', 'Iomsg_Variable', 'Scalar_Int_Variable', 'Label'] + def match(string): + for (k,v) in [\ + ('ERR', Label), + ('IOSTAT', Scalar_Int_Variable), + ('IOMSG', Iomsg_Variable), + ('UNIT', File_Unit_Number), + ]: + try: + obj = KeywordValueBase.match(k, v, string, upper_lhs = True) + except NoMatchError: + obj = None + if obj is not None: return obj + return 'UNIT', File_Unit_Number(string) + match = staticmethod(match) + +class Inquire_Stmt(StmtBase): # R929 + """ + <inquire-stmt> = INQUIRE ( <inquire-spec-list> ) + | INQUIRE ( IOLENGTH = <scalar-int-variable> ) <output-item-list> + """ + subclass_names = [] + use_names = ['Inquire_Spec_List', 'Scalar_Int_Variable', 'Output_Item_List'] + +class Inquire_Spec(KeywordValueBase): # R930 + """ + <inquire-spec> = [ UNIT = ] <file-unit-number> + | FILE = <file-name-expr> + | ACCESS = <scalar-default-char-variable> + | ACTION = <scalar-default-char-variable> + | ASYNCHRONOUS = <scalar-default-char-variable> + | BLANK = <scalar-default-char-variable> + | DECIMAL = <scalar-default-char-variable> + | DELIM = <scalar-default-char-variable> + | DIRECT = <scalar-default-char-variable> + | ENCODING = <scalar-default-char-variable> + | ERR = <label> + | EXIST = <scalar-default-logical-variable> + | FORM = <scalar-default-char-variable> + | FORMATTED = <scalar-default-char-variable> + | ID = <scalar-int-expr> + | IOMSG = <iomsg-variable> + | IOSTAT = <scalar-int-variable> + | NAME = <scalar-default-char-variable> + | NAMED = <scalar-default-logical-variable> + | NEXTREC = <scalar-int-variable> + | NUMBER = <scalar-int-variable> + | OPENED = <scalar-default-logical-variable> + | PAD = <scalar-default-char-variable> + | PENDING = <scalar-default-logical-variable> + | POS = <scalar-int-variable> + | POSITION = <scalar-default-char-variable> + | READ = <scalar-default-char-variable> + | READWRITE = <scalar-default-char-variable> + | RECL = <scalar-int-variable> + | ROUND = <scalar-default-char-variable> + | SEQUENTIAL = <scalar-default-char-variable> + | SIGN = <scalar-default-char-variable> + | SIZE = <scalar-int-variable> + | STREAM = <scalar-default-char-variable> + | UNFORMATTED = <scalar-default-char-variable> + | WRITE = <scalar-default-char-variable> + """ + subclass_names = [] + use_names = ['File_Unit_Number', 'File_Name_Expr', 'Scalar_Default_Char_Variable', + 'Scalar_Default_Logical_Variable', 'Scalar_Int_Variable', 'Scalar_Int_Expr', + 'Label', 'Iomsg_Variable'] + def match(string): + for (k,v) in [\ + (['ACCESS','ACTION','ASYNCHRONOUS', 'BLANK', 'DECIMAL', 'DELIM', + 'DIRECT','ENCODING','FORM','NAME','PAD', 'POSITION','READ','READWRITE', + 'ROUND', 'SEQUENTIAL', 'SIGN','STREAM','UNFORMATTED','WRITE'], + Scalar_Default_Char_Variable), + ('ERR', Label), + (['EXIST','NAMED','PENDING'], Scalar_Default_Logical_Variable), + ('ID', Scalar_Int_Expr), + (['IOSTAT','NEXTREC','NUMBER','POS','RECL','SIZE'], Scalar_Int_Variable), + ('IOMSG', Iomsg_Variable), + ('FILE', File_Name_Expr), + ('UNIT', File_Unit_Number), + ]: + try: + obj = KeywordValueBase.match(k, v, string, upper_lhs = True) + except NoMatchError: + obj = None + if obj is not None: return obj + return 'UNIT', File_Unit_Number(string) + return + match = staticmethod(match) + +############################################################################### +############################### SECTION 10 #################################### +############################################################################### + +class Format_Stmt(StmtBase, WORDClsBase): # R1001 + """ + <format-stmt> = FORMAT <format-specification> + """ + subclass_names = [] + use_names = ['Format_Specification'] + def match(string): WORDClsBase.match('FORMAT', Format_Specification, string, require_cls=True) + match = staticmethod(match) + +class Format_Specification(BracketBase): # R1002 + """ + <format-specification> = ( [ <format-item-list> ] ) + """ + subclass_names = [] + use_names = ['Format_Item_List'] + def match(string): return BracketBase.match('()', Format_Item_List, string, require_cls=False) + match = staticmethod(match) + +class Format_Item(Base): # R1003 + """ + <format-item> = [ <r> ] <data-edit-desc> + | <control-edit-desc> + | <char-string-edit-desc> + | [ <r> ] ( <format-item-list> ) + """ + subclass_names = ['Control_Edit_Desc', 'Char_String_Edit_Desc'] + use_names = ['R', 'Format_Item_List'] + +class R(Base): # R1004 + """ + <r> = <int-literal-constant> + <r> shall be positive and without kind parameter specified. + """ + subclass_names = ['Int_Literal_Constant'] + +class Data_Edit_Desc(Base): # R1005 + """ + <data-edit-desc> = I <w> [ . <m> ] + | B <w> [ . <m> ] + | O <w> [ . <m> ] + | Z <w> [ . <m> ] + | F <w> . <d> + | E <w> . <d> [ E <e> ] + | EN <w> . <d> [ E <e> ] + | ES <w> . <d> [ E <e>] + | G <w> . <d> [ E <e> ] + | L <w> + | A [ <w> ] + | D <w> . <d> + | DT [ <char-literal-constant> ] [ ( <v-list> ) ] + """ + subclass_names = [] + use_names = ['W', 'M', 'D', 'E', 'Char_Literal_Constant', 'V_List'] + def match(string): + c = string[0].upper() + if c in ['I','B','O','Z','D']: + line = string[1:].lstrip() + if '.' in line: + i1,i2 = line.split('.',1) + i1 = i1.rstrip() + i2 = i2.lstrip() + return c, W(i1), M(i2), None + return c,W(line), None, None + if c in ['E','G']: + line = string[1:].lstrip() + if line.count('.')==1: + i1,i2 = line.split('.',1) + i1 = i1.rstrip() + i2 = i2.lstrip() + return c, W(i1), D(i2), None + elif line.count('.')==2: + i1,i2,i3 = line.split('.',2) + i1 = i1.rstrip() + i2 = i2.lstrip() + i3 = i3.lstrip() + return c, W(i1), D(i2), E(i3) + else: + return + if c=='L': + line = string[1:].lstrip() + if not line: return + return c, W(line), None, None + if c=='A': + line = string[1:].lstrip() + if not line: + return c, None, None, None + return c, W(line), None, None + c = string[:2].upper() + if len(c)!=2: return + if c in ['EN','ES']: + line = string[2:].lstrip() + if line.count('.')==1: + i1,i2 = line.split('.',1) + i1 = i1.rstrip() + i2 = i2.lstrip() + return c, W(i1), D(i2), None + elif line.count('.')==2: + i1,i2,i3 = line.split('.',2) + i1 = i1.rstrip() + i2 = i2.lstrip() + i3 = i3.lstrip() + return c, W(i1), D(i2), E(i3) + else: + return + if c=='DT': + line = string[2:].lstrip() + if not line: + return c, None, None, None + lst = None + if line.endswith(')'): + i = line.rfind('(') + if i==-1: return + l = line[i+1:-1].strip() + if not l: return + lst = V_List(l) + line = line[:i].rstrip() + if not line: + return c, None, lst, None + return c, Char_Literal_Constant(line), lst, None + return + match = staticmethod(match) + def tostr(self): + c = selt.items[0] + if c in ['I', 'B', 'O', 'Z', 'F', 'D', 'A', 'L']: + if self.items[2] is None: + return '%s%s' % (c, self.items[1]) + return '%s%s.%s' % (c, self.items[1], self.items[2]) + if c in ['E', 'EN', 'ES', 'G']: + if self.items[3] is None: + return '%s%s.%s' % (c, self.items[1], self.items[2]) + return '%s%s.%sE%s' % (c, self.items[1], self.items[2], self.items[3]) + if c=='DT': + if self.items[1] is None: + if self.items[2] is None: + return c + else: + return '%s(%s)' % (c, self.items[2]) + else: + if self.items[2] is None: + return '%s%s' % (c, self.items[1]) + else: + return '%s%s(%s)' % (c, self.items[1], self.items[2]) + raise NotImpletenetedError,`c` + +class W(Base): # R1006 + """ + <w> = <int-literal-constant> + """ + subclass_names = ['Int_Literal_Constant'] + +class M(Base): # R1007 + """ + <m> = <int-literal-constant> + """ + subclass_names = ['Int_Literal_Constant'] + +class D(Base): # R1008 + """ + <d> = <int-literal-constant> + """ + subclass_names = ['Int_Literal_Constant'] + +class E(Base): # R1009 + """ + <e> = <int-literal-constant> + """ + subclass_names = ['Int_Literal_Constant'] + +class V(Base): # R1010 + """ + <v> = <signed-int-literal-constant> + """ + subclass_names = ['Signed_Int_Literal_Constant'] + +class Control_Edit_Desc(Base): # R1011 + """ + <control-edit-desc> = <position-edit-desc> + | [ <r> ] / + | : + | <sign-edit-desc> + | <k> P + | <blank-interp-edit-desc> + | <round-edit-desc> + | <decimal-edit-desc> + """ + subclass_names = ['Position_Edit_Desc', 'Sign_Edit_Desc', 'Blank_Interp_Edit_Desc', 'Round_Edit_Desc', + 'Decimal_Edit_Desc'] + use_names = ['R', 'K'] + +class K(Base): # R1012 + """ + <k> = <signed-int-literal-constant> + """ + subclass_names = ['Signed_Int_Literal_Constant'] + +class Position_Edit_Desc(Base): # R1013 + """ + <position-edit-desc> = T <n> + | TL <n> + | TR <n> + | <n> X + """ + subclass_names = [] + use_names = ['N'] + +class N(Base): # R1014 + """ + <n> = <int-literal-constant> + """ + subclass_names = ['Int_Literal_Constant'] + +class Sign_Edit_Desc(STRINGBase): # R1015 + """ + <sign-edit-desc> = SS + | SP + | S + """ + subclass_names = [] + def match(string): return STRINGBase.match(['SS','SP','S'], string) + match = staticmethod(match) + +class Blank_Interp_Edit_Desc(STRINGBase): # R1016 + """ + <blank-interp-edit-desc> = BN + | BZ + """ + subclass_names = [] + def match(string): return STRINGBase.match(['BN','BZ',], string) + match = staticmethod(match) + +class Round_Edit_Desc(STRINGBase): # R1017 + """ + <round-edit-desc> = RU + | RD + | RZ + | RN + | RC + | RP + """ + subclass_names = [] + def match(string): return STRINGBase.match(['RU','RD','RZ','RN','RC','RP'], string) + match = staticmethod(match) + +class Decimal_Edit_Desc(STRINGBase): # R1018 + """ + <decimal-edit-desc> = DC + | DP + """ + subclass_names = [] + def match(string): return STRINGBase.match(['DC','DP'], string) + match = staticmethod(match) + +class Char_String_Edit_Desc(Base): # R1019 + """ + <char-string-edit-desc> = <char-literal-constant> + """ + subclass_names = ['Char_Literal_Constant'] + +############################################################################### +############################### SECTION 11 #################################### +############################################################################### + +class Main_Program(Base): # R1101 + """ + <main-program> = [ <program-stmt> ] + [ <specification-part> ] + [ <execution-part> ] + [ <internal-subprogram-part> ] + <end-program-stmt> + """ + subclass_names = [] + use_names = ['Program_Stmt', 'Specification_Part', 'Execution_Part', 'Internal_Subprogram_Part', + 'End_Program_Stmt'] + +class Program_Stmt(StmtBase, WORDClsBase): # R1102 + """ + <program-stmt> = PROGRAM <program-name> + """ + subclass_names = [] + use_names = ['Program_Name'] + def match(string): return WORDClsBase.match('PROGRAM',Program_Name, string, require_cls = True) + match = staticmethod(match) + +class End_Program_Stmt(EndStmtBase): # R1103 + """ + <end-program-stmt> = END [ PROGRAM [ <program-name> ] ] + """ + subclass_names = [] + use_names = ['Program_Name'] + def match(string): return EndStmtBase.match('PROGRAM',Program_Name, string) + match = staticmethod(match) + +class Module(Base): # R1104 + """ + <module> = <module-stmt> + [ <specification-part> ] + [ <module-subprogram-part> ] + <end-module-stmt> + """ + subclass_names = [] + use_names = ['Module_Stmt', 'Specification_Part', 'Module_Subprogram_Part', 'End_Module_Stmt'] + +class Module_Stmt(StmtBase, WORDClsBase): # R1105 + """ + <module-stmt> = MODULE <module-name> + """ + subclass_names = [] + use_names = ['Module_Name'] + def match(string): return WORDClsBase.match('MODULE',Module_Name, string, require_cls = True) + match = staticmethod(match) + +class End_Module_Stmt(EndStmtBase): # R1106 + """ + <end-module-stmt> = END [ MODULE [ <module-name> ] ] + """ + subclass_names = [] + use_names = ['Module_Name'] + def match(string): return EndStmtBase.match('MODULE',Module_Name, string, require_stmt_type=True) + match = staticmethod(match) + +class Module_Subprogram_Part(Base): # R1107 + """ + <module-subprogram-part> = <contains-stmt> + <module-subprogram> + [ <module-subprogram> ]... + """ + subclass_names = [] + use_names = ['Contains_Stmt', 'Module_Subprogram'] + +class Module_Subprogram(Base): # R1108 + """ + <module-subprogram> = <function-subprogram> + | <subroutine-subprogram> + """ + subclass_names = ['Function_Subprogram', 'Subroutine_Subprogram'] + +class Use_Stmt(StmtBase): # R1109 + """ + <use-stmt> = USE [ [ , <module-nature> ] :: ] <module-name> [ , <rename-list> ] + | USE [ [ , <module-nature> ] :: ] <module-name> , ONLY: [ <only-list> ] + """ + subclass_names = [] + use_names = ['Module_Nature', 'Module_Name', 'Rename_List', 'Only_List'] + + def match(string): + if string[:3].upper() != 'USE': return + line = string[3:] + if not line: return + if isalnum(line[0]): return + line = line.lstrip() + i = line.find('::') + nature = None + if i!=-1: + if line.startswith(','): + l = line[1:i].strip() + if not l: return + nature = Module_Nature(l) + line = line[i+2:].lstrip() + if not line: return + i = line.find(',') + if i==-1: return nature, Module_Name(line), '', None + name = line[:i].rstrip() + if not name: return + name = Module_Name(name) + line = line[i+1:].lstrip() + if not line: return + if line[:5].upper()=='ONLY:': + line = line[5:].lstrip() + if not line: + return nature, name, ', ONLY:', None + return nature, name, ', ONLY:', Only_List(line) + return nature, name, ',', Rename_List(line) + match = staticmethod(match) + def tostr(self): + s = 'USE' + if self.items[0] is not None: + s += ', %s' % (self.items[0]) + s += ' :: %s%s' % (self.items[1], self.items[2]) + if self.items[3] is not None: + s += ' %s' % (self.items[3]) + return s + +class Module_Nature(STRINGBase): # R1110 + """ + <module-nature> = INTRINSIC + | NON_INTRINSIC + """ + subclass_names = [] + def match(string): return STRINGBase.match(['INTRINSIC','NON_INTRINSIC'], string) + match = staticmethod(match) + +class Rename(Base): # R1111 + """ + <rename> = <local-name> => <use-name> + | OPERATOR(<local-defined-operator>) => OPERATOR(<use-defined-operator>) + """ + subclass_names = [] + use_names = ['Local_Name', 'Use_Name', 'Local_Defined_Operator', 'Use_Defined_Operator'] + def match(string): + s = string.split('=>', 1) + if len(s) != 2: return + lhs, rhs = s[0].rstrip(), s[1].lstrip() + if not lhs or not rhs: return + if lhs[:8].upper()=='OPERATOR' and rhs[:8].upper()=='OPERATOR': + l = lhs[8:].lstrip() + r = rhs[8:].lstrip() + if l and r and l[0]+l[-1]=='()': + if r[0]+r[-1] != '()': return + l = l[1:-1].strip() + r = r[1:-1].strip() + if not l or not r: return + return 'OPERATOR', Local_Defined_Operator(l), Use_Defined_Operator(r) + return None, Local_Name(lhs), Use_Name(rhs) + match = staticmethod(match) + def tostr(self): + if not self.items[0]: + return '%s => %s' % self.items[1:] + return '%s(%s) => %s(%s)' % (self.items[0], self.items[1],self.items[0], self.items[2]) + +class Only(Base): # R1112 + """ + <only> = <generic-spec> + | <only-use-name> + | <rename> + """ + subclass_names = ['Generic_Spec', 'Only_Use_Name', 'Rename'] + +class Only_Use_Name(Base): # R1113 + """ + <only-use-name> = <name> + """ + subclass_names = ['Name'] + +class Local_Defined_Operator(Base): # R1114 + """ + <local-defined-operator> = <defined-unary-op> + | <defined-binary-op> + """ + subclass_names = ['Defined_Unary_Op', 'Defined_Binary_Op'] + +class Use_Defined_Operator(Base): # R1115 + """ + <use-defined-operator> = <defined-unary-op> + | <defined-binary-op> + """ + subclass_names = ['Defined_Unary_Op', 'Defined_Binary_Op'] + +class Block_Data(Base): # R1116 + """ + <block-data> = <block-data-stmt> + [ <specification-part> ] + <end-block-data-stmt> + """ + subclass_names = [] + use_names = ['Block_Data_Stmt', 'Specification_Part', 'End_Block_Data_Stmt'] + +class Block_Data_Stmt(StmtBase): # R1117 + """ + <block-data-stmt> = BLOCK DATA [ <block-data-name> ] + """ + subclass_names = [] + use_names = ['Block_Data_Name'] + def match(string): + if string[:5].upper()!='BLOCK': return + line = string[5:].lstrip() + if line[:4].upper()!='DATA': return + line = line[4:].lstrip() + if not line: return None, + return Block_Data_Name(line), + match = staticmethod(match) + def tostr(self): + if self.items[0] is None: return 'BLOCK DATA' + return 'BLOCK DATA %s' % self.items + +class End_Block_Data_Stmt(EndStmtBase): # R1118 + """ + <end-block-data-stmt> = END [ BLOCK DATA [ <block-data-name> ] ] + """ + subclass_names = [] + use_names = ['Block_Data_Name'] + def match(string): return EndStmtBase.match('BLOCK DATA',Block_Data_Name, string) + match = staticmethod(match) + +############################################################################### +############################### SECTION 12 #################################### +############################################################################### + + +class Interface_Block(Base): # R1201 + """ + <interface-block> = <interface-stmt> + [ <interface-specification> ]... + <end-interface-stmt> + """ + subclass_names = [] + use_names = ['Interface_Stmt', 'Interface_Specification', 'End_Interface_Stmt'] + +class Interface_Specification(Base): # R1202 + """ + <interface-specification> = <interface-body> + | <procedure-stmt> + """ + subclass_names = ['Interface_Body', 'Procedure_Stmt'] + +class Interface_Stmt(StmtBase): # R1203 + """ + <interface-stmt> = INTERFACE [ <generic-spec> ] + | ABSTRACT INTERFACE + """ + subclass_names = [] + use_names = ['Generic_Spec'] + +class End_Interface_Stmt(EndStmtBase): # R1204 + """ + <end-interface-stmt> = END INTERFACE [ <generic-spec> ] + """ + subclass_names = [] + use_names = ['Generic_Spec'] + def match(string): return EndStmtBase.match('INTERFACE',Generic_Spec, string, require_stmt_type=True) + match = staticmethod(match) + +class Interface_Body(Base): # R1205 + """ + <interface-body> = <function-stmt> + [ <specification-part> ] + <end-function-stmt> + | <subroutine-stmt> + [ <specification-part> ] + <end-subroutine-stmt> + """ + subclass_names = [] + use_names = ['Function_Stmt', 'Specification_Part', 'Subroutine_Stmt', 'End_Function_Stmt', 'End_Subroutine_Stmt'] + +class Procedure_Stmt(StmtBase): # R1206 + """ + <procedure-stmt> = [ MODULE ] PROCEDURE <procedure-name-list> + """ + subclass_names = [] + use_names = ['Procedure_Name_List'] + +class Generic_Spec(Base): # R1207 + """ + <generic-spec> = <generic-name> + | OPERATOR ( <defined-operator> ) + | ASSIGNMENT ( = ) + | <dtio-generic-spec> + """ + subclass_names = ['Generic_Name', 'Dtio_Generic_Spec'] + use_names = ['Defined_Operator'] + +class Dtio_Generic_Spec(Base): # R1208 + """ + <dtio-generic-spec> = READ ( FORMATTED ) + | READ ( UNFORMATTED ) + | WRITE ( FORMATTED ) + | WRITE ( UNFORMATTED ) + """ + subclass_names = [] + +class Import_Stmt(StmtBase, WORDClsBase): # R1209 + """ + <import-stmt> = IMPORT [ :: ] <import-name-list> + """ + subclass_names = [] + use_names = ['Import_Name_List'] + def match(string): return WORDClsBase.match('IMPORT',Import_Name_List,string,check_colons=True, require_cls=True) + match = staticmethod(match) + tostr = WORDClsBase.tostr_a + +class External_Stmt(StmtBase, WORDClsBase): # R1210 + """ + <external-stmt> = EXTERNAL [ :: ] <external-name-list> + """ + subclass_names = [] + use_names = ['External_Name_List'] + def match(string): return WORDClsBase.match('EXTERNAL',External_Name_List,string,check_colons=True, require_cls=True) + match = staticmethod(match) + tostr = WORDClsBase.tostr_a + +class Procedure_Declaration_Stmt(StmtBase): # R1211 + """ + <procedure-declaration-stmt> = PROCEDURE ( [ <proc-interface> ] ) [ [ , <proc-attr-spec> ]... :: ] <proc-decl-list> + """ + subclass_names = [] + use_names = ['Proc_Interface', 'Proc_Attr_Spec', 'Proc_Decl_List'] + +class Proc_Interface(Base): # R1212 + """ + <proc-interface> = <interface-name> + | <declaration-type-spec> + """ + subclass_names = ['Interface_Name', 'Declaration_Type_Spec'] + +class Proc_Attr_Spec(Base): # R1213 + """ + <proc-attr-spec> = <access-spec> + | <proc-language-binding-spec> + | INTENT ( <intent-spec> ) + | OPTIONAL + | SAVE + """ + subclass_names = ['Access_Spec', 'Proc_Language_Binding_Spec'] + use_names = ['Intent_Spec'] + +class Proc_Decl(BinaryOpBase): # R1214 + """ + <proc-decl> = <procedure-entity-name> [ => <null-init> ] + """ + subclass_names = ['Procedure_Entity_Name'] + use_names = ['Null_Init'] + def match(string): return BinaryOpBase.match(Procedure_Entity_Name,'=>', Null_Init, string) + match = staticmethod(match) + +class Interface_Name(Base): # R1215 + """ + <interface-name> = <name> + """ + subclass_names = ['Name'] + +class Intrinsic_Stmt(StmtBase, WORDClsBase): # R1216 + """ + <intrinsic-stmt> = INTRINSIC [ :: ] <intrinsic-procedure-name-list> + """ + subclass_names = [] + use_names = ['Intrinsic_Procedure_Name_List'] + def match(string): return WORDClsBase.match('INTRINSIC',Intrinsic_Procedure_Name_List,string,check_colons=True, require_cls=True) + match = staticmethod(match) + tostr = WORDClsBase.tostr_a + +class Function_Reference(CallBase): # R1217 + """ + <function-reference> = <procedure-designator> ( [ <actual-arg-spec-list> ] ) + """ + subclass_names = [] + use_names = ['Procedure_Designator','Actual_Arg_Spec_List'] + def match(string): + return CallBase.match(Procedure_Designator, Actual_Arg_Spec_List, string) + match = staticmethod(match) + +class Call_Stmt(StmtBase): # R1218 + """ + <call-stmt> = CALL <procedure-designator> [ ( [ <actual-arg-spec-list> ] ) ] + """ + subclass_names = [] + use_names = ['Procedure_Designator', 'Actual_Arg_Spec_List'] + def match(string): + if string[:4].upper()!='CALL': return + line, repmap = string_replace_map(string[4:].lstrip()) + if line.endswith(')'): + i = line.rfind('(') + if i==-1: return + args = repmap(line[i+1:-1].strip()) + if args: + return Procedure_Designator(repmap(line[:i].rstrip())),Actual_Arg_Spec_List(args) + return Procedure_Designator(repmap(line[:i].rstrip())),None + return Procedure_Designator(string[4:].lstrip()),None + match = staticmethod(match) + def tostr(self): + if self.items[1] is None: return 'CALL %s' % (self.items[0]) + return 'CALL %s(%s)' % self.items + +class Procedure_Designator(BinaryOpBase): # R1219 + """ + <procedure-designator> = <procedure-name> + | <proc-component-ref> + | <data-ref> % <binding-name> + """ + subclass_names = ['Procedure_Name','Proc_Component_Ref'] + use_names = ['Data_Ref','Binding_Name'] + def match(string): + return BinaryOpBase.match(\ + Data_Ref, pattern.percent_op.named(), Binding_Name, string) + match = staticmethod(match) + +class Actual_Arg_Spec(KeywordValueBase): # R1220 + """ + <actual-arg-spec> = [ <keyword> = ] <actual-arg> + """ + subclass_names = ['Actual_Arg'] + use_names = ['Keyword'] + def match(string): return KeywordValueBase.match(Keyword, Actual_Arg, string) + match = staticmethod(match) + +class Actual_Arg(Base): # R1221 + """ + <actual-arg> = <expr> + | <variable> + | <procedure-name> + | <proc-component-ref> + | <alt-return-spec> + """ + subclass_names = ['Procedure_Name','Proc_Component_Ref','Alt_Return_Spec', 'Variable', 'Expr'] + +class Alt_Return_Spec(Base): # R1222 + """ + <alt-return-spec> = * <label> + """ + subclass_names = [] + use_names = ['Label'] + def match(string): + if not string.startswith('*'): return + line = string[1:].lstrip() + if not line: return + return Label(line), + match = staticmethod(match) + def tostr(self): return '*%s' % (self.items[0]) + +class Function_Subprogram(BlockBase): # R1223 + """ + <function-subprogram> = <function-stmt> + [ <specification-part> ] + [ <execution-part> ] + [ <internal-subprogram-part> ] + <end-function-stmt> + """ + subclass_names = [] + use_names = ['Function_Stmt', 'Specification_Part', 'Execution_Part', + 'Internal_Subprogram_Part', 'End_Function_Stmt'] + def match(reader): + return BlockBase.match(Function_Stmt, [Specification_Part, Execution_Part, Internal_Subprogram_Part], End_Function_Stmt, reader) + match = staticmethod(match) + +class Function_Stmt(StmtBase): # R1224 + """ + <function-stmt> = [ <prefix> ] FUNCTION <function-name> ( [ <dummy-arg-name-list> ] ) [ <suffix> ] + """ + subclass_names = [] + use_names = ['Prefix','Function_Name','Dummy_Arg_Name_List', 'Suffix'] + +class Proc_Language_Binding_Spec(Base): #1225 + """ + <proc-language-binding-spec> = <language-binding-spec> + """ + subclass_names = ['Language_Binding_Spec'] + +class Dummy_Arg_Name(Base): # R1226 + """ + <dummy-arg-name> = <name> + """ + subclass_names = ['Name'] + +class Prefix(SequenceBase): # R1227 + """ + <prefix> = <prefix-spec> [ <prefix-spec> ].. + """ + subclass_names = ['Prefix_Spec'] + _separator = (' ',re.compile(r'\s+(?=[a-z_])',re.I)) + def match(string): return SequenceBase.match(Prefix._separator, Prefix_Spec, string) + match = staticmethod(match) + +class Prefix_Spec(STRINGBase): # R1228 + """ + <prefix-spec> = <declaration-type-spec> + | RECURSIVE + | PURE + | ELEMENTAL + """ + subclass_names = ['Declaration_Type_Spec'] + def match(string): + return STRINGBase.match(['RECURSIVE', 'PURE', 'ELEMENTAL'], string) + match = staticmethod(match) + +class Suffix(Base): # R1229 + """ + <suffix> = <proc-language-binding-spec> [ RESULT ( <result-name> ) ] + | RESULT ( <result-name> ) [ <proc-language-binding-spec> ] + """ + subclass_names = ['Proc_Language_Binding_Spec'] + use_names = ['Result_Name'] + + def match(string): + if string[:6].upper()=='RESULT': + line = string[6:].lstrip() + if not line.startswith('('): return + i = line.find(')') + if i==-1: return + name = line[1:i].strip() + if not name: return + line = line[i+1:].lstrip() + if line: return Result_Name(name), Proc_Language_Binding_Spec(line) + return Result_Name(name), None + if not string.endswith(')'): return + i = string.rfind('(') + if i==-1: return + name = string[i+1:-1].strip() + if not name: return + line = string[:i].rstrip() + if line[-6:].upper()!='RESULT': return + line = line[:-6].rstrip() + if not line: return + return Result_Name(name), Proc_Language_Binding_Spec(line) + match = staticmethod(match) + def tostr(self): + if self.items[1] is None: + return 'RESULT(%s)' % (self.items[0]) + return 'RESULT(%s) %s' % self.items + +class End_Function_Stmt(EndStmtBase): # R1230 + """ + <end-function-stmt> = END [ FUNCTION [ <function-name> ] ] + """ + subclass_names = [] + use_names = ['Function_Name'] + def match(string): return EndStmtBase.match('FUNCTION',Function_Name, string) + match = staticmethod(match) + +class Subroutine_Subprogram(BlockBase): # R1231 + """ + <subroutine-subprogram> = <subroutine-stmt> + [ <specification-part> ] + [ <execution-part> ] + [ <internal-subprogram-part> ] + <end-subroutine-stmt> + """ + subclass_names = [] + use_names = ['Subroutine_Stmt', 'Specification_Part', 'Execution_Part', + 'Internal_Subprogram_Part', 'End_Subroutine_Stmt'] + def match(reader): + return BlockBase.match(Subroutine_Stmt, [Specification_Part, Execution_Part, Internal_Subprogram_Part], End_Subroutine_Stmt, reader) + match = staticmethod(match) + +class Subroutine_Stmt(StmtBase): # R1232 + """ + <subroutine-stmt> = [ <prefix> ] SUBROUTINE <subroutine-name> [ ( [ <dummy-arg-list> ] ) [ <proc-language-binding-spec> ] ] + """ + subclass_names = [] + use_names = ['Prefix', 'Subroutine_Name', 'Dummy_Arg_List', 'Proc_Language_Binding_Spec'] + def match(string): + line, repmap = string_replace_map(string) + m = pattern.subroutine.search(line) + if m is None: return + prefix = line[:m.start()].rstrip() or None + if prefix is not None: + prefix = Prefix(repmap(prefix)) + line = line[m.end():].lstrip() + m = pattern.name.match(line) + if m is None: return + name = Subroutine_Name(m.group()) + line = line[m.end():].lstrip() + dummy_args = None + if line.startswith('('): + i = line.find(')') + if i==-1: return + dummy_args = line[1:i].strip() or None + if dummy_args is not None: + dummy_args = Dummy_Arg_List(repmap(dummy_args)) + line = line[i+1:].lstrip() + binding_spec = None + if line: + binding_spec = Proc_Language_Binding_Spec(repmap(line)) + return prefix, name, dummy_args, binding_spec + match = staticmethod(match) + def get_name(self): return self.items[1] + def tostr(self): + if self.items[0] is not None: + s = '%s SUBROUTINE %s' % (self.items[0], self.items[1]) + else: + s = 'SUBROUTINE %s' % (self.items[1]) + if self.items[2] is not None: + s += '(%s)' % (self.items[2]) + if self.items[3] is not None: + s += ' %s' % (self.items[3]) + return s + +class Dummy_Arg(StringBase): # R1233 + """ + <dummy-arg> = <dummy-arg-name> + | * + """ + subclass_names = ['Dummy_Arg_Name'] + def match(string): return StringBase.match('*', string) + match = staticmethod(match) + +class End_Subroutine_Stmt(EndStmtBase): # R1234 + """ + <end-subroutine-stmt> = END [ SUBROUTINE [ <subroutine-name> ] ] + """ + subclass_names = [] + use_names = ['Subroutine_Name'] + def match(string): return EndStmtBase.match('SUBROUTINE', Subroutine_Name, string) + match = staticmethod(match) + +class Entry_Stmt(StmtBase): # R1235 + """ + <entry-stmt> = ENTRY <entry-name> [ ( [ <dummy-arg-list> ] ) [ <suffix> ] ] + """ + subclass_names = [] + use_names = ['Entry_Name', 'Dummy_Arg_List', 'Suffix'] + +class Return_Stmt(StmtBase): # R1236 + """ + <return-stmt> = RETURN [ <scalar-int-expr> ] + """ + subclass_names = [] + use_names = ['Scalar_Int_Expr'] + def match(string): + start = string[:6].upper() + if start!='RETURN': return + if len(string)==6: return None, + return Scalar_Int_Expr(string[6:].lstrip()), + match = staticmethod(match) + def tostr(self): + if self.items[0] is None: return 'RETURN' + return 'RETURN %s' % self.items + +class Contains_Stmt(StmtBase, STRINGBase): # R1237 + """ + <contains-stmt> = CONTAINS + """ + subclass_names = [] + def match(string): return STRINGBase.match('CONTAINS',string) + match = staticmethod(match) + +class Stmt_Function_Stmt(StmtBase): # R1238 + """ + <stmt-function-stmt> = <function-name> ( [ <dummy-arg-name-list> ] ) = Scalar_Expr + """ + subclass_names = [] + use_names = ['Function_Name', 'Dummy_Arg_Name_List', 'Scalar_Expr'] + + def match(string): + i = string.find('=') + if i==-1: return + expr = string[i+1:].lstrip() + if not expr: return + line = string[:i].rstrip() + if not line or not line.endswith(')'): return + i = line.find('(') + if i==-1: return + name = line[:i].rstrip() + if not name: return + args = line[i+1:-1].strip() + if args: + return Function_Name(name), Dummy_Arg_Name_List(args), Scalar_Expr(expr) + return Function_Name(name), None, Scalar_Expr(expr) + match = staticmethod(match) + def tostr(self): + if self.items[1] is None: + return '%s () = %s' % (self.items[0], self.items[2]) + return '%s (%s) = %s' % self.items + +############################################################################### +################ GENERATE Scalar_, _List, _Name CLASSES ####################### +############################################################################### + +ClassType = type(Base) +_names = dir() +for clsname in _names: + cls = eval(clsname) + if not (isinstance(cls, ClassType) and issubclass(cls, Base) and not cls.__name__.endswith('Base')): continue + names = getattr(cls, 'subclass_names', []) + getattr(cls, 'use_names', []) + for n in names: + if n in _names: continue + if n.endswith('_List'): + _names.append(n) + n = n[:-5] + #print 'Generating %s_List' % (n) + exec '''\ +class %s_List(SequenceBase): + subclass_names = [\'%s\'] + use_names = [] + def match(string): return SequenceBase.match(r\',\', %s, string) + match = staticmethod(match) +''' % (n, n, n) + elif n.endswith('_Name'): + _names.append(n) + n = n[:-5] + #print 'Generating %s_Name' % (n) + exec '''\ +class %s_Name(Base): + subclass_names = [\'Name\'] +''' % (n) + elif n.startswith('Scalar_'): + _names.append(n) + n = n[7:] + #print 'Generating Scalar_%s' % (n) + exec '''\ +class Scalar_%s(Base): + subclass_names = [\'%s\'] +''' % (n,n) + + +Base_classes = {} +for clsname in dir(): + cls = eval(clsname) + if isinstance(cls, ClassType) and issubclass(cls, Base) and not cls.__name__.endswith('Base'): + Base_classes[cls.__name__] = cls + + +############################################################################### +##################### OPTIMIZE subclass_names tree ############################ +############################################################################### + +if 1: # Optimize subclass tree: + + def _rpl_list(clsname): + if not Base_classes.has_key(clsname): + print 'Not implemented:',clsname + return [] # remove this code when all classes are implemented + cls = Base_classes[clsname] + if cls.__dict__.has_key('match'): return [clsname] + l = [] + for n in getattr(cls,'subclass_names',[]): + l1 = _rpl_list(n) + for n1 in l1: + if n1 not in l: + l.append(n1) + return l + + for cls in Base_classes.values(): + if not hasattr(cls, 'subclass_names'): continue + opt_subclass_names = [] + for n in cls.subclass_names: + for n1 in _rpl_list(n): + if n1 not in opt_subclass_names: opt_subclass_names.append(n1) + if not opt_subclass_names==cls.subclass_names: + #print cls.__name__,':',', '.join(cls.subclass_names),'->',', '.join(opt_subclass_names) + cls.subclass_names[:] = opt_subclass_names + #else: + # print cls.__name__,':',opt_subclass_names + + +# Initialize Base.subclasses dictionary: +for clsname, cls in Base_classes.items(): + subclass_names = getattr(cls, 'subclass_names', None) + if subclass_names is None: + print '%s class is missing subclass_names list' % (clsname) + continue + try: + l = Base.subclasses[clsname] + except KeyError: + Base.subclasses[clsname] = l = [] + for n in subclass_names: + if Base_classes.has_key(n): + l.append(Base_classes[n]) + else: + print '%s not implemented needed by %s' % (n,clsname) + +if 1: + for cls in Base_classes.values(): + subclasses = Base.subclasses.get(cls.__name__,[]) + subclasses_names = [c.__name__ for c in subclasses] + subclass_names = getattr(cls,'subclass_names', []) + use_names = getattr(cls,'use_names',[]) + for n in subclasses_names: + break + if n not in subclass_names: + print '%s needs to be added to %s subclasses_name list' % (n,cls.__name__) + for n in subclass_names: + break + if n not in subclasses_names: + print '%s needs to be added to %s subclass_name list' % (n,cls.__name__) + for n in use_names + subclass_names: + if not Base_classes.has_key(n): + print '%s not defined used by %s' % (n, cls.__name__) + + +#EOF diff --git a/numpy/f2py/lib/parser/__init__.py b/numpy/f2py/lib/parser/__init__.py new file mode 100644 index 000000000..9d707c01f --- /dev/null +++ b/numpy/f2py/lib/parser/__init__.py @@ -0,0 +1,14 @@ +""" +Tools for parsing Fortran 60/77/90/2003 codes into Statement tree. + +Use api module for importing public symbols. + +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: Oct 2006 +----- +""" diff --git a/numpy/f2py/lib/parser/api.py b/numpy/f2py/lib/parser/api.py new file mode 100644 index 000000000..476c142e5 --- /dev/null +++ b/numpy/f2py/lib/parser/api.py @@ -0,0 +1,73 @@ +""" +Public API for Fortran parser. + +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: Oct 2006 +----- +""" + +import Fortran2003 +# import all Statement classes: +from base_classes import EndStatement +from block_statements import * + +# CHAR_BIT is used to convert object bit sizes to byte sizes +from utils import CHAR_BIT + +def get_reader(input, isfree=None, isstrict=None, include_dirs = None): + import os + import re + from readfortran import FortranFileReader, FortranStringReader + from parsefortran import FortranParser + if os.path.isfile(input): + name,ext = os.path.splitext(input) + if ext.lower() in ['.c']: + # get signatures from C file comments starting with `/*f2py` and ending with `*/`. + # TODO: improve parser to take line number offset making line numbers in + # parser messages correct. + f2py_c_comments = re.compile('/[*]\s*f2py\s.*[*]/',re.I | re.M) + f = open(filename,'r') + c_input = '' + for s1 in f2py_c_comments.findall(f.read()): + c_input += s1[2:-2].lstrip()[4:] + '\n' + f.close() + if isfree is None: isfree = True + if isstrict is None: isstrict = True + return parse(c_input, isfree, isstrict, include_dirs) + reader = FortranFileReader(input, + include_dirs = include_dirs) + if isfree is None: isfree = reader.isfree + if isstrict is None: isstrict = reader.isstrict + reader.set_mode(isfree, isstrict) + elif isinstance(input, str): + if isfree is None: isfree = True + if isstrict is None: isstrict = False + reader = FortranStringReader(input, + isfree, isstrict, + include_dirs = include_dirs) + else: + raise TypeError,'Expected string or filename input but got %s' % (type(input)) + return reader + +def parse(input, isfree=None, isstrict=None, include_dirs = None): + """ Parse input and return Statement tree. + + input --- string or filename. + isfree, isstrict --- specify input Fortran format. + Defaults are True, False, respectively, or + determined from input. + include_dirs --- list of include directories. + Default contains current working directory + and the directory of file name. + """ + from parsefortran import FortranParser + reader = get_reader(input, isfree, isstrict, include_dirs) + parser = FortranParser(reader) + parser.parse() + parser.analyze() + return parser.block diff --git a/numpy/f2py/lib/parser/base_classes.py b/numpy/f2py/lib/parser/base_classes.py new file mode 100644 index 000000000..68ea9c24a --- /dev/null +++ b/numpy/f2py/lib/parser/base_classes.py @@ -0,0 +1,819 @@ +""" +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: May 2006 +----- +""" + +__all__ = ['Statement','BeginStatement','EndStatement', 'Variable', + 'AttributeHolder','ProgramBlock'] + +import re +import sys +import copy +from readfortran import Line +from numpy.distutils.misc_util import yellow_text, red_text +from utils import split_comma, specs_split_comma, is_int_literal_constant + +class AttributeHolder: + # copied from symbolic.base module + """ + Defines a object with predefined attributes. Only those attributes + are allowed that are specified as keyword arguments of a constructor. + When an argument is callable then the corresponding attribute will + be read-only and set by the value the callable object returns. + """ + def __init__(self, **kws): + self._attributes = {} + self._readonly = [] + for k,v in kws.items(): + self._attributes[k] = v + if callable(v): + self._readonly.append(k) + return + + def __getattr__(self, name): + if name not in self._attributes: + raise AttributeError,'%s instance has no attribute %r, '\ + 'expected attributes: %s' \ + % (self.__class__.__name__,name, + ','.join(self._attributes.keys())) + value = self._attributes[name] + if callable(value): + value = value() + self._attributes[name] = value + return value + + def __setattr__(self, name, value): + if name in ['_attributes','_readonly']: + self.__dict__[name] = value + return + if name in self._readonly: + raise AttributeError,'%s instance attribute %r is readonly' \ + % (self.__class__.__name__, name) + if name not in self._attributes: + raise AttributeError,'%s instance has no attribute %r, '\ + 'expected attributes: %s' \ + % (self.__class__.__name__,name,','.join(self._attributes.keys())) + self._attributes[name] = value + + def isempty(self): + for k in self._attributes.keys(): + v = getattr(self,k) + 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(): + v = getattr(self, k) + d[k] = v + return d + +def get_base_classes(cls): + bases = () + for c in cls.__bases__: + bases += get_base_classes(c) + return bases + cls.__bases__ + (cls,) + +class Variable: + """ + Variable instance has attributes: + name + typedecl + dimension + attributes + intent + parent - Statement instances defining the variable + """ + def __init__(self, parent, name): + self.parent = parent + self.parents = [parent] + self.name = name + self.typedecl = None + self.dimension = None + self.bounds = None + self.length = None + self.attributes = [] + self.intent = None + self.bind = [] + self.check = [] + self.init = None + + # after calling analyze the following additional attributes are set: + # .is_array: + # rank + # shape + return + + def __repr__(self): + l = [] + for a in ['name','typedecl','dimension','bounds','length','attributes','intent','bind','check','init']: + v = getattr(self,a) + if v: + l.append('%s=%r' % (a,v)) + return 'Variable: ' + ', '.join(l) + + def get_bit_size(self): + typesize = self.typedecl.get_bit_size() + 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) + self.parent = parent + return + + def set_type(self, typedecl): + if self.typedecl is not None: + if not self.typedecl==typedecl: + self.parent.warning(\ + 'variable %r already has type %s,'\ + ' resetting to %s' \ + % (self.name, self.typedecl.tostr(),typedecl.tostr())) + assert typedecl is not None + self.typedecl = typedecl + return + + def set_init(self, expr): + if self.init is not None: + if not self.init==expr: + self.parent.warning(\ + 'variable %r already has initialization %r, '\ + ' resetting to %r' % (self.name, self.expr, expr)) + self.init = expr + return + + def set_dimension(self, dims): + if self.dimension is not None: + if not self.dimension==dims: + self.parent.warning(\ + 'variable %r already has dimension %r, '\ + ' resetting to %r' % (self.name, self.dimension, dims)) + self.dimension = dims + return + + def set_bounds(self, bounds): + if self.bounds is not None: + if not self.bounds==bounds: + self.parent.warning(\ + 'variable %r already has bounds %r, '\ + ' resetting to %r' % (self.name, self.bounds, bounds)) + self.bounds = bounds + return + + def set_length(self, length): + if self.length is not None: + if not self.length==length: + self.parent.warning(\ + 'variable %r already has length %r, '\ + ' resetting to %r' % (self.name, self.length, length)) + self.length = length + return + + known_intent_specs = ['IN','OUT','INOUT','CACHE','HIDE', 'COPY', + 'OVERWRITE', 'CALLBACK', 'AUX', 'C', 'INPLACE', + 'OUT='] + + def set_intent(self, intent): + if self.intent is None: + self.intent = [] + for i in intent: + if i not in self.intent: + if i not in self.known_intent_specs: + self.parent.warning('unknown intent-spec %r for %r'\ + % (i, self.name)) + self.intent.append(i) + return + + known_attributes = ['PUBLIC', 'PRIVATE', 'ALLOCATABLE', 'ASYNCHRONOUS', + 'EXTERNAL', 'INTRINSIC', 'OPTIONAL', 'PARAMETER', + 'POINTER', 'PROTECTED', 'SAVE', 'TARGET', 'VALUE', + 'VOLATILE', 'REQUIRED'] + + def is_intent_in(self): + if not self.intent: return True + if 'HIDE' in self.intent: return False + if 'INPLACE' in self.intent: return False + if 'IN' in self.intent: return True + if 'OUT' in self.intent: return False + if 'INOUT' in self.intent: return False + if 'OUTIN' in self.intent: return False + return True + + def is_intent_inout(self): + if not self.intent: return False + if 'INOUT' in self.intent: + if 'IN' in self.intent or 'HIDE' in self.intent or 'INPLACE' in self.intent: + self.warning('INOUT ignored in INPUT(%s)' % (', '.join(self.intent))) + return False + return True + return False + + def is_intent_hide(self): + if not self.intent: return False + if 'HIDE' in self.intent: return True + if 'OUT' in self.intent: + return 'IN' not in self.intent and 'INPLACE' not in self.intent and 'INOUT' not in self.intent + return False + + def is_intent_inplace(self): return self.intent and 'INPLACE' in self.intent + def is_intent_out(self): return self.intent and 'OUT' in self.intent + def is_intent_c(self): return self.intent and 'C' in self.intent + def is_intent_cache(self): return self.intent and 'CACHE' in self.intent + def is_intent_copy(self): return self.intent and 'COPY' in self.intent + def is_intent_overwrite(self): return self.intent and 'OVERWRITE' in self.intent + def is_intent_callback(self): return self.intent and 'CALLBACK' in self.intent + def is_intent_aux(self): return self.intent and 'AUX' in self.intent + + def is_private(self): + if 'PUBLIC' in self.attributes: return False + if 'PRIVATE' in self.attributes: return True + parent_attrs = self.parent.parent.a.attributes + if 'PUBLIC' in parent_attrs: return False + if 'PRIVATE' in parent_attrs: return True + return + def is_public(self): return not self.is_private() + + def is_allocatable(self): return 'ALLOCATABLE' in self.attributes + def is_external(self): return 'EXTERNAL' in self.attributes + def is_intrinsic(self): return 'INTRINSIC' in self.attributes + def is_parameter(self): return 'PARAMETER' in self.attributes + def is_optional(self): return 'OPTIONAL' in self.attributes and 'REQUIRED' not in self.attributes and not self.is_intent_hide() + def is_required(self): return self.is_optional() and not self.is_intent_hide() + def is_pointer(self): return 'POINTER' in self.attributes + + def is_array(self): return not not (self.bounds or self.dimension) + def is_scalar(self): return not self.is_array() + + def update(self, *attrs): + attributes = self.attributes + if len(attrs)==1 and isinstance(attrs[0],(tuple,list)): + attrs = attrs[0] + for attr in attrs: + lattr = attr.lower() + uattr = attr.upper() + if lattr.startswith('dimension'): + assert self.dimension is None, `self.dimension,attr` + l = attr[9:].lstrip() + assert l[0]+l[-1]=='()',`l` + self.set_dimension(split_comma(l[1:-1].strip(), self.parent.item)) + continue + if lattr.startswith('intent'): + l = attr[6:].lstrip() + assert l[0]+l[-1]=='()',`l` + self.set_intent(specs_split_comma(l[1:-1].strip(), + self.parent.item, upper=True)) + continue + if lattr.startswith('bind'): + l = attr[4:].lstrip() + assert l[0]+l[-1]=='()',`l` + self.bind = specs_split_comma(l[1:-1].strip(), self.parent.item, + upper = True) + continue + if lattr.startswith('check'): + l = attr[5:].lstrip() + assert l[0]+l[-1]=='()',`l` + self.check.extend(split_comma(l[1:-1].strip()), self.parent.item) + continue + if uattr not in attributes: + if uattr not in self.known_attributes: + self.parent.warning('unknown attribute %r' % (attr)) + attributes.append(uattr) + return + + def __str__(self): + s = '' + 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))) + if self.intent is not None: + a.append('INTENT(%s)' % (', '.join(self.intent))) + if self.bind: + a.append('BIND(%s)' % (', '.join(self.bind))) + if self.check: + a.append('CHECK(%s)' % (', '.join(self.check))) + if a: + s += ', ' + ', '.join(a) + ' :: ' + s += self.name + if self.bounds: + s += '(%s)' % (', '.join([':'.join(spec) for spec in self.bounds])) + if self.length: + if is_int_literal_constant(self.length): + s += '*%s' % (self.length) + else: + s += '*(%s)' % (self.length) + if self.init: + s += ' = ' + self.init + return s + + def get_array_spec(self): + assert self.is_array(),'array_spec is available only for arrays' + if self.bounds: + if self.dimension: + self.parent.warning('both bounds=%r and dimension=%r are defined, ignoring dimension.' % (self.bounds, self.dimension)) + array_spec = self.bounds + else: + array_spec = self.dimension + return array_spec + + def is_deferred_shape_array(self): + if not self.is_array(): return False + return self.is_allocatable() or self.is_pointer() + + def is_assumed_size_array(self): + if not self.is_array(): return False + return self.get_array_spec()[-1][-1]=='*' + + def is_assumed_shape_array(self): + if not self.is_array(): return False + if self.is_deferred_shape_array(): return False + for spec in self.get_array_spec(): + if not spec[-1]: return True + return False + + def is_explicit_shape_array(self): + if not self.is_array(): return False + if self.is_deferred_shape_array(): return False + for spec in self.get_array_spec(): + if not spec[-1] or spec[-1] == '*': return False + return True + + def is_allocatable_array(self): + return self.is_array() and self.is_allocatable() + + def is_array_pointer(self): + return self.is_array() and self.is_pointer() + + def analyze(self): + typedecl = self.get_typedecl() + if self.is_array(): + array_spec = self.get_array_spec() + self.rank = len(array_spec) + if self.is_deferred_shape_array(): # a(:,:) + pass + elif self.is_explicit_shape_array(): + shape = [] + for spec in array_spec: + if len(spec)==1: + shape.append(spec[0]) + else: + shape.append(spec[1]-spec[0]) + self.shape = shape + return + +class ProgramBlock: + pass + +class Statement: + """ + Statement instance has attributes: + parent - Parent BeginStatement or FortranParser instance + item - Line instance containing the statement line + 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 + if item is not None: + self.reader = item.reader + else: + self.reader = parent.reader + 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 + + # 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 + self.ignore = False + + # attribute a will hold analyze information. + a_dict = {} + for cls in get_base_classes(self.__class__): + if hasattr(cls,'a'): + a_dict.update(copy.deepcopy(cls.a.todict())) + self.a = AttributeHolder(**a_dict) + if hasattr(self.__class__,'a'): + assert self.a is not self.__class__.a + + self.process_item() + + 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(depth-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,isfix=None): + if isfix is None: isfix = self.reader.isfix + if isfix: + tab = ' '*6 + else: + tab = '' + p = self.parent + while isinstance(p, Statement): + tab += ' ' + p = p.parent + if deindent: + tab = tab[:-2] + if self.item is None: + return tab + s = self.item.label + if colon is None: + if isfix: + colon = '' + else: + colon = ':' + if s: + c = '' + if isfix: + c = ' ' + tab = tab[len(c+s)+len(colon):] + if not tab: tab = ' ' + tab = c + s + colon + tab + return tab + + def __str__(self): + return self.tofortran() + + def asfix(self): + lines = [] + for line in self.tofortran(isfix=True).split('\n'): + if len(line)>72 and line[0]==' ': + lines.append(line[:72]+'&\n &') + line = line[72:] + while len(line)>66: + lines.append(line[:66]+'&\n &') + line = line[66:] + lines.append(line+'\n') + else: lines.append(line+'\n') + return ''.join(lines).replace('\n &\n','\n') + + def format_message(self, kind, message): + 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): + print >> stream, message + stream.flush() + return + + def error(self, message): + message = self.format_message('ERROR', red_text(message)) + self.show_message(message) + return + + def warning(self, message): + message = self.format_message('WARNING', yellow_text(message)) + self.show_message(message) + return + + def info(self, message): + message = self.format_message('INFO', message) + self.show_message(message) + return + + def analyze(self): + self.warning('nothing analyzed') + return + + def get_variable(self, name): + """ 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> + + BeginStatement instances have additional attributes: + name + blocktype + + Block instance has attributes: + content - list of Line or Statement instances + name - name of the block, unnamed blocks are named + 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 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 = [] + self.get_item = parent.get_item # get line function + self.put_item = parent.put_item # put line function + if not hasattr(self, 'blocktype'): + self.blocktype = self.__class__.__name__.lower() + if not hasattr(self, 'name'): + # process_item may change this + self.name = '__'+self.blocktype.upper()+'__' + Statement.__init__(self, parent, item) + return + + def tostr(self): + return self.blocktype.upper() + ' '+ self.name + + def tofortran(self, isfix=None): + l=[self.get_indent_tab(colon=':', isfix=isfix) + self.tostr()] + for c in self.content: + l.append(c.tofortran(isfix=isfix)) + 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 + """ + item = self.item + if item is None: return + self.fill() + return + + def fill(self, end_flag = False): + """ + Fills blocks content until the end of block statement. + """ + + mode = self.reader.mode + classes = self.get_classes() + self.classes = [cls for cls in classes if mode in cls.modes] + self.pyf_classes = [cls for cls in classes if 'pyf' in cls.modes] + + item = self.get_item() + while item is not None: + if isinstance(item, Line): + if self.process_subitem(item): + end_flag = True + break + item = self.get_item() + + if not end_flag: + self.warning('failed to find the end of block') + return + + def process_subitem(self, item): + """ + Check is item is blocks start statement, if it is, read the block. + + Return True to stop adding items to given block. + """ + line = item.get_line() + + # First check for the end of block + cls = self.end_stmt_cls + if cls.match(line): + stmt = cls(self, item) + if stmt.isvalid: + self.content.append(stmt) + return True + + if item.is_f2py_directive: + classes = self.pyf_classes + else: + classes = self.classes + + # Look for statement match + for cls in classes: + if cls.match(line): + stmt = cls(self, item) + if stmt.isvalid: + if not stmt.ignore: + self.content.append(stmt) + return False + # item may be cloned that changes the items line: + line = item.get_line() + + # Check if f77 code contains inline comments or other f90 + # constructs that got undetected by get_source_info. + if item.reader.isfix77: + i = line.find('!') + if i != -1: + message = item.reader.format_message(\ + 'WARNING', + 'no parse pattern found for "%s" in %r block'\ + ' maybe due to inline comment.'\ + ' Trying to remove the comment.'\ + % (item.get_line(),self.__class__.__name__), + item.span[0], item.span[1]) + # .. but at the expense of loosing the comment. + self.show_message(message) + newitem = item.copy(line[:i].rstrip()) + return self.process_subitem(newitem) + + # try fix90 statement classes + f77_classes = self.classes + classes = [] + for cls in self.get_classes(): + if 'fix90' in cls.modes and cls not in f77_classes: + classes.append(cls) + if classes: + message = item.reader.format_message(\ + 'WARNING', + 'no parse pattern found for "%s" in %r block'\ + ' maybe due to strict f77 mode.'\ + ' Trying f90 fix mode patterns..'\ + % (item.get_line(),self.__class__.__name__), + item.span[0], item.span[1]) + self.show_message(message) + + item.reader.set_mode(False, False) + self.classes = classes + + r = BeginStatement.process_subitem(self, item) + if r is None: + # restore f77 fix mode + self.classes = f77_classes + item.reader.set_mode(False, True) + else: + message = item.reader.format_message(\ + 'INFORMATION', + 'The f90 fix mode resolved the parse pattern issue.'\ + ' Setting reader to f90 fix mode.', + item.span[0], item.span[1]) + self.show_message(message) + # set f90 fix mode + self.classes = f77_classes + classes + self.reader.set_mode(False, False) + return r + + self.handle_unknown_item(item) + return + + def handle_unknown_item(self, item): + message = item.reader.format_message(\ + 'WARNING', + 'no parse pattern found for "%s" in %r block.'\ + % (item.get_line(),self.__class__.__name__), + item.span[0], item.span[1]) + self.show_message(message) + self.content.append(item) + #sys.exit() + return + + def analyze(self): + for stmt in self.content: + stmt.analyze() + return + +class EndStatement(Statement): + """ + END [<blocktype> [<name>]] + + EndStatement instances have additional attributes: + name + blocktype + """ + _repr_attr_names = ['blocktype','name'] + Statement._repr_attr_names + + def __init__(self, parent, item): + if not hasattr(self, 'blocktype'): + self.blocktype = self.__class__.__name__.lower()[3:] + Statement.__init__(self, parent, item) + + def process_item(self): + item = self.item + line = item.get_line().replace(' ','')[3:] + blocktype = self.blocktype + if line.lower().startswith(blocktype): + line = line[len(blocktype):].strip() + else: + if line: + # not the end of expected block + line = '' + self.isvalid = False + if line: + if not line==self.parent.name: + self.warning(\ + 'expected the end of %r block but got the end of %r, skipping.'\ + % (self.parent.name, line)) + self.isvalid = False + self.name = self.parent.name + + def analyze(self): + return + + def get_indent_tab(self,colon=None,deindent=False,isfix=None): + return Statement.get_indent_tab(self, colon=colon, deindent=True,isfix=isfix) + + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'END %s %s'\ + % (self.blocktype.upper(),self.name or '') diff --git a/numpy/f2py/lib/parser/block_statements.py b/numpy/f2py/lib/parser/block_statements.py new file mode 100644 index 000000000..b3d29c911 --- /dev/null +++ b/numpy/f2py/lib/parser/block_statements.py @@ -0,0 +1,1229 @@ +""" +Fortran block statements. + +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: May 2006 +----- +""" + +__all__ = ['BeginSource','Module','PythonModule','Program','BlockData','Interface', + 'Subroutine','Function','Select','WhereConstruct','ForallConstruct', + 'IfThen','If','Do','Associate','TypeDecl','Enum', + 'EndSource','EndModule','EndPythonModule','EndProgram','EndBlockData','EndInterface', + 'EndSubroutine','EndFunction','EndSelect','EndWhere','EndForall', + 'EndIfThen','EndDo','EndAssociate','EndType','EndEnum', + ] + +import re +import sys + +from base_classes import BeginStatement, EndStatement, Statement,\ + AttributeHolder, ProgramBlock, Variable +from readfortran import Line +from utils import filter_stmts, parse_bind, parse_result, AnalyzeError, is_name + +class HasImplicitStmt: + + a = AttributeHolder(implicit_rules = {}) + + 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 while getting %r type' % (name) + l = name[0].lower() + if implicit_rules.has_key(l): + return implicit_rules[l] + # default rules: + if l in 'ijklmn': + l = 'default_integer' + else: + l = 'default_real' + t = implicit_rules.get(l, None) + if t is None: + if l[8:]=='real': + implicit_rules[l] = t = Real(self, self.item.copy('real')) + else: + implicit_rules[l] = t = Integer(self, self.item.copy('integer')) + return t + + def topyf(self, tab=' '): + implicit_rules = self.a.implicit_rules + if implicit_rules is None: + return tab + 'IMPLICIT NONE\n' + items = {} + for c,t in implicit_rules.items(): + if c.startswith('default'): + continue + st = t.tostr() + if items.has_key(st): + items[st].append(c) + else: + items[st] = [c] + if not items: + return tab + '! default IMPLICIT rules apply\n' + s = 'IMPLICIT' + ls = [] + for st,l in items.items(): + l.sort() + ls.append(st + ' (%s)' % (', '.join(l))) + s += ' ' + ', '.join(ls) + return tab + s + '\n' + +class HasUseStmt: + + a = AttributeHolder(use = {}, + use_provides = {}) + + def get_entity(self, name): + for modname, modblock in self.top.a.module.items(): + for stmt in modblock.content: + if getattr(stmt,'name','') == name: + return stmt + return + + def topyf(self, tab=' '): + sys.stderr.write('HasUseStmt.topyf not implemented\n') + return '' + +class AccessSpecs: + + a = AttributeHolder(private_id_list = [], public_id_list = []) + + def topyf(self, tab=' '): + private_list = self.a.private_id_list + public_list = self.a.public_id_list + l = [] + if '' in private_list: l.append(tab + 'PRIVATE\n') + if '' in public_list: l.append(tab + 'PUBLIC\n') + for a in private_list: + if not a: continue + l.append(tab + 'PRIVATE :: %s\n' % (a)) + for a in public_list: + if not a: continue + l.append(tab + 'PUBLIC :: %s\n' % (a)) + return ''.join(l) + +class HasVariables: + + 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='', only_variables = None): + s = '' + if only_variables is None: + only_variables = self.a.variables.keys() + for name in only_variables: + var = self.a.variables[name] + s += tab + str(var) + '\n' + return s + +class HasTypeDecls: + + a = AttributeHolder(type_decls = {}) + + def topyf(self, tab=''): + s = '' + for name, stmt in self.a.type_decls.items(): + 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) + return type_decl + +class HasAttributes: + + known_attributes = [] + a = AttributeHolder(attributes = []) + + def topyf(self, tab=''): + s = '' + for attr in self.a.attributes: + s += tab + attr + '\n' + return s + + 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 not known_attributes(uattr): + self.warning('unknown attribute %r' % (attr)) + attributes.append(uattr) + return + +class HasModuleProcedures: + + a = AttributeHolder(module_procedures = []) + +# File block + +class EndSource(EndStatement): + """ + Dummy End statement for BeginSource. + """ + match = staticmethod(lambda s: False) + +class BeginSource(BeginStatement): + """ + Fortran source content. + """ + match = staticmethod(lambda s: True) + end_stmt_cls = EndSource + a = AttributeHolder(module = {}, + external_subprogram = {}, + blockdata = {}, + ) + + def tostr(self): + return '!' + self.blocktype.upper() + ' '+ self.name + + def process_item(self): + self.name = self.reader.name + self.top = self + self.fill(end_flag = True) + return + + def analyze(self): + for stmt in self.content: + if isinstance(stmt, Module): + stmt.analyze() + self.a.module[stmt.name] = stmt + elif isinstance(stmt, SubProgramStatement): + stmt.analyze() + self.a.external_subprogram[stmt.name] = stmt + elif isinstance(stmt, BlockData): + stmt.analyze() + self.a.blockdata[stmt.name] = stmt + else: + stmt.analyze() + return + + def get_classes(self): + if self.reader.ispyf: + return [PythonModule] + program_unit + return program_unit + + def process_subitem(self, item): + # MAIN block does not define start/end line conditions, + # so it should never end until all lines are read. + # However, sometimes F77 programs lack the PROGRAM statement, + # and here we fix that: + if self.reader.isfix77: + line = item.get_line() + if line=='end': + message = item.reader.format_message(\ + 'WARNING', + 'assuming the end of undefined PROGRAM statement', + item.span[0],item.span[1]) + print >> sys.stderr, message + p = Program(self) + p.content.extend(self.content) + p.content.append(EndProgram(p,item)) + self.content[:] = [p] + return + return BeginStatement.process_subitem(self, item) + + def topyf(self, tab=''): # XXXX + s = '' + for name, stmt in self.a.module.items(): + s += stmt.topyf(tab=tab) + for name, stmt in self.a.external_subprogram.items(): + s += stmt.topyf(tab=tab) + for name, stmt in self.a.blockdata.items(): + s += stmt.topyf(tab=tab) + return s +# Module + +class EndModule(EndStatement): + match = re.compile(r'end(\s*module\s*\w*|)\Z', re.I).match + +class Module(BeginStatement, HasAttributes, + HasImplicitStmt, HasUseStmt, HasVariables, + HasTypeDecls, AccessSpecs): + """ + MODULE <name> + .. + END [MODULE [name]] + """ + match = re.compile(r'module\s*\w+\Z', re.I).match + end_stmt_cls = EndModule + + a = AttributeHolder(module_subprogram = {}, + module_provides = {}, # all symbols that are public and so + # can be imported via USE statement + # by other blocks + module_interface = {} + ) + + known_attributes = ['PUBLIC', 'PRIVATE'] + + def get_classes(self): + return access_spec + specification_part + module_subprogram_part + + def process_item(self): + name = self.item.get_line().replace(' ','')[len(self.blocktype):].strip() + self.name = name + return BeginStatement.process_item(self) + + def get_provides(self): + return self.a.module_provides + + def get_interface(self): + return self.a.module_interface + + def analyze(self): + content = self.content[:] + + while content: + stmt = content.pop(0) + if isinstance(stmt, Contains): + for stmt in filter_stmts(content, SubProgramStatement): + stmt.analyze() + self.a.module_subprogram[stmt.name] = stmt + stmt = content.pop(0) + assert isinstance(stmt, EndModule),`stmt` + continue + stmt.analyze() + + 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 += AccessSpecs.topyf(self, tab=tab+' ') + s += HasAttributes.topyf(self, tab=tab+' ') + s += HasTypeDecls.topyf(self, tab=tab+' ') + s += HasVariables.topyf(self, tab=tab+' ') + for name, stmt in self.a.module_interface.items(): + s += stmt.topyf(tab=tab+' ') + s += tab + ' CONTAINS\n' + for name, stmt in self.a.module_subprogram.items(): + s += stmt.topyf(tab=tab+' ') + s += tab + 'END MODULE ' + self.name + '\n' + return s + +# Python Module + +class EndPythonModule(EndStatement): + match = re.compile(r'end(\s*python\s*module\s*\w*|)\Z', re.I).match + +class PythonModule(BeginStatement, HasImplicitStmt, HasUseStmt): + """ + PYTHON MODULE <name> + .. + END [PYTHON MODULE [name]] + """ + modes = ['pyf'] + match = re.compile(r'python\s*module\s*\w+\Z', re.I).match + end_stmt_cls = EndPythonModule + + def get_classes(self): + return [Interface, Function, Subroutine, Module] + + def process_item(self): + self.name = self.item.get_line().replace(' ','')\ + [len(self.blocktype):].strip() + return BeginStatement.process_item(self) + +# Program + +class EndProgram(EndStatement): + """ + END [PROGRAM [name]] + """ + match = re.compile(r'end(\s*program\s*\w*|)\Z', re.I).match + +class Program(BeginStatement, ProgramBlock, + #HasAttributes, # XXX: why Program needs .attributes? + HasImplicitStmt, HasUseStmt, AccessSpecs): + """ PROGRAM [name] + """ + match = re.compile(r'program\s*\w*\Z', re.I).match + end_stmt_cls = EndProgram + + def get_classes(self): + return specification_part + execution_part + internal_subprogram_part + + def process_item(self): + if self.item is not None: + name = self.item.get_line().replace(' ','')\ + [len(self.blocktype):].strip() + if name: + self.name = name + return BeginStatement.process_item(self) + +# BlockData + +class EndBlockData(EndStatement): + """ + END [ BLOCK DATA [ <block-data-name> ] ] + """ + match = re.compile(r'end(\s*block\s*data\s*\w*|)\Z', re.I).match + blocktype = 'blockdata' + +class BlockData(BeginStatement, HasImplicitStmt, HasUseStmt, + HasVariables, AccessSpecs): + """ + BLOCK DATA [ <block-data-name> ] + """ + end_stmt_cls = EndBlockData + match = re.compile(r'block\s*data\s*\w*\Z', re.I).match + + def process_item(self): + self.name = self.item.get_line()[5:].lstrip()[4:].lstrip() + return BeginStatement.process_item(self) + + def get_classes(self): + return specification_part + +# Interface + +class EndInterface(EndStatement): + match = re.compile(r'end\s*interface\s*\w*\Z', re.I).match + blocktype = 'interface' + +class Interface(BeginStatement, HasImplicitStmt, HasUseStmt, + HasModuleProcedures, AccessSpecs + ): + """ + INTERFACE [<generic-spec>] | ABSTRACT INTERFACE + END INTERFACE [<generic-spec>] + + <generic-spec> = <generic-name> + | OPERATOR ( <defined-operator> ) + | ASSIGNMENT ( = ) + | <dtio-generic-spec> + <dtio-generic-spec> = READ ( FORMATTED ) + | READ ( UNFORMATTED ) + | WRITE ( FORMATTED ) + | WRITE ( UNFORMATTED ) + + """ + modes = ['free90', 'fix90', 'pyf'] + match = re.compile(r'(interface\s*(\w+\s*\(.*\)|\w*)|abstract\s*interface)\Z',re.I).match + end_stmt_cls = EndInterface + blocktype = 'interface' + + a = AttributeHolder(interface_provides = {}) + + def get_classes(self): + l = intrinsic_type_spec + interface_specification + if self.reader.mode=='pyf': + return [Subroutine, Function] + l + return l + + def process_item(self): + line = self.item.get_line() + self.isabstract = line.startswith('abstract') + if self.isabstract: + self.generic_spec = '' + else: + self.generic_spec = line[len(self.blocktype):].strip() + self.name = self.generic_spec # XXX + return BeginStatement.process_item(self) + + def tostr(self): + if self.isabstract: + 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) + + if self.parent.a.variables.has_key(self.name): + var = self.parent.a.variables.pop(self.name) + self.update_attributes(var.attributes) + + parent_interface = self.parent.get_interface() + if parent_interface.has_key(self.name): + p = parent_interface[self.name] + last = p.content.pop() + assert isinstance(last,EndInterface),`last.__class__` + p.content += self.content + p.update_attributes(self.a.attributes) + else: + parent_interface[self.name] = self + return + + def topyf(self, tab=''): + s = tab + self.tostr() + '\n' + s += HasImplicitStmt.topyf(self, tab=tab+' ') + s += HasAttributes.topyf(self, tab=tab+' ') + s += HasUseStmt.topyf(self, tab=tab+' ') + s += tab + 'END' + self.tostr() + '\n' + return s + +# Subroutine + +class SubProgramStatement(BeginStatement, ProgramBlock, + HasImplicitStmt, HasAttributes, + HasUseStmt, + HasVariables, HasTypeDecls, AccessSpecs + ): + """ + [ <prefix> ] <FUNCTION|SUBROUTINE> <name> [ ( <args> ) ] [ <suffix> ] + """ + + a = AttributeHolder(internal_subprogram = {}) + + def process_item(self): + clsname = self.__class__.__name__.lower() + item = self.item + line = item.get_line() + m = self.match(line) + i = line.lower().find(clsname) + assert i!=-1,`clsname, line` + self.prefix = line[:i].rstrip() + self.name = line[i:m.end()].lstrip()[len(clsname):].strip() + line = line[m.end():].lstrip() + args = [] + if line.startswith('('): + i = line.find(')') + assert i!=-1,`line` + line2 = item.apply_map(line[:i+1]) + for a in line2[1:-1].split(','): + a=a.strip() + if not a: continue + args.append(a) + line = line[i+1:].lstrip() + suffix = item.apply_map(line) + self.bind, suffix = parse_bind(suffix, item) + self.result = None + if isinstance(self, Function): + self.result, suffix = parse_result(suffix, item) + if suffix: + assert self.bind is None,`self.bind` + self.bind, suffix = parse_result(suffix, item) + if self.result is None: + self.result = self.name + assert not suffix,`suffix` + self.args = args + self.typedecl = None + return BeginStatement.process_item(self) + + def tostr(self): + clsname = self.__class__.__name__.upper() + s = '' + if self.prefix: + s += self.prefix + ' ' + if self.typedecl is not None: + assert isinstance(self, Function),`self.__class__.__name__` + s += self.typedecl.tostr() + ' ' + s += clsname + suf = '' + if self.result and self.result!=self.name: + suf += ' RESULT ( %s )' % (self.result) + if self.bind: + suf += ' BIND ( %s )' % (', '.join(self.bind)) + return '%s %s(%s)%s' % (s, self.name,', '.join(self.args),suf) + + def get_classes(self): + return f2py_stmt + specification_part + execution_part \ + + internal_subprogram_part + + def analyze(self): + content = self.content[:] + + if self.prefix: + self.update_attributes(prefix.upper().split()) + + variables = self.a.variables + for a in self.args: + assert not variables.has_key(a) + assert is_name(a) + variables[a] = Variable(self, a) + + if isinstance(self, Function): + var = variables[self.result] = Variable(self, self.result) + if self.typedecl is not None: + var.set_type(self.typedecl) + + while content: + stmt = content.pop(0) + if isinstance(stmt, Contains): + for stmt in filter_stmts(content, SubProgramStatement): + stmt.analyze() + self.a.internal_subprogram[stmt.name] = stmt + stmt = content.pop(0) + assert isinstance(stmt, self.end_stmt_cls),`stmt` + elif isinstance(stmt, self.end_stmt_cls): + continue + else: + stmt.analyze() + + 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=''): + s = tab + self.__class__.__name__.upper() + s += ' ' + self.name + ' (%s)' % (', '.join(self.args)) + if isinstance(self, Function) and self.result != self.name: + s += ' RESULT (%s)' % (self.result) + s += '\n' + s += HasImplicitStmt.topyf(self, tab=tab+' ') + s += AccessSpecs.topyf(self, tab=tab+' ') + s += HasTypeDecls.topyf(self, tab=tab+' ') + s += HasVariables.topyf(self, tab=tab+' ', only_variables = self.args) + s += tab + 'END ' + self.__class__.__name__.upper() + ' ' + self.name + '\n' + return s + +class EndSubroutine(EndStatement): + """ + END [SUBROUTINE [name]] + """ + match = re.compile(r'end(\s*subroutine\s*\w*|)\Z', re.I).match + + +class Subroutine(SubProgramStatement): + """ + [ <prefix> ] SUBROUTINE <name> [ ( [ <dummy-arg-list> ] ) [ <proc-language-binding-spec> ]] + """ + 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 + +class EndFunction(EndStatement): + """ + END [FUNCTION [name]] + """ + match = re.compile(r'end(\s*function\s*\w*|)\Z', re.I).match + +class Function(SubProgramStatement): + """ + [ <prefix> ] FUNCTION <name> ( [<dummy-arg-list>] ) [<suffix>] + <prefix> = <prefix-spec> [ <prefix-spec> ]... + <prefix-spec> = <declaration-type-spec> + | RECURSIVE | PURE | ELEMENTAL + <suffix> = <proc-language-binding-spec> [ RESULT ( <result-name> ) ] + | RESULT ( <result-name> ) [ <proc-language-binding-spec> ] + """ + 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 + + def subroutine_wrapper_code(self): + name = 'f2pywrap_' + self.name + args = ['f2pyvalue_'+self.result] + self.args + var = self.a.variables[self.result] + typedecl = var.get_typedecl().astypedecl() + lines = [] + tab = ' '*6 + lines.append('%sSUBROUTINE %s(%s)' % (tab, name, ', '.join(args))) + if isinstance(self.parent,Module): + lines.append('%s USE %s' % (tab, self.parent.name)) + else: + if isinstance(typedecl, TypeStmt): + type_decl = typedecl.get_type_decl(typedecl.name) + if type_decl.parent is self: + for line in str(type_decl).split('\n'): + lines.append('%s %s' % (tab, line.lstrip())) + lines.append('%s EXTERNAL %s' % (tab, self.name)) + lines.append('%s %s %s' % (tab, str(typedecl).lstrip(), self.name)) + lines.append('%s %s %s' % (tab, str(typedecl).lstrip(), args[0])) + lines.append('!f2py intent(out) %s' % (args[0])) + for a in self.args: + v = self.a.variables[a] + lines.append('%s %s' % (tab, str(v).lstrip())) + lines.append('%s %s = %s(%s)' % (tab, args[0], self.name, ', '.join(self.args))) + #lines.append('%s print*,"%s=",%s' % (tab, args[0], args[0])) # debug line + lines.append('%sEND SUBROUTINE %s' % (tab, name)) + return '\n'.join(lines) + + def subroutine_wrapper(self): + code = self.subroutine_wrapper_code() + from api import parse + block = parse(code) # XXX: set include_dirs + while len(block.content)==1: + block = block.content[0] + return block + +# Handle subprogram prefixes + +class SubprogramPrefix(Statement): + """ + <prefix> <declaration-type-spec> <function|subroutine> ... + """ + match = re.compile(r'(pure|elemental|recursive|\s)+\b',re.I).match + def process_item(self): + line = self.item.get_line() + m = self.match(line) + prefix = line[:m.end()].rstrip() + rest = self.item.get_line()[m.end():].lstrip() + if rest: + self.parent.put_item(self.item.copy(prefix)) + self.item.clone(rest) + self.isvalid = False + return + if self.parent.__class__ not in [Function, Subroutine]: + self.isvalid = False + return + prefix = prefix + ' ' + self.parent.prefix + self.parent.prefix = prefix.strip() + self.ignore = True + return + +# SelectCase + +class EndSelect(EndStatement): + match = re.compile(r'end\s*select\s*\w*\Z', re.I).match + blocktype = 'select' + +class Select(BeginStatement): + """ + [ <case-construct-name> : ] SELECT CASE ( <case-expr> ) + + """ + match = re.compile(r'select\s*case\s*\(.*\)\Z',re.I).match + end_stmt_cls = EndSelect + name = '' + def tostr(self): + return 'SELECT CASE ( %s )' % (self.expr) + def process_item(self): + self.expr = self.item.get_line()[6:].lstrip()[4:].lstrip()[1:-1].strip() + self.name = self.item.label + return BeginStatement.process_item(self) + + def get_classes(self): + return [Case] + execution_part_construct + +# Where + +class EndWhere(EndStatement): + """ + END WHERE [ <where-construct-name> ] + """ + match = re.compile(r'end\s*\where\s*\w*\Z',re.I).match + + +class Where(BeginStatement): + """ + [ <where-construct-name> : ] WHERE ( <mask-expr> ) + <mask-expr> = <logical-expr> + """ + match = re.compile(r'where\s*\([^)]*\)\Z',re.I).match + end_stmt_cls = EndWhere + name = '' + def tostr(self): + return 'WHERE ( %s )' % (self.expr) + def process_item(self): + self.expr = self.item.get_line()[5:].lstrip()[1:-1].strip() + self.name = self.item.label + return BeginStatement.process_item(self) + + def get_classes(self): + return [Assignment, WhereStmt, + WhereConstruct, ElseWhere + ] + +WhereConstruct = Where + +# Forall + +class EndForall(EndStatement): + """ + END FORALL [ <forall-construct-name> ] + """ + match = re.compile(r'end\s*forall\s*\w*\Z',re.I).match + +class Forall(BeginStatement): + """ + [ <forall-construct-name> : ] FORALL <forall-header> + [ <forall-body-construct> ]... + <forall-body-construct> = <forall-assignment-stmt> + | <where-stmt> + | <where-construct> + | <forall-construct> + | <forall-stmt> + <forall-header> = ( <forall-triplet-spec-list> [ , <scalar-mask-expr> ] ) + <forall-triplet-spec> = <index-name> = <subscript> : <subscript> [ : <stride> ] + <subscript|stride> = <scalar-int-expr> + <forall-assignment-stmt> = <assignment-stmt> | <pointer-assignment-stmt> + """ + end_stmt_cls = EndForall + match = re.compile(r'forarr\s*\(.*\)\Z',re.I).match + name = '' + def process_item(self): + self.specs = self.item.get_line()[6:].lstrip()[1:-1].strip() + return BeginStatement.process_item(self) + def tostr(self): + return 'FORALL (%s)' % (self.specs) + def get_classes(self): + return [GeneralAssignment, WhereStmt, WhereConstruct, + ForallConstruct, ForallStmt] + +ForallConstruct = Forall + +# IfThen + +class EndIfThen(EndStatement): + """ + END IF [ <if-construct-name> ] + """ + match = re.compile(r'end\s*if\s*\w*\Z', re.I).match + blocktype = 'if' + +class IfThen(BeginStatement): + """ + [<if-construct-name> :] IF ( <scalar-logical-expr> ) THEN + + IfThen instance has the following attributes: + expr + """ + + match = re.compile(r'if\s*\(.*\)\s*then\Z',re.I).match + end_stmt_cls = EndIfThen + name = '' + + def tostr(self): + return 'IF (%s) THEN' % (self.expr) + + def process_item(self): + item = self.item + line = item.get_line()[2:-4].strip() + assert line[0]=='(' and line[-1]==')',`line` + self.expr = line[1:-1].strip() + self.name = item.label + return BeginStatement.process_item(self) + + def get_classes(self): + return [Else, ElseIf] + execution_part_construct + +class If(BeginStatement): + """ + IF ( <scalar-logical-expr> ) action-stmt + """ + + match = re.compile(r'if\s*\(',re.I).match + + def process_item(self): + item = self.item + mode = self.reader.mode + classes = self.get_classes() + classes = [cls for cls in classes if mode in cls.modes] + + line = item.get_line()[2:].lstrip() + i = line.find(')') + expr = line[1:i].strip() + line = line[i+1:].strip() + if line.lower()=='then': + self.isvalid = False + return + self.expr = item.apply_map(expr) + + if not line: + newitem = self.get_item() + else: + newitem = item.copy(line) + newline = newitem.get_line() + for cls in classes: + if cls.match(newline): + stmt = cls(self, newitem) + if stmt.isvalid: + self.content.append(stmt) + return + if not line: + self.put_item(newitem) + self.isvalid = False + return + + def tostr(self): + assert len(self.content)==1,`self.content` + return 'IF (%s) %s' % (self.expr, str(self.content[0]).lstrip()) + + def tofortran(self,isfix=None): + return self.get_indent_tab(colon=':',isfix=isfix) + self.tostr() + + def get_classes(self): + return action_stmt + +# Do + +class EndDo(EndStatement): + """ + END DO [ <do-construct-name> ] + """ + match = re.compile(r'end\s*do\s*\w*\Z', re.I).match + blocktype = 'do' + +class Do(BeginStatement): + """ + [ <do-construct-name> : ] DO label [loopcontrol] + [ <do-construct-name> : ] DO [loopcontrol] + + """ + + match = re.compile(r'do\b\s*\d*',re.I).match + item_re = re.compile(r'do\b\s*(?P<label>\d*)\s*,?\s*(?P<loopcontrol>.*)\Z',re.I).match + end_stmt_cls = EndDo + name = '' + + def tostr(self): + return 'DO %s %s' % (self.endlabel, self.loopcontrol) + + def process_item(self): + item = self.item + line = item.get_line() + m = self.item_re(line) + self.endlabel = m.group('label').strip() + self.name = item.label + self.loopcontrol = m.group('loopcontrol').strip() + return BeginStatement.process_item(self) + + def process_subitem(self, item): + r = False + if self.endlabel: + label = item.label + if label == self.endlabel: + r = True + if isinstance(self.parent, Do) and label==self.parent.endlabel: + # the same item label may be used for different block ends + self.put_item(item) + return BeginStatement.process_subitem(self, item) or r + + def get_classes(self): + return execution_part_construct + +# Associate + +class EndAssociate(EndStatement): + """ + END ASSOCIATE [ <associate-construct-name> ] + """ + match = re.compile(r'end\s*associate\s*\w*\Z',re.I).match + +class Associate(BeginStatement): + """ + [ <associate-construct-name> : ] ASSOCIATE ( <association-list> ) + <block> + + <association> = <associate-name> => <selector> + <selector> = <expr> | <variable> + """ + match = re.compile(r'associate\s*\(.*\)\Z',re.I).match + end_stmt_cls = EndAssociate + + def process_item(self): + line = self.item.get_line()[9:].lstrip() + self.associations = line[1:-1].strip() + return BeginStatement.process_item(self) + def tostr(self): + return 'ASSOCIATE (%s)' % (self.associations) + def get_classes(self): + return execution_part_construct + +# Type + +class EndType(EndStatement): + """ + END TYPE [<type-name>] + """ + match = re.compile(r'end\s*type\s*\w*\Z', re.I).match + blocktype = 'type' + +class Type(BeginStatement, HasVariables, HasAttributes, AccessSpecs): + """ + TYPE [ [ , <type-attr-spec-list>] :: ] <type-name> [ ( <type-param-name-list> ) ] + <type-attr-spec> = <access-spec> | EXTENDS ( <parent-type-name> ) + | ABSTRACT | BIND(C) + """ + match = re.compile(r'type\b\s*').match + end_stmt_cls = EndType + + a = AttributeHolder(extends = None, + parameters = {}, + component_names = [], # specifies component order for sequence types + components = {} + ) + known_attributes = re.compile(r'\A(PUBLIC|PRIVATE|SEQUENCE|ABSTRACT|BIND\s*\(.*\))\Z',re.I).match + + def process_item(self): + line = self.item.get_line()[4:].lstrip() + if line.startswith('('): + self.isvalid = False + return + specs = [] + i = line.find('::') + if i!=-1: + for s in line[:i].split(','): + s = s.strip() + if s: specs.append(s) + line = line[i+2:].lstrip() + self.specs = specs + i = line.find('(') + if i!=-1: + self.name = line[:i].rstrip() + assert line[-1]==')',`line` + self.params = split_comma(line[i+1:-1].lstrip()) + else: + self.name = line + self.params = [] + if not is_name(self.name): + self.isvalid = False + return + return BeginStatement.process_item(self) + + def tostr(self): + s = 'TYPE' + if self.specs: + s += ', '.join(['']+self.specs) + ' ::' + s += ' ' + self.name + if self.params: + s += ' ('+', '.join(self.params)+')' + return s + + def get_classes(self): + return [Integer] + private_or_sequence + component_part +\ + type_bound_procedure_part + + def analyze(self): + BeginStatement.analyze(self) + for spec in self.specs: + i = spec.find('(') + if i!=-1: + assert spec.endswith(')'),`spec` + s = spec[:i].rstrip().upper() + n = spec[i+1:-1].strip() + if s=='EXTENDS': + self.a.extends = n + continue + elif s=='BIND': + args,rest = parse_bind(spec) + assert not rest,`rest` + spec = 'BIND(%s)' % (', '.join(args)) + else: + spec = '%s(%s)' % (s,n) + else: + spec = spec.upper() + 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=''): + s = tab + 'TYPE' + if self.a.extends is not None: + s += ', EXTENDS(%s) ::' % (self.a.extends) + s += ' ' + self.name + if self.a.parameters: + s += ' (%s)' % (', '.join(self.a.parameters)) + s += '\n' + s += AccessSpecs.topyf(self, tab=tab+' ') + s += HasAttributes.topyf(self, tab=tab+' ') + s += HasVariables.topyf(self, tab=tab+' ') + s += tab + 'END TYPE ' + self.name + '\n' + return s + + # Wrapper methods: + + def get_bit_size(self, _cache={}): + try: + return _cache[id(self)] + except KeyError: + s = 0 + for name,var in self.a.components.items(): + s += var.get_bit_size() + _cache[id(self)] = s + return s + +TypeDecl = Type + +# Enum + +class EndEnum(EndStatement): + """ + END ENUM + """ + match = re.compile(r'end\s*enum\Z',re.I).match + blocktype = 'enum' + +class Enum(BeginStatement): + """ + ENUM , BIND(C) + <enumerator-def-stmt> + [ <enumerator-def-stmt> ]... + """ + blocktype = 'enum' + end_stmt_cls = EndEnum + match = re.compile(r'enum\s*,\s*bind\s*\(\s*c\s*\)\Z',re.I).match + def process_item(self): + return BeginStatement.process_item(self) + def get_classes(self): + return [Enumerator] + +################################################### + +import statements +import typedecl_statements +__all__.extend(statements.__all__) +__all__.extend(typedecl_statements.__all__) + +from statements import * +from typedecl_statements import * + +f2py_stmt = [Threadsafe, FortranName, Depend, Check, CallStatement, + CallProtoArgument] + +access_spec = [Public, Private] + +interface_specification = [Function, Subroutine, + ModuleProcedure + ] + +module_subprogram_part = [ Contains, Function, Subroutine ] + +specification_stmt = access_spec + [ Allocatable, Asynchronous, Bind, + Common, Data, Dimension, Equivalence, External, Intent, Intrinsic, + Namelist, Optional, Pointer, Protected, Save, Target, Volatile, + Value ] + +intrinsic_type_spec = [ SubprogramPrefix, Integer , Real, + DoublePrecision, Complex, DoubleComplex, Character, Logical, Byte + ] + +derived_type_spec = [ ] +type_spec = intrinsic_type_spec + derived_type_spec +declaration_type_spec = intrinsic_type_spec + [ TypeStmt, Class ] + +type_declaration_stmt = declaration_type_spec + +private_or_sequence = [ Private, Sequence ] + +component_part = declaration_type_spec + [ ModuleProcedure ] + +proc_binding_stmt = [SpecificBinding, GenericBinding, FinalBinding] + +type_bound_procedure_part = [Contains, Private] + proc_binding_stmt + +#R214 +action_stmt = [ Allocate, GeneralAssignment, Assign, Backspace, Call, Close, + Continue, Cycle, Deallocate, Endfile, Exit, Flush, ForallStmt, + Goto, If, Inquire, Nullify, Open, Print, Read, Return, Rewind, + Stop, Wait, WhereStmt, Write, ArithmeticIf, ComputedGoto, + AssignedGoto, Pause ] +# GeneralAssignment = Assignment + PointerAssignment +# EndFunction, EndProgram, EndSubroutine - part of the corresponding blocks + +executable_construct = [ Associate, Do, ForallConstruct, IfThen, + Select, WhereConstruct ] + action_stmt +#Case, see Select + +execution_part_construct = executable_construct + [ Format, Entry, + Data ] + +execution_part = execution_part_construct[:] + +#C201, R208 +for cls in [EndFunction, EndProgram, EndSubroutine]: + try: execution_part.remove(cls) + except ValueError: pass + +internal_subprogram = [Function, Subroutine] + +internal_subprogram_part = [ Contains, ] + internal_subprogram + +declaration_construct = [ TypeDecl, Entry, Enum, Format, Interface, + Parameter, ModuleProcedure, ] + specification_stmt + \ + type_declaration_stmt +# stmt-function-stmt + +implicit_part = [ Implicit, Parameter, Format, Entry ] + +specification_part = [ Use, Import ] + implicit_part + \ + declaration_construct + + +external_subprogram = [Function, Subroutine] + +main_program = [Program] + specification_part + execution_part + \ + internal_subprogram_part + +program_unit = main_program + external_subprogram + [Module, + BlockData ] diff --git a/numpy/f2py/lib/parser/doc.txt b/numpy/f2py/lib/parser/doc.txt new file mode 100644 index 000000000..0d20bf73f --- /dev/null +++ b/numpy/f2py/lib/parser/doc.txt @@ -0,0 +1,365 @@ +.. -*- rest -*- + +Created: September 2006 +Author: Pearu Peterson <pearu.peterson@gmail.com> + +Fortran parser package structure +================================ + +numpy.f2py.lib.parser package contains the following files: + +api.py +------ + +Public API for Fortran parser. + +It exposes Statement classes, CHAR_BIT constant, and parse function. + +Function parse(<input>, ..) parses, analyzes and returns Statement +tree of Fortran input. For example, + +:: + + >>> from api import parse + >>> code = """ + ... c comment + ... subroutine foo(a) + ... integer a + ... print*,"a=",a + ... end + ... """ + >>> tree = parse(code,isfree=False) + >>> print tree + !BEGINSOURCE <cStringIO.StringI object at 0xb75ac410> mode=fix90 + SUBROUTINE foo(a) + INTEGER a + PRINT *, "a=", a + END SUBROUTINE foo + >>> + >>> tree + BeginSource + blocktype='beginsource' + name='<cStringIO.StringI object at 0xb75ac410> mode=fix90' + a=AttributeHolder: + external_subprogram=<dict with keys ['foo']> + content: + Subroutine + args=['a'] + item=Line('subroutine foo(a)',(3, 3),'') + a=AttributeHolder: + variables=<dict with keys ['a']> + content: + Integer + selector=('', '') + entity_decls=['a'] + item=Line('integer a',(4, 4),'') + Print + item=Line('print*,"a=",a',(5, 5),'') + EndSubroutine + blocktype='subroutine' + name='foo' + item=Line('end',(6, 6),'') + +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 diff --git a/numpy/f2py/lib/parser/parsefortran.py b/numpy/f2py/lib/parser/parsefortran.py new file mode 100644 index 000000000..08716e7c8 --- /dev/null +++ b/numpy/f2py/lib/parser/parsefortran.py @@ -0,0 +1,197 @@ +#!/usr/bin/env python +""" +Defines FortranParser. + +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: May 2006 +""" + +__all__ = ['FortranParser'] + +import re +import sys +import traceback +from numpy.distutils.misc_util import yellow_text, red_text + +from readfortran import FortranFileReader, FortranStringReader +from block_statements import BeginSource +from utils import AnalyzeError + +class FortranParser: + + 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] + self.block = parser.block + self.is_analyzed = parser.is_analyzed + self.block.show_message('using cached %s' % (reader.id)) + else: + self.cache[reader.id] = self + self.block = None + self.is_analyzed = False + return + + def get_item(self): + try: + return self.reader.next(ignore_comments = True) + except StopIteration: + pass + return + + def put_item(self, item): + self.reader.fifo_item.insert(0, item) + return + + def parse(self): + if self.block is not None: + return + try: + block = self.block = BeginSource(self) + except KeyboardInterrupt: + raise + except: + reader = self.reader + while reader is not None: + message = reader.format_message('FATAL ERROR', + 'while processing line', + reader.linecount, reader.linecount) + reader.show_message(message, sys.stderr) + reader = reader.reader + traceback.print_exc(file=sys.stderr) + self.reader.show_message(red_text('STOPPED PARSING'), sys.stderr) + return + return + + def analyze(self): + if self.is_analyzed: + return + if self.block is None: + self.reader.show_message('Nothing to analyze.') + return + + try: + self.block.analyze() + except AnalyzeError: + pass + except Exception, msg: + if str(msg) != '123454321': + traceback.print_exc(file=sys.stderr) + self.reader.show_message(red_text('FATAL ERROR: STOPPED ANALYSING %r CONTENT' % (self.reader.source) ), sys.stderr) + sys.exit(123454321) + return + self.is_analyzed = True + return + +def test_pyf(): + string = """ +python module foo + interface tere + subroutine bar + real r + end subroutine bar + end interface tere +end python module foo +""" + reader = FortranStringReader(string, True, True) + parser = FortranParser(reader) + block = parser.parse() + print block + +def test_free90(): + string = """ +module foo + + subroutine bar + real r + if ( pc_get_lun() .ne. 6) & + write ( pc_get_lun(), '( & + & /, a, /, " p=", i4, " stopping c_flag=", a, & + & /, " print unit=", i8)') & + trim(title), pcpsx_i_pel(), trim(c_flag), pc_get_lun() + if (.true.) then + call smth + end if + aaa : if (.false.) then + else if (a) then aaa + else aaa + end if aaa + hey = 1 + end subroutine bar + abstract interface + + end interface + +end module foo +""" + reader = FortranStringReader(string, True, False) + parser = FortranParser(reader) + block = parser.parse() + print block + +def test_f77(): + string = """\ + program foo + a = 3 + end + subroutine bar + end + pure function foo(a) + end + pure real*4 recursive function bar() + end +""" + reader = FortranStringReader(string, False, True) + parser = FortranParser(reader) + block = parser.parse() + print block + +def simple_main(): + import sys + if not sys.argv[1:]: + return parse_all_f() + for filename in sys.argv[1:]: + reader = FortranFileReader(filename) + print yellow_text('Processing '+filename+' (mode=%r)' % (reader.mode)) + parser = FortranParser(reader) + parser.parse() + parser.analyze() + print parser.block.torepr(4) + #print parser.block + +def profile_main(): + import hotshot, hotshot.stats + prof = hotshot.Profile("_parsefortran.prof") + prof.runcall(simple_main) + prof.close() + stats = hotshot.stats.load("_parsefortran.prof") + stats.strip_dirs() + stats.sort_stats('time', 'calls') + stats.print_stats(30) + +def parse_all_f(): + for filename in open('opt_all_f.txt'): + filename = filename.strip() + reader = FortranFileReader(filename) + print yellow_text('Processing '+filename+' (mode=%r)' % (reader.mode)) + parser = FortranParser(reader) + block = parser.parse() + print block + +if __name__ == "__main__": + #test_f77() + #test_free90() + #test_pyf() + simple_main() + #profile_main() + #parse_all_f() diff --git a/numpy/f2py/lib/parser/pattern_tools.py b/numpy/f2py/lib/parser/pattern_tools.py new file mode 100644 index 000000000..3c009a6a8 --- /dev/null +++ b/numpy/f2py/lib/parser/pattern_tools.py @@ -0,0 +1,401 @@ +""" +Tools for constructing patterns. + +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: Oct 2006 +----- +""" + +import re + +class Pattern: + """ + p1 | p2 -> <p1> | <p2> + p1 + p2 -> <p1> <p2> + p1 & p2 -> <p1><p2> + ~p1 -> [ <p1> ] + ~~p1 -> [ <p1> ]... + ~~~p1 -> <p1> [ <p1> ]... + ~~~~p1 -> ~~~p1 + abs(p1) -> whole string match of <p1> + p1.named(name) -> match of <p1> has name + p1.match(string) -> return string match with <p1> + p1.flags(<re.I,..>) + p1.rsplit(..) -> split a string from the rightmost p1 occurrence + p1.lsplit(..) -> split a string from the leftmost p1 occurrence + """ + _special_symbol_map = {'.': '[.]', + '*': '[*]', + '+': '[+]', + '|': '[|]', + '(': r'\(', + ')': r'\)', + '[': r'\[', + ']': r'\]', + '^': '[^]', + '$': '[$]', + '?': '[?]', + '{': '\{', + '}': '\}', + '>': '[>]', + '<': '[<]', + '=': '[=]' + } + + def __init__(self, label, pattern, optional=0, flags=0, value=None): + self.label = label + self.pattern = pattern + self.optional = optional + self._flags = flags + self.value = value + return + + def flags(self, *flags): + f = self._flags + for f1 in flags: + f = f | f1 + return Pattern(self.label, self.pattern, optional=self.optional, flags=f, value=self.value) + + def get_compiled(self): + try: + return self._compiled_pattern + except AttributeError: + self._compiled_pattern = compiled = re.compile(self.pattern, self._flags) + return compiled + + def match(self, string): + return self.get_compiled().match(string) + + def search(self, string): + return self.get_compiled().search(string) + + def rsplit(self, string): + """ + Return (<lhs>, <pattern_match>, <rhs>) where + string = lhs + pattern_match + rhs + and rhs does not contain pattern_match. + If no pattern_match is found in string, return None. + """ + compiled = self.get_compiled() + t = compiled.split(string) + if len(t) < 3: return + if '' in t[1:-1]: return + rhs = t[-1].strip() + pattern_match = t[-2].strip() + assert abs(self).match(pattern_match),`self,string,t,pattern_match` + lhs = (''.join(t[:-2])).strip() + return lhs, pattern_match, rhs + + def lsplit(self, string): + """ + Return (<lhs>, <pattern_match>, <rhs>) where + string = lhs + pattern_match + rhs + and rhs does not contain pattern_match. + If no pattern_match is found in string, return None. + """ + compiled = self.get_compiled() + t = compiled.split(string) # can be optimized + if len(t) < 3: return + lhs = t[0].strip() + pattern_match = t[1].strip() + rhs = (''.join(t[2:])).strip() + assert abs(self).match(pattern_match),`pattern_match` + return lhs, pattern_match, rhs + + def __abs__(self): + return Pattern(self.label, r'\A' + self.pattern+ r'\Z',flags=self._flags, value=self.value) + + def __repr__(self): + return '%s(%r, %r)' % (self.__class__.__name__, self.label, self.pattern) + + def __or__(self, other): + label = '( %s OR %s )' % (self.label, other.label) + if self.pattern==other.pattern: + pattern = self.pattern + flags = self._flags + else: + pattern = '(%s|%s)' % (self.pattern, other.pattern) + flags = self._flags | other._flags + return Pattern(label, pattern, flags=flags) + + def __and__(self, other): + if isinstance(other, Pattern): + label = '%s%s' % (self.label, other.label) + pattern = self.pattern + other.pattern + flags = self._flags | other._flags + else: + assert isinstance(other,str),`other` + label = '%s%s' % (self.label, other) + pattern = self.pattern + other + flags = self._flags + return Pattern(label, pattern, flags=flags) + + def __rand__(self, other): + assert isinstance(other,str),`other` + label = '%s%s' % (other, self.label) + pattern = other + self.pattern + return Pattern(label, pattern, flags=self._flags) + + def __invert__(self): + if self.optional: + if self.optional==1: + return Pattern(self.label + '...', self.pattern[:-1] + '*', optional=2,flags=self._flags) + if self.optional==2: + return Pattern('%s %s' % (self.label[1:-4].strip(), self.label), self.pattern[:-1] + '+', + optional=3, flags=self._flags) + return self + label = '[ %s ]' % (self.label) + pattern = '(%s)?' % (self.pattern) + return Pattern(label, pattern, optional=1, flags=self._flags) + + def __add__(self, other): + if isinstance(other, Pattern): + label = '%s %s' % (self.label, other.label) + pattern = self.pattern + r'\s*' + other.pattern + flags = self._flags | other._flags + else: + assert isinstance(other,str),`other` + label = '%s %s' % (self.label, other) + other = self._special_symbol_map.get(other, other) + pattern = self.pattern + r'\s*' + other + flags = self._flags + return Pattern(label, pattern, flags = flags) + + def __radd__(self, other): + assert isinstance(other,str),`other` + label = '%s %s' % (other, self.label) + other = self._special_symbol_map.get(other, other) + pattern = other + r'\s*' + self.pattern + return Pattern(label, pattern, flags=self._flags) + + def named(self, name = None): + if name is None: + label = self.label + assert label[0]+label[-1]=='<>' and ' ' not in label,`label` + else: + label = '<%s>' % (name) + pattern = '(?P%s%s)' % (label.replace('-','_'), self.pattern) + return Pattern(label, pattern, flags=self._flags, value= self.value) + + def rename(self, label): + if label[0]+label[-1]!='<>': + label = '<%s>' % (label) + return Pattern(label, self.pattern, optional=self.optional, flags=self._flags, value=self.value) + + def __call__(self, string): + m = self.match(string) + if m is None: return + if self.value is not None: return self.value + return m.group() + +# Predefined patterns + +letter = Pattern('<letter>','[A-Z]',flags=re.I) +name = Pattern('<name>', r'[A-Z]\w*',flags=re.I) +digit = Pattern('<digit>',r'\d') +underscore = Pattern('<underscore>', '_') +binary_digit = Pattern('<binary-digit>',r'[01]') +octal_digit = Pattern('<octal-digit>',r'[0-7]') +hex_digit = Pattern('<hex-digit>',r'[\dA-F]',flags=re.I) + +digit_string = Pattern('<digit-string>',r'\d+') +binary_digit_string = Pattern('<binary-digit-string>',r'[01]+') +octal_digit_string = Pattern('<octal-digit-string>',r'[0-7]+') +hex_digit_string = Pattern('<hex-digit-string>',r'[\dA-F]+',flags=re.I) + +sign = Pattern('<sign>',r'[+-]') +exponent_letter = Pattern('<exponent-letter>',r'[ED]',flags=re.I) + +alphanumeric_character = Pattern('<alphanumeric-character>',r'\w') # [A-Z0-9_] +special_character = Pattern('<special-character>',r'[ =+-*/\()[\]{},.:;!"%&~<>?,\'`^|$#@]') +character = alphanumeric_character | special_character + +kind_param = digit_string | name +kind_param_named = kind_param.named('kind-param') +signed_digit_string = ~sign + digit_string +int_literal_constant = digit_string + ~('_' + kind_param) +signed_int_literal_constant = ~sign + int_literal_constant +int_literal_constant_named = digit_string.named('value') + ~ ('_' + kind_param_named) +signed_int_literal_constant_named = (~sign + digit_string).named('value') + ~ ('_' + kind_param_named) + +binary_constant = ('B' + ("'" & binary_digit_string & "'" | '"' & binary_digit_string & '"')).flags(re.I) +octal_constant = ('O' + ("'" & octal_digit_string & "'" | '"' & octal_digit_string & '"')).flags(re.I) +hex_constant = ('Z' + ("'" & hex_digit_string & "'" | '"' & hex_digit_string & '"')).flags(re.I) +boz_literal_constant = binary_constant | octal_constant | hex_constant + +exponent = signed_digit_string +significand = digit_string + '.' + ~digit_string | '.' + digit_string +real_literal_constant = significand + ~(exponent_letter + exponent) + ~ ('_' + kind_param) | \ + digit_string + exponent_letter + exponent + ~ ('_' + kind_param) +real_literal_constant_named = (significand + ~(exponent_letter + exponent) |\ + digit_string + exponent_letter + exponent).named('value') + ~ ('_' + kind_param_named) +signed_real_literal_constant_named = (~sign + (significand + ~(exponent_letter + exponent) |\ + digit_string + exponent_letter + exponent)).named('value') + ~ ('_' + kind_param_named) +signed_real_literal_constant = ~sign + real_literal_constant + +named_constant = name +real_part = signed_int_literal_constant | signed_real_literal_constant | named_constant +imag_part = real_part +complex_literal_constant = '(' + real_part + ',' + imag_part + ')' + +a_n_rep_char = Pattern('<alpha-numeric-rep-char>',r'\w') +rep_char = Pattern('<rep-char>',r'.') +char_literal_constant = ~( kind_param + '_') + ("'" + ~~rep_char + "'" | '"' + ~~rep_char + '"' ) +a_n_char_literal_constant_named1 = ~( kind_param_named + '_') + (~~~("'" + ~~a_n_rep_char + "'" )).named('value') +a_n_char_literal_constant_named2 = ~( kind_param_named + '_') + (~~~('"' + ~~a_n_rep_char + '"' )).named('value') + +logical_literal_constant = ('[.](TRUE|FALSE)[.]' + ~ ('_' + kind_param)).flags(re.I) +logical_literal_constant_named = Pattern('<value>',r'[.](TRUE|FALSE)[.]',flags=re.I).named() + ~ ('_' + kind_param_named) +literal_constant = int_literal_constant | real_literal_constant | complex_literal_constant | logical_literal_constant | char_literal_constant | boz_literal_constant +constant = literal_constant | named_constant +int_constant = int_literal_constant | boz_literal_constant | named_constant +char_constant = char_literal_constant | named_constant + +# assume that replace_string_map is applied: +part_ref = name + ~((r'[(]' + name + r'[)]')) +data_ref = part_ref + ~~~(r'[%]' + part_ref) +primary = constant | name | data_ref | (r'[(]' + name + r'[)]') + +power_op = Pattern('<power-op>',r'(?<![*])[*]{2}(?![*])') +mult_op = Pattern('<mult-op>',r'(?<![*])[*](?![*])|(?<![/])[/](?![/])') +add_op = Pattern('<add-op>',r'[+-]') +concat_op = Pattern('<concat-op>',r'(?<![/])[/]{2}(?![/])') +rel_op = Pattern('<rel-op>','[.]EQ[.]|[.]NE[.]|[.]LT[.]|[.]LE[.]|[.]GT[.]|[.]GE[.]|[=]{2}|/[=]|[<][=]|[<]|[>][=]|[>]',flags=re.I) +not_op = Pattern('<not-op>','[.]NOT[.]',flags=re.I) +and_op = Pattern('<and-op>','[.]AND[.]',flags=re.I) +or_op = Pattern('<or-op>','[.]OR[.]',flags=re.I) +equiv_op = Pattern('<equiv-op>','[.]EQV[.]|[.]NEQV[.]',flags=re.I) +percent_op = Pattern('<percent-op>',r'%',flags=re.I) +intrinsic_operator = power_op | mult_op | add_op | concat_op | rel_op | not_op | and_op | or_op | equiv_op +extended_intrinsic_operator = intrinsic_operator + +defined_unary_op = Pattern('<defined-unary-op>','[.][A-Z]+[.]',flags=re.I) +defined_binary_op = Pattern('<defined-binary-op>','[.][A-Z]+[.]',flags=re.I) +defined_operator = defined_unary_op | defined_binary_op | extended_intrinsic_operator +abs_defined_operator = abs(defined_operator) +defined_op = Pattern('<defined-op>','[.][A-Z]+[.]',flags=re.I) +abs_defined_op = abs(defined_op) + +non_defined_binary_op = intrinsic_operator | logical_literal_constant + +label = Pattern('<label>','\d{1,5}') +abs_label = abs(label) + +keyword = name +keyword_equal = keyword + '=' + + + + +abs_constant = abs(constant) +abs_literal_constant = abs(literal_constant) +abs_int_literal_constant = abs(int_literal_constant) +abs_signed_int_literal_constant = abs(signed_int_literal_constant) +abs_signed_int_literal_constant_named = abs(signed_int_literal_constant_named) +abs_int_literal_constant_named = abs(int_literal_constant_named) +abs_real_literal_constant = abs(real_literal_constant) +abs_signed_real_literal_constant = abs(signed_real_literal_constant) +abs_signed_real_literal_constant_named = abs(signed_real_literal_constant_named) +abs_real_literal_constant_named = abs(real_literal_constant_named) +abs_complex_literal_constant = abs(complex_literal_constant) +abs_logical_literal_constant = abs(logical_literal_constant) +abs_char_literal_constant = abs(char_literal_constant) +abs_boz_literal_constant = abs(boz_literal_constant) +abs_name = abs(name) +abs_a_n_char_literal_constant_named1 = abs(a_n_char_literal_constant_named1) +abs_a_n_char_literal_constant_named2 = abs(a_n_char_literal_constant_named2) +abs_logical_literal_constant_named = abs(logical_literal_constant_named) +abs_binary_constant = abs(binary_constant) +abs_octal_constant = abs(octal_constant) +abs_hex_constant = abs(hex_constant) + +intrinsic_type_name = Pattern('<intrinsic-type-name>',r'(INTEGER|REAL|COMPLEX|LOGICAL|CHARACTER|DOUBLE\s*COMPLEX|DOUBLE\s*PRECISION|BYTE)',flags=re.I) +abs_intrinsic_type_name = abs(intrinsic_type_name) +double_complex_name = Pattern('<double-complex-name>','DOUBLE\s*COMPLEX', flags=re.I, value='DOUBLE COMPLEX') +double_precision_name = Pattern('<double-precision-name>','DOUBLE\s*PRECISION', flags=re.I, value='DOUBLE PRECISION') +abs_double_complex_name = abs(double_complex_name) +abs_double_precision_name = abs(double_precision_name) + +access_spec = Pattern('<access-spec>',r'PUBLIC|PRIVATE',flags=re.I) +abs_access_spec = abs(access_spec) + +implicit_none = Pattern('<implicit-none>',r'IMPLICIT\s*NONE',flags=re.I, value='IMPLICIT NONE') +abs_implicit_none = abs(implicit_none) + +attr_spec = Pattern('<attr-spec>',r'ALLOCATABLE|ASYNCHRONOUS|EXTERNAL|INTENT|INTRINSIC|OPTIONAL|PARAMETER|POINTER|PROTECTED|SAVE|TARGET|VALUE|VOLATILE',flags=re.I) +abs_attr_spec = abs(attr_spec) + +dimension = Pattern('<dimension>',r'DIMENSION', flags=re.I) +abs_dimension = abs(dimension) + +intent = Pattern('<intent>', r'INTENT', flags=re.I) +abs_intent = abs(intent) + +intent_spec = Pattern('<intent-spec>', r'INOUT|IN|OUT', flags=re.I) +abs_intent_spec = abs(intent_spec) + +subroutine = Pattern('<subroutine>', r'SUBROUTINE', flags=re.I) + +select_case = Pattern('<select-case>', r'SELECT\s*CASE', flags=re.I, value='SELECT CASE') +abs_select_case = abs(select_case) + +def _test(): + assert name.match('a1_a') + assert abs(name).match('a1_a') + assert not abs(name).match('a1_a[]') + + m = abs(kind_param) + assert m.match('23') + assert m.match('SHORT') + + m = abs(signed_digit_string) + assert m.match('23') + assert m.match('+ 23') + assert m.match('- 23') + assert m.match('-23') + assert not m.match('+n') + + m = ~sign.named() + digit_string.named('number') + r = m.match('23') + assert r.groupdict()=={'number': '23', 'sign': None} + r = m.match('- 23') + assert r.groupdict()=={'number': '23', 'sign': '-'} + + m = abs(char_literal_constant) + assert m.match('"adadfa"') + assert m.match('"adadfa""adad"') + assert m.match('HEY_"adadfa"') + assert m.match('HEY _ "ad\tadfa"') + assert not m.match('adadfa') + + def assert_equal(result, expect): + try: + assert result==expect + except AssertionError, msg: + raise AssertionError,"Expected %r but got %r: %s" \ + % (expect, result, msg) + + m = mult_op.named() + assert m.rsplit('a * b') + assert_equal(m.lsplit('a * c* b'),('a','*','c* b')) + assert_equal(m.rsplit('a * c* b'),('a * c','*','b')) + assert_equal(m.lsplit('a * b ** c'),('a','*','b ** c')) + assert_equal(m.rsplit('a * b ** c'),('a','*','b ** c')) + assert_equal(m.lsplit('a * b ** c * d'),('a','*','b ** c * d')) + assert_equal(m.rsplit('a * b ** c * d'),('a * b ** c','*','d')) + + m = power_op.named() + assert m.rsplit('a ** b') + assert_equal(m.lsplit('a * b ** c'),('a * b','**','c')) + assert_equal(m.rsplit('a * b ** c'),('a * b','**','c')) + assert_equal(m.lsplit('a ** b ** c'),('a','**','b ** c')) + assert_equal(m.rsplit('a ** b ** c'),('a ** b','**','c')) + print 'ok' + +if __name__ == '__main__': + _test() diff --git a/numpy/f2py/lib/parser/readfortran.py b/numpy/f2py/lib/parser/readfortran.py new file mode 100644 index 000000000..e3acffa36 --- /dev/null +++ b/numpy/f2py/lib/parser/readfortran.py @@ -0,0 +1,857 @@ +#!/usr/bin/env python +""" +Defines FortranReader classes for reading Fortran codes from +files and strings. FortranReader handles comments and line continuations +of both fix and free format Fortran codes. + +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: May 2006 +----- +""" + +__all__ = ['FortranFileReader', + 'FortranStringReader', + 'FortranReaderError', + 'Line', 'SyntaxErrorLine', + 'Comment', + 'MultiLine','SyntaxErrorMultiLine', + ] + +import re +import os +import sys +import tempfile +import traceback +from cStringIO import StringIO +from numpy.distutils.misc_util import yellow_text, red_text, blue_text + +from sourceinfo import get_source_info +from splitline import String, string_replace_map, splitquote + +_spacedigits=' 0123456789' +_cf2py_re = re.compile(r'(?P<indent>\s*)!f2py(?P<rest>.*)',re.I) +_is_fix_cont = lambda line: line and len(line)>5 and line[5]!=' ' and line[:5]==5*' ' +_is_f90_cont = lambda line: line and '&' in line and line.rstrip()[-1]=='&' +_f90label_re = re.compile(r'\s*(?P<label>(\w+\s*:|\d+))\s*(\b|(?=&)|\Z)',re.I) +_is_include_line = re.compile(r'\s*include\s*("[^"]+"|\'[^\']+\')\s*\Z',re.I).match +_is_fix_comment = lambda line: line and line[0] in '*cC!' +_hollerith_start_search = re.compile(r'(?P<pre>\A|,\s*)(?P<num>\d+)h',re.I).search +_is_call_stmt = re.compile(r'call\b', re.I).match + +class FortranReaderError: # TODO: may be derive it from Exception + def __init__(self, message): + self.message = message + print >> sys.stderr,message + sys.stderr.flush() + +class Line: + """ Holds a Fortran source line. + """ + + f2py_strmap_findall = re.compile(r'(_F2PY_STRING_CONSTANT_\d+_|F2PY_EXPR_TUPLE_\d+)').findall + + def __init__(self, line, linenospan, label, reader): + self.line = line.strip() + self.span = linenospan + self.label = label + self.reader = reader + self.strline = None + self.is_f2py_directive = linenospan[0] in reader.f2py_comment_lines + + def has_map(self): + return not not (hasattr(self,'strlinemap') and self.strlinemap) + + def apply_map(self, line): + if not hasattr(self,'strlinemap') or not self.strlinemap: + return line + findall = self.f2py_strmap_findall + str_map = self.strlinemap + keys = findall(line) + for k in keys: + line = line.replace(k, str_map[k]) + return line + + def copy(self, line = None, apply_map = False): + if line is None: + line = self.line + if apply_map: + line = self.apply_map(line) + return Line(line, self.span, self.label, self.reader) + + def clone(self, line): + self.line = self.apply_map(line) + self.strline = None + return + + def __repr__(self): + return self.__class__.__name__+'(%r,%s,%r)' \ + % (self.line, self.span, self.label) + + def isempty(self, ignore_comments=False): + return not (self.line.strip() or self.label) + + def get_line(self): + if self.strline is not None: + return self.strline + line = self.line + if self.reader.isfix77: + # Handle Hollerith constants by replacing them + # with char-literal-constants. + # H constants may appear only in DATA statements and + # in the argument list of CALL statement. + # Holleriht constants were removed from the Fortran 77 standard. + # The following handling is not perfect but works for simple + # usage cases. + # todo: Handle hollerith constants in DATA statement + if _is_call_stmt(line): + l2 = self.line[4:].lstrip() + i = l2.find('(') + if i != -1 and l2[-1]==')': + substrings = ['call '+l2[:i+1]] + start_search = _hollerith_start_search + l2 = l2[i+1:-1].strip() + m = start_search(l2) + while m: + substrings.append(l2[:m.start()]) + substrings.append(m.group('pre')) + num = int(m.group('num')) + substrings.append("'"+l2[m.end():m.end()+num]+"'") + l2 = l2[m.end()+num:] + m = start_search(l2) + substrings.append(l2) + substrings.append(')') + line = ''.join(substrings) + + line, str_map = string_replace_map(line, lower=not self.reader.ispyf) + self.strline = line + self.strlinemap = str_map + return line + +class SyntaxErrorLine(Line, FortranReaderError): + def __init__(self, line, linenospan, label, reader, message): + Line.__init__(self, line, linenospan, label, reader) + FortranReaderError.__init__(self, message) + +class Comment: + """ Holds Fortran comment. + """ + def __init__(self, comment, linenospan, reader): + self.comment = comment + self.span = linenospan + self.reader = reader + def __repr__(self): + return self.__class__.__name__+'(%r,%s)' \ + % (self.comment, self.span) + def isempty(self, ignore_comments=False): + return ignore_comments or len(self.comment)<2 + +class MultiLine: + """ Holds (prefix, line list, suffix) representing multiline + syntax in .pyf files: + prefix+'''+lines+'''+suffix. + """ + def __init__(self, prefix, block, suffix, linenospan, reader): + self.prefix = prefix + self.block = block + self.suffix = suffix + self.span = linenospan + self.reader = reader + def __repr__(self): + return self.__class__.__name__+'(%r,%r,%r,%s)' \ + % (self.prefix,self.block,self.suffix, + self.span) + def isempty(self, ignore_comments=False): + return not (self.prefix or self.block or self.suffix) + +class SyntaxErrorMultiLine(MultiLine, FortranReaderError): + def __init__(self, prefix, block, suffix, linenospan, reader, message): + MultiLine.__init__(self, prefix, block, suffix, linenospan, reader) + FortranReaderError.__init__(self, message) + + +class FortranReaderBase: + + def __init__(self, source, isfree, isstrict): + """ + source - file-like object with .next() method + used to retrive a line. + source may contain + - Fortran 77 code + - fixed format Fortran 90 code + - free format Fortran 90 code + - .pyf signatures - extended free format Fortran 90 syntax + """ + + self.linecount = 0 + self.source = source + self.isclosed = False + + self.filo_line = [] + self.fifo_item = [] + self.source_lines = [] + + self.f2py_comment_lines = [] # line numbers that contain f2py directives + + self.reader = None + self.include_dirs = ['.'] + + self.set_mode(isfree, isstrict) + return + + def set_mode(self, isfree, isstrict): + self.isfree90 = isfree and not isstrict + self.isfix90 = not isfree and not isstrict + self.isfix77 = not isfree and isstrict + self.ispyf = isfree and isstrict + self.isfree = isfree + self.isfix = not isfree + self.isstrict = isstrict + + if self.isfree90: mode = 'free90' + elif self.isfix90: mode = 'fix90' + elif self.isfix77: mode = 'fix77' + else: mode = 'pyf' + self.mode = mode + self.name = '%s mode=%s' % (self.source, mode) + return + + def close_source(self): + # called when self.source.next() raises StopIteration. + pass + + # For handling raw source lines: + + def put_single_line(self, line): + self.filo_line.append(line) + self.linecount -= 1 + return + + def get_single_line(self): + try: + line = self.filo_line.pop() + self.linecount += 1 + return line + except IndexError: + pass + if self.isclosed: + return None + try: + line = self.source.next() + except StopIteration: + self.isclosed = True + self.close_source() + return None + self.linecount += 1 + # expand tabs, replace special symbols, get rid of nl characters + line = line.expandtabs().replace('\xa0',' ').rstrip() + self.source_lines.append(line) + if not line: + return self.get_single_line() + return line + + def get_next_line(self): + line = self.get_single_line() + if line is None: return + self.put_single_line(line) + return line + + # Parser methods: + def get_item(self): + try: + return self.next(ignore_comments = True) + except StopIteration: + pass + return + + def put_item(self, item): + self.fifo_item.insert(0, item) + return + # Iterator methods: + + def __iter__(self): + return self + + def next(self, ignore_comments = False): + + try: + if self.reader is not None: + try: + return self.reader.next() + except StopIteration: + self.reader = None + item = self._next(ignore_comments) + if isinstance(item, Line) and _is_include_line(item.line): + reader = item.reader + filename = item.line.strip()[7:].lstrip()[1:-1] + include_dirs = self.include_dirs[:] + path = filename + for incl_dir in include_dirs: + path = os.path.join(incl_dir, filename) + if os.path.exists(path): + break + if not os.path.isfile(path): + dirs = os.pathsep.join(include_dirs) + message = reader.format_message(\ + 'WARNING', + 'include file %r not found in %r,'\ + ' ignoring.' % (filename, dirs), + item.span[0], item.span[1]) + reader.show_message(message, sys.stdout) + return self.next(ignore_comments = ignore_comments) + message = reader.format_message('INFORMATION', + 'found file %r' % (path), + item.span[0], item.span[1]) + reader.show_message(message, sys.stdout) + self.reader = FortranFileReader(path, include_dirs = include_dirs) + return self.reader.next(ignore_comments = ignore_comments) + return item + except StopIteration: + raise + except: + message = self.format_message('FATAL ERROR', + 'while processing line', + self.linecount, self.linecount) + self.show_message(message, sys.stdout) + traceback.print_exc(file=sys.stdout) + self.show_message(red_text('STOPPED READING'), sys.stdout) + raise StopIteration + + def _next(self, ignore_comments = False): + fifo_item_pop = self.fifo_item.pop + while 1: + try: + item = fifo_item_pop(0) + except IndexError: + item = self.get_source_item() + if item is None: + raise StopIteration + if not item.isempty(ignore_comments): + break + # else ignore empty lines and comments + if not isinstance(item, Comment): + if not self.ispyf and isinstance(item, Line) \ + and not item.is_f2py_directive \ + and ';' in item.get_line(): + # ;-separator not recognized in pyf-mode + items = [] + for line in item.get_line().split(';'): + line = line.strip() + items.append(item.copy(line, apply_map=True)) + items.reverse() + for newitem in items: + self.fifo_item.insert(0, newitem) + return fifo_item_pop(0) + return item + # collect subsequent comments to one comment instance + comments = [] + start = item.span[0] + while isinstance(item, Comment): + comments.append(item.comment) + end = item.span[1] + while 1: + try: + item = fifo_item_pop(0) + except IndexError: + item = self.get_source_item() + if item is None or not item.isempty(ignore_comments): + break + if item is None: + break # hold raising StopIteration for the next call. + if item is not None: + self.fifo_item.insert(0,item) + return self.comment_item('\n'.join(comments), start, end) + + # Interface to returned items: + + def line_item(self, line, startlineno, endlineno, label, errmessage=None): + if errmessage is None: + return Line(line, (startlineno, endlineno), label, self) + return SyntaxErrorLine(line, (startlineno, endlineno), + label, self, errmessage) + + def multiline_item(self, prefix, lines, suffix, + startlineno, endlineno, errmessage=None): + if errmessage is None: + return MultiLine(prefix, lines, suffix, (startlineno, endlineno), self) + return SyntaxErrorMultiLine(prefix, lines, suffix, + (startlineno, endlineno), self, errmessage) + + def comment_item(self, comment, startlineno, endlineno): + return Comment(comment, (startlineno, endlineno), self) + + # For handling messages: + + def show_message(self, message, stream = sys.stdout): + stream.write(message+'\n') + stream.flush() + return + + def format_message(self, kind, message, startlineno, endlineno, + startcolno=0, endcolno=-1): + back_index = {'warning':2,'error':3,'info':0}.get(kind.lower(),3) + r = ['%s while processing %r (mode=%r)..' % (kind, self.id, self.mode)] + for i in range(max(1,startlineno-back_index),startlineno): + r.append('%5d:%s' % (i,self.source_lines[i-1])) + for i in range(startlineno,min(endlineno+back_index,len(self.source_lines))+1): + if i==0 and not self.source_lines: + break + linenostr = '%5d:' % (i) + if i==endlineno: + sourceline = self.source_lines[i-1] + l0 = linenostr+sourceline[:startcolno] + if endcolno==-1: + l1 = sourceline[startcolno:] + l2 = '' + else: + l1 = sourceline[startcolno:endcolno] + l2 = sourceline[endcolno:] + r.append('%s%s%s <== %s' % (l0,yellow_text(l1),l2,red_text(message))) + else: + r.append(linenostr+ self.source_lines[i-1]) + return '\n'.join(r) + + def format_error_message(self, message, startlineno, endlineno, + startcolno=0, endcolno=-1): + return self.format_message('ERROR',message, startlineno, + endlineno, startcolno, endcolno) + + def format_warning_message(self, message, startlineno, endlineno, + startcolno=0, endcolno=-1): + return self.format_message('WARNING',message, startlineno, + endlineno, startcolno, endcolno) + + def error(self, message, item=None): + if item is None: + m = self.format_error_message(message, len(self.source_lines)-2, len(self.source_lines)) + else: + m = self.format_error_message(message, item.span[0], item.span[1]) + self.show_message(m) + return + + def warning(self, message, item=None): + if item is None: + m = self.format_warning_message(message, len(self.source_lines)-2, len(self.source_lines)) + else: + m = self.format_warning_message(message, item.span[0], item.span[1]) + self.show_message(m) + return + + # Auxiliary methods for processing raw source lines: + + def handle_cf2py_start(self, line): + """ + f2py directives can be used only in Fortran codes. + They are ignored when used inside .pyf files. + """ + if not line or self.ispyf: return line + if self.isfix: + if line[0] in '*cC!#': + if line[1:5].lower() == 'f2py': + line = 5*' ' + line[5:] + self.f2py_comment_lines.append(self.linecount) + if self.isfix77: + return line + m = _cf2py_re.match(line) + if m: + newline = m.group('indent')+5*' '+m.group('rest') + self.f2py_comment_lines.append(self.linecount) + assert len(newline)==len(line),`newlinel,line` + return newline + return line + + def handle_inline_comment(self, line, lineno, quotechar=None): + if quotechar is None and '!' not in line and \ + '"' not in line and "'" not in line: + return line, quotechar + i = line.find('!') + put_item = self.fifo_item.append + if quotechar is None and i!=-1: + # first try a quick method + newline = line[:i] + if '"' not in newline and '\'' not in newline: + if self.isfix77 or not line[i:].startswith('!f2py'): + put_item(self.comment_item(line[i:], lineno, lineno)) + return newline, quotechar + # handle cases where comment char may be a part of a character content + #splitter = LineSplitter(line, quotechar) + #items = [item for item in splitter] + #newquotechar = splitter.quotechar + items, newquotechar = splitquote(line, quotechar) + + noncomment_items = [] + noncomment_items_append = noncomment_items.append + n = len(items) + commentline = None + for k in range(n): + item = items[k] + if isinstance(item, String) or '!' not in item: + noncomment_items_append(item) + continue + j = item.find('!') + noncomment_items_append(item[:j]) + items[k] = item[j:] + commentline = ''.join(items[k:]) + break + if commentline is not None: + if commentline.startswith('!f2py'): + # go to next iteration: + newline = ''.join(noncomment_items) + commentline[5:] + self.f2py_comment_lines.append(lineno) + return self.handle_inline_comment(newline, lineno, quotechar) + put_item(self.comment_item(commentline, lineno, lineno)) + return ''.join(noncomment_items), newquotechar + + def handle_multilines(self, line, startlineno, mlstr): + i = line.find(mlstr) + if i != -1: + prefix = line[:i] + # skip fake multiline starts + p,k = prefix,0 + while p.endswith('\\'): + p,k = p[:-1],k+1 + if k % 2: return + if i != -1 and '!' not in prefix: + # Note character constans like 'abc"""123', + # so multiline prefix should better not contain `'' or `"' not `!'. + for quote in '"\'': + if prefix.count(quote) % 2: + message = self.format_warning_message(\ + 'multiline prefix contains odd number of %r characters' \ + % (quote), startlineno, startlineno, + 0, len(prefix)) + self.show_message(message, sys.stderr) + + suffix = None + multilines = [] + line = line[i+3:] + while line is not None: + j = line.find(mlstr) + if j != -1 and '!' not in line[:j]: + multilines.append(line[:j]) + suffix = line[j+3:] + break + multilines.append(line) + line = self.get_single_line() + if line is None: + message = self.format_error_message(\ + 'multiline block never ends', startlineno, + startlineno, i) + return self.multiline_item(\ + prefix,multilines,suffix,\ + startlineno, self.linecount, message) + suffix,qc = self.handle_inline_comment(suffix, self.linecount) + # no line continuation allowed in multiline suffix + if qc is not None: + message = self.format_message(\ + 'ASSERTION FAILURE(pyf)', + 'following character continuation: %r, expected None.' % (qc), + startlineno, self.linecount) + self.show_message(message, sys.stderr) + # XXX: should we do line.replace('\\'+mlstr[0],mlstr[0]) + # for line in multilines? + return self.multiline_item(prefix,multilines,suffix, + startlineno, self.linecount) + + # The main method of interpreting raw source lines within + # the following contexts: f77, fixed f90, free f90, pyf. + + def get_source_item(self): + """ + a source item is .. + - a fortran line + - a list of continued fortran lines + - a multiline - lines inside triple-qoutes, only when in ispyf mode + """ + get_single_line = self.get_single_line + line = get_single_line() + if line is None: return + startlineno = self.linecount + line = self.handle_cf2py_start(line) + is_f2py_directive = startlineno in self.f2py_comment_lines + + label = None + if self.ispyf: + # handle multilines + for mlstr in ['"""',"'''"]: + r = self.handle_multilines(line, startlineno, mlstr) + if r: return r + + if self.isfix: + label = line[:5].strip().lower() + if label.endswith(':'): label = label[:-1].strip() + if not line.strip(): + # empty line + return self.line_item(line[6:],startlineno,self.linecount,label) + if _is_fix_comment(line): + return self.comment_item(line, startlineno, startlineno) + for i in range(5): + if line[i] not in _spacedigits: + message = 'non-space/digit char %r found in column %i'\ + ' of fixed Fortran code' % (line[i],i+1) + if self.isfix90: + message = message + ', switching to free format mode' + message = self.format_warning_message(\ + message,startlineno, self.linecount) + self.show_message(message, sys.stderr) + self.set_mode(True, False) + else: + return self.line_item(line[6:], startlineno, self.linecount, + label, self.format_error_message(\ + message, startlineno, self.linecount)) + + if self.isfix77 and not is_f2py_directive: + lines = [line[6:72]] + while _is_fix_cont(self.get_next_line()): + # handle fix format line continuations for F77 code + line = get_single_line() + lines.append(line[6:72]) + return self.line_item(''.join(lines),startlineno,self.linecount,label) + + handle_inline_comment = self.handle_inline_comment + + if self.isfix90 and not is_f2py_directive: + # handle inline comment + newline,qc = handle_inline_comment(line[6:], startlineno) + lines = [newline] + next_line = self.get_next_line() + while _is_fix_cont(next_line) or _is_fix_comment(next_line): + # handle fix format line continuations for F90 code. + # mixing fix format and f90 line continuations is not allowed + # nor detected, just eject warnings. + line2 = get_single_line() + if _is_fix_comment(line2): + # handle fix format comments inside line continuations + citem = self.comment_item(line2,self.linecount,self.linecount) + self.fifo_item.append(citem) + else: + newline, qc = self.handle_inline_comment(line2[6:], + self.linecount, qc) + lines.append(newline) + next_line = self.get_next_line() + # no character continuation should follows now + if qc is not None: + message = self.format_message(\ + 'ASSERTION FAILURE(fix90)', + 'following character continuation: %r, expected None.'\ + % (qc), startlineno, self.linecount) + self.show_message(message, sys.stderr) + if len(lines)>1: + for i in range(len(lines)): + l = lines[i] + if l.rstrip().endswith('&'): + message = self.format_warning_message(\ + 'f90 line continuation character `&\' detected'\ + ' in fix format code', + startlineno + i, startlineno + i, l.rfind('&')+5) + self.show_message(message, sys.stderr) + return self.line_item(''.join(lines),startlineno, + self.linecount,label) + start_index = 0 + if self.isfix90: + start_index = 6 + + lines = [] + lines_append = lines.append + put_item = self.fifo_item.append + qc = None + while line is not None: + if start_index: # fix format code + line,qc = handle_inline_comment(line[start_index:], + self.linecount,qc) + is_f2py_directive = self.linecount in self.f2py_comment_lines + else: + line_lstrip = line.lstrip() + if lines: + if line_lstrip.startswith('!'): + # check for comment line within line continuation + put_item(self.comment_item(line_lstrip, + self.linecount, self.linecount)) + line = get_single_line() + continue + else: + # first line, check for a f90 label + m = _f90label_re.match(line) + if m: + assert not label,`label,m.group('label')` + label = m.group('label').strip() + if label.endswith(':'): label = label[:-1].strip() + if not self.ispyf: label = label.lower() + line = line[m.end():] + line,qc = handle_inline_comment(line, self.linecount, qc) + is_f2py_directive = self.linecount in self.f2py_comment_lines + + i = line.rfind('&') + if i!=-1: + line_i1_rstrip = line[i+1:].rstrip() + if not lines: + # first line + if i == -1 or line_i1_rstrip: + lines_append(line) + break + lines_append(line[:i]) + line = get_single_line() + continue + if i == -1 or line_i1_rstrip: + # no line continuation follows + i = len(line) + k = -1 + if i != -1: + # handle the beggining of continued line + k = line[:i].find('&') + if k != 1 and line[:k].lstrip(): + k = -1 + lines_append(line[k+1:i]) + if i==len(line): + break + line = get_single_line() + + if qc is not None: + message = self.format_message('ASSERTION FAILURE(free)', + 'following character continuation: %r, expected None.' % (qc), + startlineno, self.linecount) + self.show_message(message, sys.stderr) + return self.line_item(''.join(lines),startlineno,self.linecount,label) + + ## FortranReaderBase + +# Fortran file and string readers: + +class FortranFileReader(FortranReaderBase): + + def __init__(self, filename, + include_dirs = None): + isfree, isstrict = get_source_info(filename) + self.id = filename + self.file = open(filename,'r') + FortranReaderBase.__init__(self, self.file, isfree, isstrict) + if include_dirs is None: + self.include_dirs.insert(0, os.path.dirname(filename)) + else: + self.include_dirs = include_dirs[:] + return + + def close_source(self): + self.file.close() + +class FortranStringReader(FortranReaderBase): + + def __init__(self, string, isfree, isstrict, include_dirs = None): + self.id = 'string-'+str(id(string)) + source = StringIO(string) + FortranReaderBase.__init__(self, source, isfree, isstrict) + if include_dirs is not None: + self.include_dirs = include_dirs[:] + return + +# Testing: + +def test_f77(): + string_f77 = """ +c12346 comment + subroutine foo + call foo + 'bar +a 'g + abc=2 +cf2py call me ! hey + call you ! hi + end + '""" + reader = FortranStringReader(string_f77,False,True) + for item in reader: + print item + + filename = tempfile.mktemp()+'.f' + f = open(filename,'w') + f.write(string_f77) + f.close() + + reader = FortranFileReader(filename) + for item in reader: + print item + +def test_pyf(): + string_pyf = """\ +python module foo + interface + beginml '''1st line + 2nd line + end line'''endml='tere!fake comment'!should be a comment + a = 2 + 'charc\"onstant' ''' single line mline '''a='hi!fake comment'!should be a comment + a=\\\\\\\\\\'''not a multiline''' + !blah='''never ending multiline + b=3! hey, fake line continuation:& + c=4& !line cont + &45 + thisis_label_2 : c = 3 + xxif_isotropic_2 : if ( string_upper_compare ( o%opt_aniso, 'ISOTROPIC' ) ) then + g=3 + endif + end interface + if ( pc_get_lun() .ne. 6) & + + write ( pc_get_lun(), '( & + & /, a, /, " p=", i4, " stopping c_flag=", a, & + & /, " print unit=", i8)') & + trim(title), pcpsx_i_pel(), trim(c_flag), pc_get_lun() +end python module foo +! end of file +""" + reader = FortranStringReader(string_pyf,True, True) + for item in reader: + print item + +def test_fix90(): + string_fix90 = """\ + subroutine foo +cComment + 1234 a = 3 !inline comment + b = 3 +! + !4!line cont. with comment symbol + &5 + a = 3!f2py.14 ! pi! +! KDMO + write (obj%print_lun, *) ' KDMO : ' + write (obj%print_lun, *) ' COORD = ',coord, ' BIN_WID = ', & + obj%bin_wid,' VEL_DMO = ', obj%vel_dmo + end subroutine foo + subroutine + + & foo + end +""" + reader = FortranStringReader(string_fix90,False, False) + for item in reader: + print item + +def simple_main(): + for filename in sys.argv[1:]: + print 'Processing',filename + reader = FortranFileReader(filename) + for item in reader: + print >> sys.stdout, item + sys.stdout.flush() + pass + +def profile_main(): + import hotshot, hotshot.stats + prof = hotshot.Profile("readfortran.prof") + prof.runcall(simple_main) + prof.close() + stats = hotshot.stats.load("readfortran.prof") + stats.strip_dirs() + stats.sort_stats('time', 'calls') + stats.print_stats(30) + +if __name__ == "__main__": + #test_pyf() + #test_fix90() + #profile_main() + simple_main() diff --git a/numpy/f2py/lib/parser/sourceinfo.py b/numpy/f2py/lib/parser/sourceinfo.py new file mode 100644 index 000000000..7eb980251 --- /dev/null +++ b/numpy/f2py/lib/parser/sourceinfo.py @@ -0,0 +1,81 @@ +""" +Provides get_source_info(<filename>) function to determine the format +(free|fixed|strict|pyf) of a Fortran file. + +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: May 2006 +----- +""" + +__all__ = ['get_source_info'] + +import re +import os +import sys + +_has_f_extension = re.compile(r'.*[.](for|ftn|f77|f)\Z',re.I).match +_has_f_header = re.compile(r'-[*]-\s*fortran\s*-[*]-',re.I).search +_has_f90_header = re.compile(r'-[*]-\s*f90\s*-[*]-',re.I).search +_has_fix_header = re.compile(r'-[*]-\s*fix\s*-[*]-',re.I).search +_free_f90_start = re.compile(r'[^c*!]\s*[^\s\d\t]',re.I).match + +def get_source_info(filename): + """ + Determine if fortran file is + - in fix format and contains Fortran 77 code -> return False, True + - in fix format and contains Fortran 90 code -> return False, False + - in free format and contains Fortran 90 code -> return True, False + - in free format and contains signatures (.pyf) -> return True, True + """ + base,ext = os.path.splitext(filename) + if ext=='.pyf': + return True, True + isfree = False + isstrict = False + f = open(filename,'r') + firstline = f.readline() + f.close() + if _has_f_extension(filename) and \ + not (_has_f90_header(firstline) or _has_fix_header(firstline)): + isstrict = True + elif is_free_format(filename) and not _has_fix_header(firstline): + isfree = True + return isfree,isstrict + +def is_free_format(file): + """Check if file is in free format Fortran.""" + # f90 allows both fixed and free format, assuming fixed unless + # signs of free format are detected. + isfree = False + f = open(file,'r') + line = f.readline() + n = 10000 # the number of non-comment lines to scan for hints + if _has_f_header(line): + n = 0 + elif _has_f90_header(line): + n = 0 + isfree = True + contline = False + while n>0 and line: + line = line.rstrip() + if line and line[0]!='!': + n -= 1 + if line[0]!='\t' and _free_f90_start(line[:5]) or line[-1:]=='&': + isfree = True + break + line = f.readline() + f.close() + return isfree + +def simple_main(): + for filename in sys.argv[1:]: + isfree, isstrict = get_source_info(filename) + print '%s: isfree=%s, isstrict=%s' % (filename, isfree, isstrict) + +if __name__ == '__main__': + simple_main() diff --git a/numpy/f2py/lib/parser/splitline.py b/numpy/f2py/lib/parser/splitline.py new file mode 100644 index 000000000..9d4a40fc5 --- /dev/null +++ b/numpy/f2py/lib/parser/splitline.py @@ -0,0 +1,426 @@ +#!/usr/bin/env python +""" +Defines LineSplitter and helper functions. + +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: May 2006 +----- +""" + +__all__ = ['String','string_replace_map','splitquote','splitparen'] + +import re + +class String(str): pass +class ParenString(str): pass + +def split2(line, lower=False): + """ + Split line into non-string part and into a start of a string part. + Returns 2-tuple. The second item either is empty string or start + of a string part. + """ + return LineSplitter(line,lower=lower).split2() + +_f2py_str_findall = re.compile(r"_F2PY_STRING_CONSTANT_\d+_").findall +_is_name = re.compile(r'\w*\Z',re.I).match +_is_simple_str = re.compile(r'\w*\Z',re.I).match +_f2py_findall = re.compile(r'(_F2PY_STRING_CONSTANT_\d+_|F2PY_EXPR_TUPLE_\d+)').findall + +class string_replace_dict(dict): + """ + Dictionary object that is callable for applying map returned + by string_replace_map() function. + """ + def __call__(self, line): + for k in _f2py_findall(line): + line = line.replace(k, self[k]) + return line + +def string_replace_map(line, lower=False, + _cache={'index':0,'pindex':0}): + """ + 1) Replaces string constants with symbol `'_F2PY_STRING_CONSTANT_<index>_'` + 2) Replaces (expression) with symbol `(F2PY_EXPR_TUPLE_<index>)` + Returns a new line and the replacement map. + """ + items = [] + string_map = string_replace_dict() + rev_string_map = {} + for item in splitquote(line, lower=lower)[0]: + if isinstance(item, String) and not _is_simple_str(item[1:-1]): + key = rev_string_map.get(item) + if key is None: + _cache['index'] += 1 + index = _cache['index'] + key = "_F2PY_STRING_CONSTANT_%s_" % (index) + it = item[1:-1] + string_map[key] = it + rev_string_map[it] = key + items.append(item[0]+key+item[-1]) + else: + items.append(item) + newline = ''.join(items) + items = [] + expr_keys = [] + for item in splitparen(newline): + if isinstance(item, ParenString) and not _is_name(item[1:-1]): + key = rev_string_map.get(item) + if key is None: + _cache['pindex'] += 1 + index = _cache['pindex'] + key = 'F2PY_EXPR_TUPLE_%s' % (index) + it = item[1:-1].strip() + string_map[key] = it + rev_string_map[it] = key + expr_keys.append(key) + items.append(item[0]+key+item[-1]) + else: + items.append(item) + found_keys = set() + for k in expr_keys: + v = string_map[k] + l = _f2py_str_findall(v) + if l: + found_keys = found_keys.union(l) + for k1 in l: + v = v.replace(k1, string_map[k1]) + string_map[k] = v + for k in found_keys: + del string_map[k] + return ''.join(items), string_map + +def splitquote(line, stopchar=None, lower=False, quotechars = '"\''): + """ + Fast LineSplitter + """ + items = [] + i = 0 + while 1: + try: + char = line[i]; i += 1 + except IndexError: + break + l = [] + l_append = l.append + nofslashes = 0 + if stopchar is None: + # search for string start + while 1: + if char in quotechars and not nofslashes % 2: + stopchar = char + i -= 1 + break + if char=='\\': + nofslashes += 1 + else: + nofslashes = 0 + l_append(char) + try: + char = line[i]; i += 1 + except IndexError: + break + if not l: continue + item = ''.join(l) + if lower: item = item.lower() + items.append(item) + continue + if char==stopchar: + # string starts with quotechar + l_append(char) + try: + char = line[i]; i += 1 + except IndexError: + if l: + item = String(''.join(l)) + items.append(item) + break + # else continued string + while 1: + if char==stopchar and not nofslashes % 2: + l_append(char) + stopchar = None + break + if char=='\\': + nofslashes += 1 + else: + nofslashes = 0 + l_append(char) + try: + char = line[i]; i += 1 + except IndexError: + break + if l: + item = String(''.join(l)) + items.append(item) + return items, stopchar + +class LineSplitterBase: + + def __iter__(self): + return self + + def next(self): + item = '' + while not item: + item = self.get_item() # get_item raises StopIteration + return item + +class LineSplitter(LineSplitterBase): + """ Splits a line into non strings and strings. E.g. + abc=\"123\" -> ['abc=','\"123\"'] + Handles splitting lines with incomplete string blocks. + """ + def __init__(self, line, + quotechar = None, + lower=False, + ): + self.fifo_line = [c for c in line] + self.fifo_line.reverse() + self.quotechar = quotechar + self.lower = lower + + def split2(self): + """ + Split line until the first start of a string. + """ + try: + item1 = self.get_item() + except StopIteration: + return '','' + i = len(item1) + l = self.fifo_line[:] + l.reverse() + item2 = ''.join(l) + return item1,item2 + + def get_item(self): + fifo_pop = self.fifo_line.pop + try: + char = fifo_pop() + except IndexError: + raise StopIteration + fifo_append = self.fifo_line.append + quotechar = self.quotechar + l = [] + l_append = l.append + + nofslashes = 0 + if quotechar is None: + # search for string start + while 1: + if char in '"\'' and not nofslashes % 2: + self.quotechar = char + fifo_append(char) + break + if char=='\\': + nofslashes += 1 + else: + nofslashes = 0 + l_append(char) + try: + char = fifo_pop() + except IndexError: + break + item = ''.join(l) + if self.lower: item = item.lower() + return item + + if char==quotechar: + # string starts with quotechar + l_append(char) + try: + char = fifo_pop() + except IndexError: + return String(''.join(l)) + # else continued string + while 1: + if char==quotechar and not nofslashes % 2: + l_append(char) + self.quotechar = None + break + if char=='\\': + nofslashes += 1 + else: + nofslashes = 0 + l_append(char) + try: + char = fifo_pop() + except IndexError: + break + return String(''.join(l)) + +def splitparen(line,paren='()'): + """ + Fast LineSplitterParen. + """ + stopchar = None + startchar, endchar = paren[0],paren[1] + + items = [] + i = 0 + while 1: + try: + char = line[i]; i += 1 + except IndexError: + break + nofslashes = 0 + l = [] + l_append = l.append + if stopchar is None: + # search for parenthesis start + while 1: + if char==startchar and not nofslashes % 2: + stopchar = endchar + i -= 1 + break + if char=='\\': + nofslashes += 1 + else: + nofslashes = 0 + l_append(char) + try: + char = line[i]; i += 1 + except IndexError: + break + item = ''.join(l) + else: + nofstarts = 0 + while 1: + if char==stopchar and not nofslashes % 2 and nofstarts==1: + l_append(char) + stopchar = None + break + if char=='\\': + nofslashes += 1 + else: + nofslashes = 0 + if char==startchar: + nofstarts += 1 + elif char==endchar: + nofstarts -= 1 + l_append(char) + try: + char = line[i]; i += 1 + except IndexError: + break + item = ParenString(''.join(l)) + items.append(item) + return items + +class LineSplitterParen(LineSplitterBase): + """ Splits a line into strings and strings with parenthesis. E.g. + a(x) = b(c,d) -> ['a','(x)',' = b','(c,d)'] + """ + def __init__(self, line, paren = '()'): + self.fifo_line = [c for c in line] + self.fifo_line.reverse() + self.startchar = paren[0] + self.endchar = paren[1] + self.stopchar = None + + def get_item(self): + fifo_pop = self.fifo_line.pop + try: + char = fifo_pop() + except IndexError: + raise StopIteration + fifo_append = self.fifo_line.append + startchar = self.startchar + endchar = self.endchar + stopchar = self.stopchar + l = [] + l_append = l.append + + nofslashes = 0 + if stopchar is None: + # search for parenthesis start + while 1: + if char==startchar and not nofslashes % 2: + self.stopchar = endchar + fifo_append(char) + break + if char=='\\': + nofslashes += 1 + else: + nofslashes = 0 + l_append(char) + try: + char = fifo_pop() + except IndexError: + break + item = ''.join(l) + return item + + nofstarts = 0 + while 1: + if char==stopchar and not nofslashes % 2 and nofstarts==1: + l_append(char) + self.stopchar = None + break + if char=='\\': + nofslashes += 1 + else: + nofslashes = 0 + if char==startchar: + nofstarts += 1 + elif char==endchar: + nofstarts -= 1 + l_append(char) + try: + char = fifo_pop() + except IndexError: + break + return ParenString(''.join(l)) + +def test(): + splitter = LineSplitter('abc\\\' def"12\\"3""56"dfad\'a d\'') + l = [item for item in splitter] + assert l==['abc\\\' def','"12\\"3"','"56"','dfad','\'a d\''],`l` + assert splitter.quotechar is None + l,stopchar=splitquote('abc\\\' def"12\\"3""56"dfad\'a d\'') + assert l==['abc\\\' def','"12\\"3"','"56"','dfad','\'a d\''],`l` + assert stopchar is None + + splitter = LineSplitter('"abc123&') + l = [item for item in splitter] + assert l==['"abc123&'],`l` + assert splitter.quotechar=='"' + l,stopchar = splitquote('"abc123&') + assert l==['"abc123&'],`l` + assert stopchar=='"' + + splitter = LineSplitter(' &abc"123','"') + l = [item for item in splitter] + assert l==[' &abc"','123'] + assert splitter.quotechar is None + l,stopchar = splitquote(' &abc"123','"') + assert l==[' &abc"','123'] + assert stopchar is None + + l = split2('') + assert l==('',''),`l` + l = split2('12') + assert l==('12',''),`l` + l = split2('1"a"//"b"') + assert l==('1','"a"//"b"'),`l` + l = split2('"ab"') + assert l==('','"ab"'),`l` + + splitter = LineSplitterParen('a(b) = b(x,y(1)) b\((a)\)') + l = [item for item in splitter] + assert l==['a', '(b)', ' = b', '(x,y(1))', ' b\\(', '(a)', '\\)'],`l` + l = splitparen('a(b) = b(x,y(1)) b\((a)\)') + assert l==['a', '(b)', ' = b', '(x,y(1))', ' b\\(', '(a)', '\\)'],`l` + + l = string_replace_map('a()') + print l + print 'ok' + +if __name__ == '__main__': + test() diff --git a/numpy/f2py/lib/parser/statements.py b/numpy/f2py/lib/parser/statements.py new file mode 100644 index 000000000..b37948faf --- /dev/null +++ b/numpy/f2py/lib/parser/statements.py @@ -0,0 +1,1856 @@ +""" +Fortran single line statements. + +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: May 2006 +----- +""" + +__all__ = ['GeneralAssignment', + 'Assignment','PointerAssignment','Assign','Call','Goto','ComputedGoto','AssignedGoto', + 'Continue','Return','Stop','Print','Read','Read0','Read1','Write','Flush','Wait', + 'Contains','Allocate','Deallocate','ModuleProcedure','Access','Public','Private', + 'Close','Cycle','Backspace','Endfile','Rewind','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','ForallStmt','SpecificBinding','GenericBinding', + 'FinalBinding','Allocatable','Asynchronous','Bind','Else','ElseIf', + 'Case','WhereStmt','ElseWhere','Enumerator','FortranName','Threadsafe', + 'Depend','Check','CallStatement','CallProtoArgument','Pause'] + +import re +import sys + +from base_classes import Statement, Variable + +# Auxiliary tools + +from utils import split_comma, specs_split_comma, AnalyzeError, ParseError,\ + get_module_file, parse_bind, parse_result, is_name + +class StatementWithNamelist(Statement): + """ + <statement> [ :: ] <name-list> + """ + def process_item(self): + if self.item.has_map(): + self.isvalid = False + return + if hasattr(self,'stmtname'): + clsname = self.stmtname + else: + clsname = self.__class__.__name__ + line = self.item.get_line()[len(clsname):].lstrip() + if line.startswith('::'): + line = line[2:].lstrip() + self.items = items = [] + for item in split_comma(line): + if not is_name(item): + self.isvalid = False + return + items.append(item) + return + + def tofortran(self,isfix=None): + if hasattr(self,'stmtname'): + clsname = self.stmtname.upper() + else: + clsname = self.__class__.__name__.upper() + s = ', '.join(self.items) + if s: + s = ' ' + s + return self.get_indent_tab(isfix=isfix) + clsname + s + +# Execution statements + +class GeneralAssignment(Statement): + """ + <variable> = <expr> + <pointer variable> => <expr> + """ + + 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()) + if not m: + self.isvalid = False + return + self.sign = sign = m.group('sign') + if isinstance(self, Assignment) and sign != '=': + self.isvalid = False + return + elif isinstance(self, PointerAssignment) and sign != '=>': + self.isvalid = False + return + else: + if sign=='=>': + self.__class__ = PointerAssignment + else: + self.__class__ = Assignment + apply_map = self.item.apply_map + self.variable = apply_map(m.group('variable').replace(' ','')) + self.expr = apply_map(m.group('expr')) + return + + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + '%s %s %s' \ + % (self.variable, self.sign, self.expr) + + def analyze(self): return + +class Assignment(GeneralAssignment): + pass + +class PointerAssignment(GeneralAssignment): + pass + +class Assign(Statement): + """ + ASSIGN <label> TO <int-variable-name> + """ + modes = ['fix77'] + match = re.compile(r'assign\s*\d+\s*to\s*\w+\s*\Z',re.I).match + def process_item(self): + line = self.item.get_line()[6:].lstrip() + i = line.lower().find('to') + assert not self.item.has_map() + self.items = [line[:i].rstrip(),line[i+2:].lstrip()] + return + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'ASSIGN %s TO %s' \ + % (self.items[0], self.items[1]) + def analyze(self): return + +class Call(Statement): + """Call statement class + CALL <procedure-designator> [ ( [ <actual-arg-spec-list> ] ) ] + + <procedure-designator> = <procedure-name> + | <proc-component-ref> + | <data-ref> % <binding-name> + + <actual-arg-spec> = [ <keyword> = ] <actual-arg> + <actual-arg> = <expr> + | <variable> + | <procedure-name> + | <proc-component-ref> + | <alt-return-spec> + <alt-return-spec> = * <label> + + <proc-component-ref> = <variable> % <procedure-component-name> + + <variable> = <designator> + + Call instance has attributes: + designator + arg_list + """ + match = re.compile(r'call\b', re.I).match + + def process_item(self): + item = self.item + apply_map = item.apply_map + line = item.get_line()[4:].strip() + i = line.find('(') + items = [] + if i==-1: + self.designator = apply_map(line).strip() + else: + j = line.find(')') + if j == -1 or len(line)-1 != j: + self.isvalid = False + return + self.designator = apply_map(line[:i]).strip() + items = split_comma(line[i+1:-1], item) + self.items = items + return + + def tofortran(self, isfix=None): + s = self.get_indent_tab(isfix=isfix) + 'CALL '+str(self.designator) + if self.items: + s += '('+', '.join(map(str,self.items))+ ')' + return s + + def analyze(self): + a = self.programblock.a + variables = a.variables + if hasattr(a, 'external'): + external = a.external + if self.designator in external: + print >> sys.stderr, 'Need to analyze:',self + return + +class Goto(Statement): + """ + GO TO <label> + """ + match = re.compile(r'go\s*to\s*\d+\s*\Z', re.I).match + + def process_item(self): + assert not self.item.has_map() + self.label = self.item.get_line()[2:].lstrip()[2:].lstrip() + return + + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'GO TO %s' % (self.label) + def analyze(self): return + +class ComputedGoto(Statement): + """ + GO TO ( <label-list> ) [ , ] <scalar-int-expr> + """ + match = re.compile(r'go\s*to\s*\(',re.I).match + def process_item(self): + apply_map = self.item.apply_map + line = self.item.get_line()[2:].lstrip()[2:].lstrip() + i = line.index(')') + self.items = split_comma(line[1:i], self.item) + line = line[i+1:].lstrip() + if line.startswith(','): + line = line[1:].lstrip() + self.expr = apply_map(line) + return + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'GO TO (%s) %s' \ + % (', '.join(self.items), self.expr) + def analyze(self): return + +class AssignedGoto(Statement): + """ + GO TO <int-variable-name> [ ( <label> [ , <label> ]... ) ] + """ + modes = ['fix77'] + match = re.compile(r'go\s*to\s*\w+\s*\(?',re.I).match + def process_item(self): + line = self.item.get_line()[2:].lstrip()[2:].lstrip() + i = line.find('(') + if i==-1: + self.varname = line + self.items = [] + return + self.varname = line[:i].rstrip() + assert line[-1]==')',`line` + self + self.items = split_comma(line[i+1:-1], self.item) + return + + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) + if self.items: + return tab + 'GO TO %s (%s)' \ + % (self.varname, ', '.join(self.items)) + return tab + 'GO TO %s' % (self.varname) + def analyze(self): return + +class Continue(Statement): + """ + CONTINUE + """ + match = re.compile(r'continue\Z',re.I).match + + def process_item(self): + self.label = self.item.label + return + + def tofortran(self, isfix=None): + return self.get_indent_tab(deindent=True) + 'CONTINUE' + + def analyze(self): return + +class Return(Statement): + """ + RETURN [ <scalar-int-expr> ] + """ + match = re.compile(r'return\b',re.I).match + + def process_item(self): + self.expr = self.item.apply_map(self.item.get_line()[6:].lstrip()) + return + + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) + if self.expr: + return tab + 'RETURN %s' % (self.expr) + return tab + 'RETURN' + + def analyze(self): return + +class Stop(Statement): + """ + STOP [ <stop-code> ] + <stop-code> = <scalar-char-constant> | <1-5-digit> + """ + match = re.compile(r'stop\s*(\'\w*\'|"\w*"|\d+|)\Z',re.I).match + + def process_item(self): + self.code = self.item.apply_map(self.item.get_line()[4:].lstrip()) + return + + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) + if self.code: + return tab + 'STOP %s' % (self.code) + return tab + 'STOP' + + def analyze(self): return + +class Print(Statement): + """ + PRINT <format> [, <output-item-list>] + <format> = <default-char-expr> | <label> | * + + <output-item> = <expr> | <io-implied-do> + <io-implied-do> = ( <io-implied-do-object-list> , <implied-do-control> ) + <io-implied-do-object> = <input-item> | <output-item> + <implied-do-control> = <do-variable> = <scalar-int-expr> , <scalar-int-expr> [ , <scalar-int-expr> ] + <input-item> = <variable> | <io-implied-do> + """ + match = re.compile(r'print\s*(\'\w*\'|\"\w*\"|\d+|[*]|\b\w)', re.I).match + + def process_item(self): + item = self.item + apply_map = item.apply_map + line = item.get_line()[5:].lstrip() + items = split_comma(line, item) + self.format = items[0] + self.items = items[1:] + return + + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'PRINT %s' \ + % (', '.join([self.format]+self.items)) + def analyze(self): return + +class Read(Statement): + """ +Read0: READ ( <io-control-spec-list> ) [ <input-item-list> ] + + <io-control-spec-list> = [ UNIT = ] <io-unit> + | [ FORMAT = ] <format> + | [ NML = ] <namelist-group-name> + | ADVANCE = <scalar-default-char-expr> + ... + +Read1: READ <format> [, <input-item-list>] + <format> == <default-char-expr> | <label> | * + """ + match = re.compile(r'read\b\s*[\w(*\'"]', re.I).match + + def process_item(self): + item = self.item + line = item.get_line()[4:].lstrip() + if line.startswith('('): + self.__class__ = Read0 + else: + self.__class__ = Read1 + self.process_item() + return + def analyze(self): return + +class Read0(Read): + + def process_item(self): + item = self.item + line = item.get_line()[4:].lstrip() + i = line.find(')') + self.specs = specs_split_comma(line[1:i], item) + self.items = split_comma(line[i+1:], item) + return + + def tofortran(self, isfix=None): + s = self.get_indent_tab(isfix=isfix) + 'READ (%s)' % (', '.join(self.specs)) + if self.items: + return s + ' ' + ', '.join(self.items) + return s + +class Read1(Read): + + def process_item(self): + item = self.item + line = item.get_line()[4:].lstrip() + items = split_comma(line, item) + self.format = items[0] + self.items = items[1:] + return + + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'READ ' \ + + ', '.join([self.format]+self.items) + +class Write(Statement): + """ + WRITE ( io-control-spec-list ) [<output-item-list>] + """ + match = re.compile(r'write\s*\(', re.I).match + def process_item(self): + item = self.item + line = item.get_line()[5:].lstrip() + i = line.find(')') + assert i != -1, `line` + self.specs = specs_split_comma(line[1:i], item) + self.items = split_comma(line[i+1:], item) + return + + def tofortran(self, isfix=None): + s = self.get_indent_tab(isfix=isfix) + 'WRITE (%s)' % ', '.join(self.specs) + if self.items: + s += ' ' + ', '.join(self.items) + return s + def analyze(self): return + + +class Flush(Statement): + """ + FLUSH <file-unit-number> + FLUSH ( <flush-spec-list> ) + <flush-spec> = [ UNIT = ] <file-unit-number> + | IOSTAT = <scalar-int-variable> + | IOMSG = <iomsg-variable> + | ERR = <label> + """ + match = re.compile(r'flush\b',re.I).match + + def process_item(self): + line = self.item.get_line()[5:].lstrip() + if not line: + self.isvalid = False + return + if line.startswith('('): + assert line[-1] == ')', `line` + self.specs = specs_split_comma(line[1:-1],self.item) + else: + self.specs = specs_split_comma(line,self.item) + return + + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) + return tab + 'FLUSH (%s)' % (', '.join(self.specs)) + def analyze(self): return + +class Wait(Statement): + """ + WAIT ( <wait-spec-list> ) + <wait-spec> = [ UNIT = ] <file-unit-number> + | END = <label> + | EOR = <label> + | ERR = <label> + | ID = <scalar-int-expr> + | IOMSG = <iomsg-variable> + | IOSTAT = <scalar-int-variable> + + """ + match = re.compile(r'wait\s*\(.*\)\Z',re.I).match + def process_item(self): + self.specs = specs_split_comma(\ + self.item.get_line()[4:].lstrip()[1:-1], self.item) + return + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) + return tab + 'WAIT (%s)' % (', '.join(self.specs)) + def analyze(self): return + +class Contains(Statement): + """ + CONTAINS + """ + match = re.compile(r'contains\Z',re.I).match + def process_item(self): return + def tofortran(self, isfix=None): return self.get_indent_tab(isfix=isfix) + 'CONTAINS' + +class Allocate(Statement): + """ + ALLOCATE ( [ <type-spec> :: ] <allocation-list> [ , <alloc-opt-list> ] ) + <alloc-opt> = STAT = <stat-variable> + | ERRMSG = <errmsg-variable> + | SOURCE = <source-expr> + <allocation> = <allocate-object> [ ( <allocate-shape-spec-list> ) ] + """ + match = re.compile(r'allocate\s*\(.*\)\Z',re.I).match + def process_item(self): + line = self.item.get_line()[8:].lstrip()[1:-1].strip() + item2 = self.item.copy(line, True) + line2 = item2.get_line() + i = line2.find('::') + if i != -1: + spec = item2.apply_map(line2[:i].rstrip()) + from block_statements import type_spec + stmt = None + for cls in type_spec: + if cls.match(spec): + stmt = cls(self, item2.copy(spec)) + if stmt.isvalid: + break + if stmt is not None and stmt.isvalid: + spec = stmt + else: + self.warning('TODO: unparsed type-spec' + `spec`) + line2 = line2[i+2:].lstrip() + else: + spec = None + self.spec = spec + self.items = specs_split_comma(line2, item2) + return + + def tofortran(self, isfix=None): + t = '' + if self.spec: + t = self.spec.tostr() + ' :: ' + return self.get_indent_tab(isfix=isfix) \ + + 'ALLOCATE (%s%s)' % (t,', '.join(self.items)) + def analyze(self): return + +class Deallocate(Statement): + """ + DEALLOCATE ( <allocate-object-list> [ , <dealloc-opt-list> ] ) + <allocate-object> = <variable-name> + | <structure-component> + <structure-component> = <data-ref> + <dealloc-opt> = STAT = <stat-variable> + | ERRMSG = <errmsg-variable> + """ + match = re.compile(r'deallocate\s*\(.*\)\Z',re.I).match + def process_item(self): + line = self.item.get_line()[10:].lstrip()[1:-1].strip() + self.items = specs_split_comma(line, self.item) + return + def tofortran(self, isfix=None): return self.get_indent_tab(isfix=isfix) \ + + 'DEALLOCATE (%s)' % (', '.join(self.items)) + def analyze(self): return + +class ModuleProcedure(Statement): + """ + [ MODULE ] PROCEDURE <procedure-name-list> + """ + match = re.compile(r'(module\s*|)procedure\b',re.I).match + def process_item(self): + line = self.item.get_line() + m = self.match(line) + assert m,`line` + items = split_comma(line[m.end():].strip(), self.item) + for n in items: + if not is_name(n): + self.isvalid = False + return + self.items = items + return + + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) + return tab + 'MODULE PROCEDURE %s' % (', '.join(self.items)) + + 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): + """ + <access-spec> [ [::] <access-id-list>] + <access-spec> = PUBLIC | PRIVATE + <access-id> = <use-name> | <generic-spec> + """ + match = re.compile(r'(public|private)\b',re.I).match + def process_item(self): + clsname = self.__class__.__name__.lower() + line = self.item.get_line() + if not line.lower().startswith(clsname): + self.isvalid = False + return + line = line[len(clsname):].lstrip() + if line.startswith('::'): + line = line[2:].lstrip() + self.items = split_comma(line, self.item) + return + + def tofortran(self, isfix=None): + clsname = self.__class__.__name__.upper() + tab = self.get_indent_tab(isfix=isfix) + if self.items: + return tab + clsname + ' ' + ', '.join(self.items) + return tab + clsname + + def analyze(self): + clsname = self.__class__.__name__ + l = getattr(self.parent.a, clsname.lower() + '_id_list') + if self.items: + for name in self.items: + if name not in l: l.append(name) + else: + if '' not in l: + l.append('') + return + +class Public(Access): + is_public = True +class Private(Access): + is_public = False + +class Close(Statement): + """ + CLOSE ( <close-spec-list> ) + <close-spec> = [ UNIT = ] <file-unit-number> + | IOSTAT = <scalar-int-variable> + | IOMSG = <iomsg-variable> + | ERR = <label> + | STATUS = <scalar-default-char-expr> + """ + match = re.compile(r'close\s*\(.*\)\Z',re.I).match + def process_item(self): + line = self.item.get_line()[5:].lstrip()[1:-1].strip() + self.specs = specs_split_comma(line, self.item) + return + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) + return tab + 'CLOSE (%s)' % (', '.join(self.specs)) + def analyze(self): return + +class Cycle(Statement): + """ + CYCLE [ <do-construct-name> ] + """ + match = re.compile(r'cycle\b\s*\w*\s*\Z',re.I).match + def process_item(self): + self.name = self.item.get_line()[5:].lstrip() + return + def tofortran(self, isfix=None): + if self.name: + return self.get_indent_tab(isfix=isfix) + 'CYCLE ' + self.name + return self.get_indent_tab(isfix=isfix) + 'CYCLE' + def analyze(self): return + +class FilePositioningStatement(Statement): + """ + REWIND <file-unit-number> + REWIND ( <position-spec-list> ) + <position-spec-list> = [ UNIT = ] <file-unit-number> + | IOMSG = <iomsg-variable> + | IOSTAT = <scalar-int-variable> + | ERR = <label> + The same for BACKSPACE, ENDFILE. + """ + match = re.compile(r'(rewind|backspace|endfile)\b',re.I).match + + def process_item(self): + clsname = self.__class__.__name__.lower() + line = self.item.get_line() + if not line.lower().startswith(clsname): + self.isvalid = False + return + line = line[len(clsname):].lstrip() + if line.startswith('('): + assert line[-1]==')',`line` + spec = line[1:-1].strip() + else: + spec = line + self.specs = specs_split_comma(spec, self.item) + return + + def tofortran(self, isfix=None): + clsname = self.__class__.__name__.upper() + return self.get_indent_tab(isfix=isfix) + clsname + ' (%s)' % (', '.join(self.specs)) + def analyze(self): return + +class Backspace(FilePositioningStatement): pass + +class Endfile(FilePositioningStatement): pass + +class Rewind(FilePositioningStatement): pass + +class Open(Statement): + """ + OPEN ( <connect-spec-list> ) + <connect-spec> = [ UNIT = ] <file-unit-number> + | ACCESS = <scalar-default-char-expr> + | .. + """ + match = re.compile(r'open\s*\(.*\)\Z',re.I).match + def process_item(self): + line = self.item.get_line()[4:].lstrip()[1:-1].strip() + self.specs = specs_split_comma(line, self.item) + return + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'OPEN (%s)' % (', '.join(self.specs)) + def analyze(self): return + +class Format(Statement): + """ + FORMAT <format-specification> + <format-specification> = ( [ <format-item-list> ] ) + <format-item> = [ <r> ] <data-edit-descr> + | <control-edit-descr> + | <char-string-edit-descr> + | [ <r> ] ( <format-item-list> ) + <data-edit-descr> = I <w> [ . <m> ] + | B <w> [ . <m> ] + ... + <r|w|m|d|e> = <int-literal-constant> + <v> = <signed-int-literal-constant> + <control-edit-descr> = <position-edit-descr> + | [ <r> ] / + | : + ... + <position-edit-descr> = T <n> + | TL <n> + ... + <sign-edit-descr> = SS | SP | S + ... + + """ + match = re.compile(r'format\s*\(.*\)\Z', re.I).match + def process_item(self): + item = self.item + if not item.label: + # R1001: + self.warning('R1001: FORMAT statement must be labeled but got %r.' \ + % (item.label)) + line = item.get_line()[6:].lstrip() + assert line[0]+line[-1]=='()',`line` + self.specs = split_comma(line[1:-1], item) + return + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'FORMAT (%s)' % (', '.join(self.specs)) + def analyze(self): return + +class Save(Statement): + """ + SAVE [ [ :: ] <saved-entity-list> ] + <saved-entity> = <object-name> + | <proc-pointer-name> + | / <common-block-name> / + <proc-pointer-name> = <name> + <object-name> = <name> + """ + match = re.compile(r'save\b',re.I).match + def process_item(self): + assert not self.item.has_map() + line = self.item.get_line()[4:].lstrip() + if line.startswith('::'): + line = line[2:].lstrip() + items = [] + for s in line.split(','): + s = s.strip() + if not s: continue + if s.startswith('/'): + assert s.endswith('/'),`s` + n = s[1:-1].strip() + assert is_name(n),`n` + items.append('/%s/' % (n)) + elif is_name(s): + items.append(s) + else: + self.isvalid = False + return + self.items = items + return + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) + if not self.items: + return tab + 'SAVE' + return tab + 'SAVE %s' % (', '.join(self.items)) + def analyze(self): return + +class Data(Statement): + """ + DATA <data-stmt-set> [ [ , ] <data-stmt-set> ]... + <data-stmt-set> = <data-stmt-object-list> / <data-stmt-value-list> / + <data-stmt-object> = <variable> | <data-implied-do> + <data-implied-do> = ( <data-i-do-object-list> , <data-i-do-variable> = <scalar-int-expr> , <scalar-int-expr> [ , <scalar-int-expr> ] ) + <data-i-do-object> = <array-element> | <scalar-structure-component> | <data-implied-do> + <data-i-do-variable> = <scalar-int-variable> + <variable> = <designator> + <designator> = <object-name> + | <array-element> + | <array-section> + | <structure-component> + | <substring> + <array-element> = <data-ref> + <array-section> = <data-ref> [ ( <substring-range> ) ] + + """ + match = re.compile(r'data\b',re.I).match + + def process_item(self): + line = self.item.get_line()[4:].lstrip() + stmts = [] + self.isvalid = False + while line: + i = line.find('/') + if i==-1: return + j = line.find('/',i+1) + if j==-1: return + l1, l2 = line[:i].rstrip(),line[i+1:j].strip() + l1 = split_comma(l1, self.item) + l2 = split_comma(l2, self.item) + stmts.append((l1,l2)) + line = line[j+1:].lstrip() + if line.startswith(','): + line = line[1:].lstrip() + self.stmts = stmts + self.isvalid = True + return + + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) + l = [] + for o,v in self.stmts: + l.append('%s / %s /' %(', '.join(o),', '.join(v))) + return tab + 'DATA ' + ' '.join(l) + def analyze(self): return + +class Nullify(Statement): + """ + NULLIFY ( <pointer-object-list> ) + <pointer-object> = <variable-name> + """ + match = re.compile(r'nullify\s*\(.*\)\Z',re.I).match + def process_item(self): + line = self.item.get_line()[7:].lstrip()[1:-1].strip() + self.items = split_comma(line, self.item) + return + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'NULLIFY (%s)' % (', '.join(self.items)) + def analyze(self): return + +class Use(Statement): + """ + USE [ [ , <module-nature> ] :: ] <module-name> [ , <rename-list> ] + USE [ [ , <module-nature> ] :: ] <module-name> , ONLY : [ <only-list> ] + <module-nature> = INTRINSIC | NON_INTRINSIC + <rename> = <local-name> => <use-name> + | OPERATOR ( <local-defined-operator> ) => OPERATOR ( <use-defined-operator> ) + <only> = <generic-spec> | <only-use-name> | <rename> + <only-use-name> = <use-name> + """ + match = re.compile(r'use\b',re.I).match + def process_item(self): + line = self.item.get_line()[3:].lstrip() + nature = '' + if line.startswith(','): + i = line.find('::') + nature = line[1:i].strip().upper() + line = line[i+2:].lstrip() + if line.startswith('::'): + line = line[2:].lstrip() + if nature and not is_name(nature): + self.isvalid = False + return + self.nature = nature + i = line.find(',') + self.isonly = False + if i==-1: + self.name = line + self.items = [] + else: + self.name = line[:i].rstrip() + line = line[i+1:].lstrip() + if line.lower().startswith('only') and line[4:].lstrip().startswith(':'): + self.isonly = True + line = line[4:].lstrip()[1:].lstrip() + self.items = split_comma(line, self.item) + return + + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) + s = 'USE' + if self.nature: + s += ' ' + self.nature + ' ::' + s += ' ' + self.name + if self.isonly: + s += ', ONLY:' + elif self.items: + s += ',' + if self.items: + s += ' ' + ', '.join(self.items) + 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: + fn = get_module_file(self.name, d) + if fn is not None: + break + if fn is not None: + from readfortran import FortranFileReader + from parsefortran import FortranParser + self.info('looking module information from %r' % (fn)) + reader = FortranFileReader(fn) + parser = FortranParser(reader) + parser.parse() + parser.block.a.module.update(modules) + parser.analyze() + modules.update(parser.block.a.module) + + if not modules.has_key(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 + print use + + return + +class Exit(Statement): + """ + EXIT [ <do-construct-name> ] + """ + match = re.compile(r'exit\b\s*\w*\s*\Z',re.I).match + def process_item(self): + self.name = self.item.get_line()[4:].lstrip() + return + def tofortran(self, isfix=None): + if self.name: + return self.get_indent_tab(isfix=isfix) + 'EXIT ' + self.name + return self.get_indent_tab(isfix=isfix) + 'EXIT' + def analyze(self): return + +class Parameter(Statement): + """ + PARAMETER ( <named-constant-def-list> ) + <named-constant-def> = <named-constant> = <initialization-expr> + """ + match = re.compile(r'parameter\s*\(.*\)\Z', re.I).match + def process_item(self): + line = self.item.get_line()[9:].lstrip()[1:-1].strip() + self.items = split_comma(line, self.item) + return + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'PARAMETER (%s)' % (', '.join(self.items)) + def analyze(self): + for item in self.items: + i = item.find('=') + assert i!=-1,`item` + name = item[:i].rstrip() + value = item[i+1:].lstrip() + var = self.get_variable(name) + var.update('parameter') + var.set_init(value) + return + +class Equivalence(Statement): + """ + EQUIVALENCE <equivalence-set-list> + <equivalence-set> = ( <equivalence-object> , <equivalence-object-list> ) + <equivalence-object> = <variable-name> | <array-element> | <substring> + """ + match = re.compile(r'equivalence\s*\(.*\)\Z', re.I).match + def process_item(self): + items = [] + for s in self.item.get_line()[11:].lstrip().split(','): + s = s.strip() + assert s[0]+s[-1]=='()',`s,self.item.get_line()` + s = ', '.join(split_comma(s[1:-1], self.item)) + items.append('('+s+')') + self.items = items + return + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'EQUIVALENCE %s' % (', '.join(self.items)) + def analyze(self): return + +class Dimension(Statement): + """ + DIMENSION [ :: ] <array-name> ( <array-spec> ) [ , <array-name> ( <array-spec> ) ]... + + """ + match = re.compile(r'dimension\b', re.I).match + def process_item(self): + line = self.item.get_line()[9:].lstrip() + if line.startswith('::'): + line = line[2:].lstrip() + self.items = split_comma(line, self.item) + return + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'DIMENSION %s' % (', '.join(self.items)) + def analyze(self): + for line in self.items: + i = line.find('(') + assert i!=-1 and line.endswith(')'),`line` + name = line[:i].rstrip() + array_spec = split_comma(line[i+1:-1].strip(), self.item) + var = self.get_variable(name) + var.set_bounds(array_spec) + return + +class Target(Statement): + """ + TARGET [ :: ] <object-name> ( <array-spec> ) [ , <object-name> ( <array-spec> ) ]... + + """ + match = re.compile(r'target\b', re.I).match + def process_item(self): + line = self.item.get_line()[6:].lstrip() + if line.startswith('::'): + line = line[2:].lstrip() + self.items = split_comma(line, self.item) + return + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'TARGET %s' % (', '.join(self.items)) + def analyze(self): + for line in self.items: + i = line.find('(') + assert i!=-1 and line.endswith(')'),`line` + name = line[:i].rstrip() + array_spec = split_comma(line[i+1:-1].strip(), self.item) + var = self.get_variable(name) + var.set_bounds(array_spec) + var.update('target') + return + + +class Pointer(Statement): + """ + POINTER [ :: ] <pointer-decl-list> + <pointer-decl> = <object-name> [ ( <deferred-shape-spec-list> ) ] + | <proc-entity-name> + + """ + match = re.compile(r'pointer\b',re.I).match + def process_item(self): + line = self.item.get_line()[7:].lstrip() + if line.startswith('::'): + line = line[2:].lstrip() + self.items = split_comma(line, self.item) + return + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'POINTER %s' % (', '.join(self.items)) + def analyze(self): + for line in self.items: + i = line.find('(') + if i==-1: + name = line + array_spec = None + else: + assert line.endswith(')'),`line` + name = line[:i].rstrip() + array_spec = split_comma(line[i+1:-1].strip(), self.item) + var = self.get_variable(name) + var.set_bounds(array_spec) + var.update('pointer') + return + +class Protected(StatementWithNamelist): + """ + PROTECTED [ :: ] <entity-name-list> + """ + match = re.compile(r'protected\b',re.I).match + def analyze(self): + for name in self.items: + var = self.get_variable(name) + var.update('protected') + return + +class Volatile(StatementWithNamelist): + """ + VOLATILE [ :: ] <object-name-list> + """ + match = re.compile(r'volatile\b',re.I).match + def analyze(self): + for name in self.items: + var = self.get_variable(name) + var.update('volatile') + return + +class Value(StatementWithNamelist): + """ + VALUE [ :: ] <dummy-arg-name-list> + """ + match = re.compile(r'value\b',re.I).match + def analyze(self): + for name in self.items: + var = self.get_variable(name) + var.update('value') + return + +class ArithmeticIf(Statement): + """ + IF ( <scalar-numeric-expr> ) <label> , <label> , <label> + """ + match = re.compile(r'if\s*\(.*\)\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\Z', re.I).match + def process_item(self): + line = self.item.get_line()[2:].lstrip() + line,l2,l3 = line.rsplit(',',2) + i = line.rindex(')') + l1 = line[i+1:] + self.expr = self.item.apply_map(line[1:i]).strip() + self.labels = [l1.strip(),l2.strip(),l3.strip()] + return + + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'IF (%s) %s' \ + % (self.expr,', '.join(self.labels)) + def analyze(self): return + +class Intrinsic(StatementWithNamelist): + """ + INTRINSIC [ :: ] <intrinsic-procedure-name-list> + """ + match = re.compile(r'intrinsic\b',re.I).match + def analyze(self): + for name in self.items: + var = self.get_variable(name) + var.update('intrinsic') + return + +class Inquire(Statement): + """ + INQUIRE ( <inquire-spec-list> ) + INQUIRE ( IOLENGTH = <scalar-int-variable> ) <output-item-list> + + <inquire-spec> = [ UNIT = ] <file-unit-number> + | FILE = <file-name-expr> + ... + <output-item> = <expr> + | <io-implied-do> + """ + match = re.compile(r'inquire\s*\(',re.I).match + def process_item(self): + line = self.item.get_line()[7:].lstrip() + i = line.index(')') + self.specs = specs_split_comma(line[1:i].strip(), self.item) + self.items = split_comma(line[i+1:].lstrip(), self.item) + return + def tofortran(self, isfix=None): + if self.items: + return self.get_indent_tab(isfix=isfix) + 'INQUIRE (%s) %s' \ + % (', '.join(self.specs), ', '.join(self.items)) + return self.get_indent_tab(isfix=isfix) + 'INQUIRE (%s)' \ + % (', '.join(self.specs)) + def analyze(self): return + +class Sequence(Statement): + """ + SEQUENCE + """ + match = re.compile(r'sequence\Z',re.I).match + def process_item(self): + return + def tofortran(self, isfix=None): return self.get_indent_tab(isfix=isfix) + 'SEQUENCE' + def analyze(self): + self.parent.update_attributes('SEQUENCE') + return + +class External(StatementWithNamelist): + """ + EXTERNAL [ :: ] <external-name-list> + """ + match = re.compile(r'external\b', re.I).match + def analyze(self): + for name in self.items: + var = self.get_variable(name) + var.update('external') + return + + +class Namelist(Statement): + """ + NAMELIST / <namelist-group-name> / <namelist-group-object-list> [ [ , ] / <namelist-group-name> / <namelist-group-object-list> ]... + <namelist-group-object> = <variable-name> + """ + match = re.compile(r'namelist\b',re.I).match + def process_item(self): + line = self.item.get_line()[8:].lstrip() + items = [] + while line: + assert line.startswith('/'),`line` + i = line.find('/',1) + assert i!=-1,`line` + name = line[:i+1] + line = line[i+1:].lstrip() + i = line.find('/') + if i==-1: + items.append((name,line)) + line = '' + continue + s = line[:i].rstrip() + if s.endswith(','): + s = s[:-1].rstrip() + items.append((name,s)) + line = line[i+1:].lstrip() + self.items = items + return + + def tofortran(self, isfix=None): + l = [] + for name,s in self.items: + l.append('%s %s' % (name,s)) + tab = self.get_indent_tab(isfix=isfix) + return tab + 'NAMELIST ' + ', '.join(l) + +class Common(Statement): + """ + COMMON [ / [ <common-block-name> ] / ] <common-block-object-list> \ + [ [ , ] / [ <common-block-name> ] / <common-block-object-list> ]... + <common-block-object> = <variable-name> [ ( <explicit-shape-spec-list> ) ] + | <proc-pointer-name> + """ + match = re.compile(r'common\b',re.I).match + def process_item(self): + item = self.item + line = item.get_line()[6:].lstrip() + items = [] + while line: + if not line.startswith('/'): + name = '' + assert not items,`line` + else: + i = line.find('/',1) + assert i!=-1,`line` + name = line[1:i].strip() + line = line[i+1:].lstrip() + i = line.find('/') + if i==-1: + items.append((name,split_comma(line, item))) + line = '' + continue + s = line[:i].rstrip() + if s.endswith(','): + s = s[:-1].rstrip() + items.append((name,split_comma(s,item))) + line = line[i:].lstrip() + self.items = items + return + def tofortran(self, isfix=None): + l = [] + for name,s in self.items: + s = ', '.join(s) + if name: + l.append('/ %s / %s' % (name,s)) + else: + l.append(s) + tab = self.get_indent_tab(isfix=isfix) + return tab + 'COMMON ' + ' '.join(l) + def analyze(self): + for cname, items in self.items: + for item in items: + i = item.find('(') + if i!=-1: + assert item.endswith(')'),`item` + name = item[:i].rstrip() + shape = split_comma(item[i+1:-1].strip(), self.item) + else: + name = item + shape = None + 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): + """ + OPTIONAL [ :: ] <dummy-arg-name-list> + <dummy-arg-name> = <name> + """ + match = re.compile(r'optional\b',re.I).match + def analyze(self): + for name in self.items: + var = self.get_variable(name) + var.update('optional') + return + +class Intent(Statement): + """ + INTENT ( <intent-spec> ) [ :: ] <dummy-arg-name-list> + <intent-spec> = IN | OUT | INOUT + + generalization for pyf-files: + INTENT ( <intent-spec-list> ) [ :: ] <dummy-arg-name-list> + <intent-spec> = IN | OUT | INOUT | CACHE | HIDE | OUT = <name> + """ + match = re.compile(r'intent\s*\(',re.I).match + def process_item(self): + line = self.item.get_line()[6:].lstrip() + i = line.find(')') + self.specs = specs_split_comma(line[1:i], self.item, upper=True) + line = line[i+1:].lstrip() + if line.startswith('::'): + line = line[2:].lstrip() + self.items = [s.strip() for s in line.split(',')] + for n in self.items: + if not is_name(n): + self.isvalid = False + return + return + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'INTENT (%s) %s' \ + % (', '.join(self.specs), ', '.join(self.items)) + def analyze(self): + for name in self.items: + var = self.get_variable(name) + var.set_intent(self.specs) + return + + +class Entry(Statement): + """ + ENTRY <entry-name> [ ( [ <dummy-arg-list> ] ) [ <suffix> ] ] + <suffix> = <proc-language-binding-spec> [ RESULT ( <result-name> ) ] + | RESULT ( <result-name> ) [ <proc-language-binding-spec> ] + <proc-language-binding-spec> = <language-binding-spec> + <language-binding-spec> = BIND ( C [ , NAME = <scalar-char-initialization-expr> ] ) + <dummy-arg> = <dummy-arg-name> | * + """ + match = re.compile(r'entry\b', re.I).match + def process_item(self): + line = self.item.get_line()[5:].lstrip() + m = re.match(r'\w+', line) + name = line[:m.end()] + line = line[m.end():].lstrip() + if line.startswith('('): + i = line.find(')') + assert i!=-1,`line` + items = split_comma(line[1:i], self.item) + line = line[i+1:].lstrip() + else: + items = [] + self.bind, line = parse_bind(line, self.item) + self.result, line = parse_result(line, self.item) + if line: + assert self.bind is None,`self.bind` + self.bind, line = parse_bind(line, self.item) + assert not line,`line` + self.name = name + self.items = items + return + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) + s = tab + 'ENTRY '+self.name + if self.items: + s += ' (%s)' % (', '.join(self.items)) + if self.result: + s += ' RESULT (%s)' % (self.result) + if self.bind: + s += ' BIND (%s)' % (', '.join(self.bind)) + return s + +class Import(StatementWithNamelist): + """ + IMPORT [ [ :: ] <import-name-list> ] + """ + match = re.compile(r'import(\b|\Z)',re.I).match + +class Forall(Statement): + """ + FORALL <forall-header> <forall-assignment-stmt> + <forall-header> = ( <forall-triplet-spec-list> [ , <scalar-mask-expr> ] ) + <forall-triplet-spec> = <index-name> = <subscript> : <subscript> [ : <stride> ] + <subscript|stride> = <scalar-int-expr> + <forall-assignment-stmt> = <assignment-stmt> | <pointer-assignment-stmt> + """ + match = re.compile(r'forall\s*\(.*\).*=', re.I).match + def process_item(self): + line = self.item.get_line()[6:].lstrip() + i = line.index(')') + + line0 = line[1:i] + line = line[i+1:].lstrip() + stmt = GeneralAssignment(self, self.item.copy(line, True)) + if stmt.isvalid: + self.content = [stmt] + else: + self.isvalid = False + return + + specs = [] + mask = '' + for l in split_comma(line0,self.item): + j = l.find('=') + if j==-1: + assert not mask,`mask,l` + mask = l + continue + assert j!=-1,`l` + index = l[:j].rstrip() + it = self.item.copy(l[j+1:].lstrip()) + l = it.get_line() + k = l.split(':') + if len(k)==3: + s1, s2, s3 = map(it.apply_map, + [k[0].strip(),k[1].strip(),k[2].strip()]) + else: + assert len(k)==2,`k` + s1, s2 = map(it.apply_map, + [k[0].strip(),k[1].strip()]) + s3 = '1' + specs.append((index,s1,s2,s3)) + + self.specs = specs + self.mask = mask + return + + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) + l = [] + for index,s1,s2,s3 in self.specs: + s = '%s = %s : %s' % (index,s1,s2) + if s3!='1': + s += ' : %s' % (s3) + l.append(s) + s = ', '.join(l) + if self.mask: + s += ', ' + self.mask + return tab + 'FORALL (%s) %s' % \ + (s, str(self.content[0]).lstrip()) + def analyze(self): return + +ForallStmt = Forall + +class SpecificBinding(Statement): + """ + PROCEDURE [ ( <interface-name> ) ] [ [ , <binding-attr-list> ] :: ] <binding-name> [ => <procedure-name> ] + <binding-attr> = PASS [ ( <arg-name> ) ] + | NOPASS + | NON_OVERRIDABLE + | DEFERRED + | <access-spec> + <access-spec> = PUBLIC | PRIVATE + """ + match = re.compile(r'procedure\b',re.I).match + def process_item(self): + line = self.item.get_line()[9:].lstrip() + if line.startswith('('): + i = line.index(')') + name = line[1:i].strip() + line = line[i+1:].lstrip() + else: + name = '' + self.iname = name + if line.startswith(','): + line = line[1:].lstrip() + i = line.find('::') + if i != -1: + attrs = split_comma(line[:i], self.item) + line = line[i+2:].lstrip() + else: + attrs = [] + attrs1 = [] + for attr in attrs: + if is_name(attr): + attr = attr.upper() + else: + i = attr.find('(') + assert i!=-1 and attr.endswith(')'),`attr` + attr = '%s (%s)' % (attr[:i].rstrip().upper(), attr[i+1:-1].strip()) + attrs1.append(attr) + self.attrs = attrs1 + i = line.find('=') + if i==-1: + self.name = line + self.bname = '' + else: + self.name = line[:i].rstrip() + self.bname = line[i+1:].lstrip()[1:].lstrip() + return + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) + s = 'PROCEDURE ' + if self.iname: + s += '(' + self.iname + ') ' + if self.attrs: + s += ', ' + ', '.join(self.attrs) + ' :: ' + if self.bname: + s += '%s => %s' % (self.name, self.bname) + else: + s += self.name + return tab + s + +class GenericBinding(Statement): + """ + GENERIC [ , <access-spec> ] :: <generic-spec> => <binding-name-list> + """ + match = re.compile(r'generic\b.*::.*=\>.*\Z', re.I).match + def process_item(self): + line = self.item.get_line()[7:].lstrip() + if line.startswith(','): + line = line[1:].lstrip() + i = line.index('::') + self.aspec = line[:i].rstrip().upper() + line = line[i+2:].lstrip() + i = line.index('=>') + self.spec = self.item.apply_map(line[:i].rstrip()) + self.items = split_comma(line[i+2:].lstrip()) + return + + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) + s = 'GENERIC' + if self.aspec: + s += ', '+self.aspec + s += ' :: ' + self.spec + ' => ' + ', '.join(self.items) + return tab + s + + +class FinalBinding(StatementWithNamelist): + """ + FINAL [ :: ] <final-subroutine-name-list> + """ + stmtname = 'final' + match = re.compile(r'final\b', re.I).match + +class Allocatable(Statement): + """ + ALLOCATABLE [ :: ] <object-name> [ ( <deferred-shape-spec-list> ) ] [ , <object-name> [ ( <deferred-shape-spec-list> ) ] ]... + """ + match = re.compile(r'allocatable\b',re.I).match + def process_item(self): + line = self.item.get_line()[11:].lstrip() + if line.startswith('::'): + line = line[2:].lstrip() + self.items = split_comma(line, self.item) + return + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'ALLOCATABLE ' + ', '.join(self.items) + def analyze(self): + for line in self.items: + i = line.find('(') + if i==-1: + name = line + array_spec = None + else: + assert line.endswith(')') + name = line[:i].rstrip() + array_spec = split_comma(line[i+1:-1], self.item) + var = self.get_variable(name) + var.update('allocatable') + if array_spec is not None: + var.set_bounds(array_spec) + return + +class Asynchronous(StatementWithNamelist): + """ + ASYNCHRONOUS [ :: ] <object-name-list> + """ + match = re.compile(r'asynchronous\b',re.I).match + def analyze(self): + for name in self.items: + var = self.get_variable(name) + var.update('asynchronous') + return + + +class Bind(Statement): + """ + <language-binding-spec> [ :: ] <bind-entity-list> + <language-binding-spec> = BIND ( C [ , NAME = <scalar-char-initialization-expr> ] ) + <bind-entity> = <entity-name> | / <common-block-name> / + """ + match = re.compile(r'bind\s*\(.*\)',re.I).match + def process_item(self): + line = self.item.line + self.specs, line = parse_bind(line, self.item) + if line.startswith('::'): + line = line[2:].lstrip() + items = [] + for item in split_comma(line, self.item): + if item.startswith('/'): + assert item.endswith('/'),`item` + item = '/ ' + item[1:-1].strip() + ' /' + items.append(item) + self.items = items + return + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'BIND (%s) %s' %\ + (', '.join(self.specs), ', '.join(self.items)) + +# IF construct statements + +class Else(Statement): + """ + ELSE [<if-construct-name>] + """ + match = re.compile(r'else\b\s*\w*\s*\Z',re.I).match + + def process_item(self): + item = self.item + self.name = item.get_line()[4:].strip() + parent_name = getattr(self.parent,'name','') + if self.name and self.name!=parent_name: + self.warning('expected if-construct-name %r but got %r, skipping.'\ + % (parent_name, self.name)) + self.isvalid = False + return + + def tofortran(self, isfix=None): + if self.name: + return self.get_indent_tab(deindent=True) + 'ELSE ' + self.name + return self.get_indent_tab(deindent=True) + 'ELSE' + + def analyze(self): return + +class ElseIf(Statement): + """ + ELSE IF ( <scalar-logical-expr> ) THEN [ <if-construct-name> ] + """ + match = re.compile(r'else\s*if\s*\(.*\)\s*then\s*\w*\s*\Z',re.I).match + + def process_item(self): + item = self.item + line = item.get_line()[4:].lstrip()[2:].lstrip() + i = line.find(')') + assert line[0]=='(' + self.expr = item.apply_map(line[1:i]) + self.name = line[i+1:].lstrip()[4:].strip() + parent_name = getattr(self.parent,'name','') + if self.name and self.name!=parent_name: + self.warning('expected if-construct-name %r but got %r, skipping.'\ + % (parent_name, self.name)) + self.isvalid = False + return + + def tofortran(self, isfix=None): + s = '' + if self.name: + s = ' ' + self.name + return self.get_indent_tab(deindent=True) + 'ELSE IF (%s) THEN%s' \ + % (self.expr, s) + + def analyze(self): return + +# SelectCase construct statements + +class Case(Statement): + """ + CASE <case-selector> [ <case-constract-name> ] + <case-selector> = ( <case-value-range-list> ) | DEFAULT + <case-value-range> = <case-value> + | <case-value> : + | : <case-value> + | <case-value> : <case-value> + <case-value> = <scalar-(int|char|logical)-initialization-expr> + """ + match = re.compile(r'case\b\s*(\(.*\)|DEFAULT)\s*\w*\Z',re.I).match + def process_item(self): + #assert self.parent.__class__.__name__=='Select',`self.parent.__class__` + line = self.item.get_line()[4:].lstrip() + if line.startswith('('): + i = line.find(')') + items = split_comma(line[1:i].strip(), self.item) + line = line[i+1:].lstrip() + else: + assert line.lower().startswith('default'),`line` + items = [] + line = line[7:].lstrip() + for i in range(len(items)): + it = self.item.copy(items[i]) + rl = [] + for r in it.get_line().split(':'): + rl.append(it.apply_map(r.strip())) + items[i] = rl + self.items = items + self.name = line + parent_name = getattr(self.parent, 'name', '') + if self.name and self.name!=parent_name: + self.warning('expected case-construct-name %r but got %r, skipping.'\ + % (parent_name, self.name)) + self.isvalid = False + return + + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) + s = 'CASE' + if self.items: + l = [] + for item in self.items: + l.append((' : '.join(item)).strip()) + s += ' ( %s )' % (', '.join(l)) + else: + s += ' DEFAULT' + if self.name: + s += ' ' + self.name + return s + def analyze(self): return + +# Where construct statements + +class Where(Statement): + """ + WHERE ( <mask-expr> ) <where-assignment-stmt> + """ + match = re.compile(r'where\s*\(.*\)\s*\w.*\Z',re.I).match + def process_item(self): + line = self.item.get_line()[5:].lstrip() + i = line.index(')') + self.expr = self.item.apply_map(line[1:i].strip()) + line = line[i+1:].lstrip() + newitem = self.item.copy(line) + cls = Assignment + if cls.match(line): + stmt = cls(self, newitem) + if stmt.isvalid: + self.content = [stmt] + return + self.isvalid = False + return + + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) + return tab + 'WHERE ( %s ) %s' % (self.expr, str(self.content[0]).lstrip()) + def analyze(self): return + +WhereStmt = Where + +class ElseWhere(Statement): + """ + ELSE WHERE ( <mask-expr> ) [ <where-construct-name> ] + ELSE WHERE [ <where-construct-name> ] + """ + match = re.compile(r'else\s*where\b',re.I).match + def process_item(self): + line = self.item.get_line()[4:].lstrip()[5:].lstrip() + self.expr = None + if line.startswith('('): + i = line.index(')') + assert i != -1,`line` + self.expr = self.item.apply_map(line[1:i].strip()) + line = line[i+1:].lstrip() + self.name = line + parent_name = getattr(self.parent,'name','') + if self.name and not self.name==parent_name: + self.warning('expected where-construct-name %r but got %r, skipping.'\ + % (parent_name, self.name)) + self.isvalid = False + return + + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) + s = 'ELSE WHERE' + if self.expr is not None: + s += ' ( %s )' % (self.expr) + if self.name: + s += ' ' + self.name + return tab + s + def analyze(self): return + +# Enum construct statements + +class Enumerator(Statement): + """ + ENUMERATOR [ :: ] <enumerator-list> + <enumerator> = <named-constant> [ = <scalar-int-initialization-expr> ] + """ + match = re.compile(r'enumerator\b',re.I).match + def process_item(self): + line = self.item.get_line()[10:].lstrip() + if line.startswith('::'): + line = line[2:].lstrip() + self.items = split_comma(line, self.item) + return + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'ENUMERATOR ' + ', '.join(self.items) + +# F2PY specific statements + +class FortranName(Statement): + """ + FORTRANNAME <name> + """ + match = re.compile(r'fortranname\s*\w+\Z',re.I).match + def process_item(self): + self.value = self.item.get_line()[11:].lstrip() + return + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'FORTRANNAME ' + self.value + +class Threadsafe(Statement): + """ + THREADSAFE + """ + match = re.compile(r'threadsafe\Z',re.I).match + def process_item(self): + return + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'THREADSAFE' + +class Depend(Statement): + """ + DEPEND ( <name-list> ) [ :: ] <dummy-arg-name-list> + + """ + match = re.compile(r'depend\s*\(',re.I).match + def process_item(self): + line = self.item.get_line()[6:].lstrip() + i = line.find(')') + self.depends = split_comma(line[1:i].strip(), self.item) + line = line[i+1:].lstrip() + if line.startswith('::'): + line = line[2:].lstrip() + self.items = split_comma(line) + return + + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'DEPEND ( %s ) %s' \ + % (', '.join(self.depends), ', '.join(self.items)) + +class Check(Statement): + """ + CHECK ( <c-int-scalar-expr> ) [ :: ] <name> + + """ + match = re.compile(r'check\s*\(',re.I).match + def process_item(self): + line = self.item.get_line()[5:].lstrip() + i = line.find(')') + assert i!=-1,`line` + self.expr = self.item.apply_map(line[1:i].strip()) + line = line[i+1:].lstrip() + if line.startswith('::'): + line = line[2:].lstrip() + self.value = line + return + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'CHECK ( %s ) %s' \ + % (self.expr, self.value) + +class CallStatement(Statement): + """ + CALLSTATEMENT <c-expr> + """ + match = re.compile(r'callstatement\b', re.I).match + def process_item(self): + self.expr = self.item.apply_map(self.item.get_line()[13:].lstrip()) + return + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'CALLSTATEMENT ' + self.expr + +class CallProtoArgument(Statement): + """ + CALLPROTOARGUMENT <c-type-spec-list> + """ + match = re.compile(r'callprotoargument\b', re.I).match + def process_item(self): + self.specs = self.item.apply_map(self.item.get_line()[17:].lstrip()) + return + def tofortran(self, isfix=None): + return self.get_indent_tab(isfix=isfix) + 'CALLPROTOARGUMENT ' + self.specs + +# Non-standard statements + +class Pause(Statement): + """ + PAUSE [ <char-literal-constant|int-literal-constant> ] + """ + match = re.compile(r'pause\s*(\d+|\'\w*\'|"\w*"|)\Z', re.I).match + def process_item(self): + self.value = self.item.apply_map(self.item.get_line()[5:].lstrip()) + return + def tofortran(self, isfix=None): + if self.value: + return self.get_indent_tab(isfix=isfix) + 'PAUSE ' + self.value + return self.get_indent_tab(isfix=isfix) + 'PAUSE' + def analyze(self): return diff --git a/numpy/f2py/lib/parser/test_Fortran2003.py b/numpy/f2py/lib/parser/test_Fortran2003.py new file mode 100644 index 000000000..a8aae6081 --- /dev/null +++ b/numpy/f2py/lib/parser/test_Fortran2003.py @@ -0,0 +1,2101 @@ +from numpy.testing import * + +from Fortran2003 import * +from api import get_reader + +############################################################################### +############################### SECTION 2 #################################### +############################################################################### + +class test_Program(NumpyTestCase): # R201 + + def check_simple(self): + reader = get_reader('''\ + subroutine foo + end subroutine foo + subroutine bar + end + ''') + cls = Program + a = cls(reader) + assert isinstance(a, cls),`a` + assert_equal(str(a), 'SUBROUTINE foo\nEND SUBROUTINE foo\nSUBROUTINE bar\nEND SUBROUTINE bar') + +class test_Specification_Part(NumpyTestCase): # R204 + + def check_simple(self): + from api import get_reader + reader = get_reader('''\ + integer a''') + cls = Specification_Part + a = cls(reader) + assert isinstance(a, cls),`a` + assert_equal(str(a),'INTEGER :: a') + assert_equal(repr(a), "Specification_Part(Type_Declaration_Stmt(Intrinsic_Type_Spec('INTEGER', None), None, Entity_Decl(Name('a'), None, None, None)))") + +############################################################################### +############################### SECTION 3 #################################### +############################################################################### + +class test_Name(NumpyTestCase): # R304 + + def check_name(self): + a = Name('a') + assert isinstance(a,Name),`a` + a = Name('a2') + assert isinstance(a,Name),`a` + a = Designator('a') + assert isinstance(a,Name),`a` + a = Constant('a') + assert isinstance(a,Name),`a` + a = Expr('a') + assert isinstance(a,Name),`a` + +############################################################################### +############################### SECTION 4 #################################### +############################################################################### + +class test_Type_Param_Value(NumpyTestCase): # 402 + + def check_type_param_value(self): + cls = Type_Param_Value + a = cls('*') + assert isinstance(a,cls),`a` + assert_equal(str(a),'*') + assert_equal(repr(a),"Type_Param_Value('*')") + + a = cls(':') + assert isinstance(a,cls),`a` + assert_equal(str(a),':') + + a = cls('1+2') + assert isinstance(a,Level_2_Expr),`a` + assert_equal(str(a),'1 + 2') + +class test_Intrinsic_Type_Spec(NumpyTestCase): # R403 + + def check_intrinsic_type_spec(self): + cls = Intrinsic_Type_Spec + a = cls('INTEGER') + assert isinstance(a,cls),`a` + assert_equal(str(a),'INTEGER') + assert_equal(repr(a), "Intrinsic_Type_Spec('INTEGER', None)") + + a = cls('Integer*2') + assert isinstance(a,cls),`a` + assert_equal(str(a),'INTEGER*2') + + a = cls('real*2') + assert isinstance(a,cls),`a` + assert_equal(str(a),'REAL*2') + + a = cls('logical*2') + assert isinstance(a,cls),`a` + assert_equal(str(a),'LOGICAL*2') + + a = cls('complex*2') + assert isinstance(a,cls),`a` + assert_equal(str(a),'COMPLEX*2') + + a = cls('character*2') + assert isinstance(a,cls),`a` + assert_equal(str(a),'CHARACTER*2') + + a = cls('double complex') + assert isinstance(a,cls),`a` + assert_equal(str(a),'DOUBLE COMPLEX') + + a = cls('double precision') + assert isinstance(a,cls),`a` + assert_equal(str(a),'DOUBLE PRECISION') + +class test_Kind_Selector(NumpyTestCase): # R404 + + def check_kind_selector(self): + cls = Kind_Selector + a = cls('(1)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'(KIND = 1)') + assert_equal(repr(a),"Kind_Selector('(', Int_Literal_Constant('1', None), ')')") + + a = cls('(kind=1+2)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'(KIND = 1 + 2)') + + a = cls('* 1') + assert isinstance(a,cls),`a` + assert_equal(str(a),'*1') + +class test_Signed_Int_Literal_Constant(NumpyTestCase): # R405 + + def check_int_literal_constant(self): + cls = Signed_Int_Literal_Constant + a = cls('1') + assert isinstance(a,cls),`a` + assert_equal(str(a),'1') + assert_equal(repr(a),"%s('1', None)" % (cls.__name__)) + + a = cls('+ 21_2') + assert isinstance(a,cls),`a` + assert_equal(str(a),'+ 21_2') + assert_equal(repr(a),"%s('+ 21', '2')" % (cls.__name__)) + + a = cls('-21_SHORT') + assert isinstance(a,cls),`a` + assert_equal(str(a),'-21_SHORT') + + a = cls('21_short') + assert isinstance(a,cls),`a` + assert_equal(str(a),'21_short') + + a = cls('+1976354279568241_8') + assert isinstance(a,cls),`a` + assert_equal(str(a),'+1976354279568241_8') + +class test_Int_Literal_Constant(NumpyTestCase): # R406 + + def check_int_literal_constant(self): + cls = Int_Literal_Constant + a = cls('1') + assert isinstance(a,cls),`a` + assert_equal(str(a),'1') + assert_equal(repr(a),"%s('1', None)" % (cls.__name__)) + + a = cls('21_2') + assert isinstance(a,cls),`a` + assert_equal(str(a),'21_2') + assert_equal(repr(a),"%s('21', '2')" % (cls.__name__)) + + a = cls('21_SHORT') + assert isinstance(a,cls),`a` + assert_equal(str(a),'21_SHORT') + + a = cls('21_short') + assert isinstance(a,cls),`a` + assert_equal(str(a),'21_short') + + a = cls('1976354279568241_8') + assert isinstance(a,cls),`a` + assert_equal(str(a),'1976354279568241_8') + +class test_Binary_Constant(NumpyTestCase): # R412 + + def check_boz_literal_constant(self): + cls = Boz_Literal_Constant + bcls = Binary_Constant + a = cls('B"01"') + assert isinstance(a,bcls),`a` + assert_equal(str(a),'B"01"') + assert_equal(repr(a),"%s('B\"01\"')" % (bcls.__name__)) + +class test_Octal_Constant(NumpyTestCase): # R413 + + def check_boz_literal_constant(self): + cls = Boz_Literal_Constant + ocls = Octal_Constant + a = cls('O"017"') + assert isinstance(a,ocls),`a` + assert_equal(str(a),'O"017"') + assert_equal(repr(a),"%s('O\"017\"')" % (ocls.__name__)) + +class test_Hex_Constant(NumpyTestCase): # R414 + + def check_boz_literal_constant(self): + cls = Boz_Literal_Constant + zcls = Hex_Constant + a = cls('Z"01A"') + assert isinstance(a,zcls),`a` + assert_equal(str(a),'Z"01A"') + assert_equal(repr(a),"%s('Z\"01A\"')" % (zcls.__name__)) + +class test_Signed_Real_Literal_Constant(NumpyTestCase): # R416 + + def check_signed_real_literal_constant(self): + cls = Signed_Real_Literal_Constant + a = cls('12.78') + assert isinstance(a,cls),`a` + assert_equal(str(a),'12.78') + assert_equal(repr(a),"%s('12.78', None)" % (cls.__name__)) + + a = cls('+12.78_8') + assert isinstance(a,cls),`a` + assert_equal(str(a),'+12.78_8') + assert_equal(repr(a),"%s('+12.78', '8')" % (cls.__name__)) + + a = cls('- 12.') + assert isinstance(a,cls),`a` + assert_equal(str(a),'- 12.') + + a = cls('1.6E3') + assert isinstance(a,cls),`a` + assert_equal(str(a),'1.6E3') + + a = cls('+1.6E3_8') + assert isinstance(a,cls),`a` + assert_equal(str(a),'+1.6E3_8') + + a = cls('1.6D3') + assert isinstance(a,cls),`a` + assert_equal(str(a),'1.6D3') + + a = cls('-1.6E-3') + assert isinstance(a,cls),`a` + assert_equal(str(a),'-1.6E-3') + a = cls('1.6E+3') + assert isinstance(a,cls),`a` + assert_equal(str(a),'1.6E+3') + + a = cls('3E4') + assert isinstance(a,cls),`a` + assert_equal(str(a),'3E4') + + a = cls('.123') + assert isinstance(a,cls),`a` + assert_equal(str(a),'.123') + + a = cls('+1.6E-3') + assert isinstance(a,cls),`a` + assert_equal(str(a),'+1.6E-3') + + a = cls('10.9E7_QUAD') + assert isinstance(a,cls),`a` + assert_equal(str(a),'10.9E7_QUAD') + + a = cls('-10.9e-17_quad') + assert isinstance(a,cls),`a` + assert_equal(str(a),'-10.9E-17_quad') + +class test_Real_Literal_Constant(NumpyTestCase): # R417 + + def check_real_literal_constant(self): + cls = Real_Literal_Constant + a = cls('12.78') + assert isinstance(a,cls),`a` + assert_equal(str(a),'12.78') + assert_equal(repr(a),"%s('12.78', None)" % (cls.__name__)) + + a = cls('12.78_8') + assert isinstance(a,cls),`a` + assert_equal(str(a),'12.78_8') + assert_equal(repr(a),"%s('12.78', '8')" % (cls.__name__)) + + a = cls('12.') + assert isinstance(a,cls),`a` + assert_equal(str(a),'12.') + + a = cls('1.6E3') + assert isinstance(a,cls),`a` + assert_equal(str(a),'1.6E3') + + a = cls('1.6E3_8') + assert isinstance(a,cls),`a` + assert_equal(str(a),'1.6E3_8') + + a = cls('1.6D3') + assert isinstance(a,cls),`a` + assert_equal(str(a),'1.6D3') + + a = cls('1.6E-3') + assert isinstance(a,cls),`a` + assert_equal(str(a),'1.6E-3') + a = cls('1.6E+3') + assert isinstance(a,cls),`a` + assert_equal(str(a),'1.6E+3') + + a = cls('3E4') + assert isinstance(a,cls),`a` + assert_equal(str(a),'3E4') + + a = cls('.123') + assert isinstance(a,cls),`a` + assert_equal(str(a),'.123') + + a = cls('1.6E-3') + assert isinstance(a,cls),`a` + assert_equal(str(a),'1.6E-3') + + a = cls('10.9E7_QUAD') + assert isinstance(a,cls),`a` + assert_equal(str(a),'10.9E7_QUAD') + + a = cls('10.9e-17_quad') + assert isinstance(a,cls),`a` + assert_equal(str(a),'10.9E-17_quad') + + a = cls('0.0D+0') + assert isinstance(a,cls),`a` + assert_equal(str(a),'0.0D+0') + +class test_Char_Selector(NumpyTestCase): # R424 + + def check_char_selector(self): + cls = Char_Selector + a = cls('(len=2, kind=8)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'(LEN = 2, KIND = 8)') + assert_equal(repr(a),"Char_Selector(Int_Literal_Constant('2', None), Int_Literal_Constant('8', None))") + + + a = cls('(2, kind=8)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'(LEN = 2, KIND = 8)') + + a = cls('(2, 8)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'(LEN = 2, KIND = 8)') + + a = cls('(kind=8)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'(KIND = 8)') + + a = cls('(kind=8,len=2)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'(LEN = 2, KIND = 8)') + +class test_Complex_Literal_Constant(NumpyTestCase): # R421 + + def check_complex_literal_constant(self): + cls = Complex_Literal_Constant + a = cls('(1.0, -1.0)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'(1.0, -1.0)') + assert_equal(repr(a),"Complex_Literal_Constant(Signed_Real_Literal_Constant('1.0', None), Signed_Real_Literal_Constant('-1.0', None))") + + a = cls('(3,3.1E6)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'(3, 3.1E6)') + + a = cls('(4.0_4, 3.6E7_8)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'(4.0_4, 3.6E7_8)') + + a = cls('( 0., PI)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'(0., PI)') + + +class test_Type_Name(NumpyTestCase): # C424 + + def check_simple(self): + cls = Type_Name + a = cls('a') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a') + assert_equal(repr(a),"Type_Name('a')") + + self.assertRaises(NoMatchError,cls,'integer') + self.assertRaises(NoMatchError,cls,'doubleprecision') + +class test_Length_Selector(NumpyTestCase): # R425 + + def check_length_selector(self): + cls = Length_Selector + a = cls('( len = *)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'(LEN = *)') + assert_equal(repr(a),"Length_Selector('(', Type_Param_Value('*'), ')')") + + a = cls('*2,') + assert isinstance(a,cls),`a` + assert_equal(str(a),'*2') + +class test_Char_Length(NumpyTestCase): # R426 + + def check_char_length(self): + cls = Char_Length + a = cls('(1)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'(1)') + assert_equal(repr(a),"Char_Length('(', Int_Literal_Constant('1', None), ')')") + + a = cls('1') + assert isinstance(a,Int_Literal_Constant),`a` + assert_equal(str(a),'1') + + a = cls('(*)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'(*)') + + a = cls('(:)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'(:)') + +class test_Char_Literal_Constant(NumpyTestCase): # R427 + + def check_char_literal_constant(self): + cls = Char_Literal_Constant + a = cls('NIH_"DO"') + assert isinstance(a,cls),`a` + assert_equal(str(a),'NIH_"DO"') + assert_equal(repr(a),'Char_Literal_Constant(\'"DO"\', \'NIH\')') + + a = cls("'DO'") + assert isinstance(a,cls),`a` + assert_equal(str(a),"'DO'") + assert_equal(repr(a),'Char_Literal_Constant("\'DO\'", None)') + + a = cls("'DON''T'") + assert isinstance(a,cls),`a` + assert_equal(str(a),"'DON''T'") + + a = cls('"DON\'T"') + assert isinstance(a,cls),`a` + assert_equal(str(a),'"DON\'T"') + + a = cls('""') + assert isinstance(a,cls),`a` + assert_equal(str(a),'""') + + a = cls("''") + assert isinstance(a,cls),`a` + assert_equal(str(a),"''") + + a = cls('"hey ha(ada)\t"') + assert isinstance(a,cls),`a` + assert_equal(str(a),'"hey ha(ada)\t"') + +class test_Logical_Literal_Constant(NumpyTestCase): # R428 + + def check_logical_literal_constant(self): + cls = Logical_Literal_Constant + a = cls('.TRUE.') + assert isinstance(a,cls),`a` + assert_equal(str(a),'.TRUE.') + assert_equal(repr(a),"%s('.TRUE.', None)" % (cls.__name__)) + + a = cls('.True.') + assert isinstance(a,cls),`a` + assert_equal(str(a),'.TRUE.') + + a = cls('.FALSE.') + assert isinstance(a,cls),`a` + assert_equal(str(a),'.FALSE.') + + a = cls('.TRUE._HA') + assert isinstance(a,cls),`a` + assert_equal(str(a),'.TRUE._HA') + +class test_Derived_Type_Stmt(NumpyTestCase): # R430 + + def check_simple(self): + cls = Derived_Type_Stmt + a = cls('type a') + assert isinstance(a, cls),`a` + assert_equal(str(a),'TYPE :: a') + assert_equal(repr(a),"Derived_Type_Stmt(None, Type_Name('a'), None)") + + a = cls('type ::a(b,c)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'TYPE :: a(b, c)') + + a = cls('type, private, abstract::a(b,c)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'TYPE, PRIVATE, ABSTRACT :: a(b, c)') + +class test_Type_Name(NumpyTestCase): # C423 + + def check_simple(self): + cls = Type_Name + a = cls('a') + assert isinstance(a, cls),`a` + assert_equal(str(a),'a') + assert_equal(repr(a),"Type_Name('a')") + +class test_Type_Attr_Spec(NumpyTestCase): # R431 + + def check_simple(self): + cls = Type_Attr_Spec + a = cls('abstract') + assert isinstance(a, cls),`a` + assert_equal(str(a),'ABSTRACT') + assert_equal(repr(a),"Type_Attr_Spec('ABSTRACT')") + + a = cls('bind (c )') + assert isinstance(a, Language_Binding_Spec),`a` + assert_equal(str(a),'BIND(C)') + + a = cls('extends(a)') + assert isinstance(a, Type_EXTENDS_Parent_Type_Name),`a` + assert_equal(str(a),'EXTENDS(a)') + + a = cls('private') + assert isinstance(a, Access_Spec),`a` + assert_equal(str(a),'PRIVATE') + + +class test_End_Type_Stmt(NumpyTestCase): # R433 + + def check_simple(self): + cls = End_Type_Stmt + a = cls('end type') + assert isinstance(a, cls),`a` + assert_equal(str(a),'END TYPE') + assert_equal(repr(a),"End_Type_Stmt('TYPE', None)") + + a = cls('end type a') + assert isinstance(a, cls),`a` + assert_equal(str(a),'END TYPE a') + +class test_Sequence_Stmt(NumpyTestCase): # R434 + + def check_simple(self): + cls = Sequence_Stmt + a = cls('sequence') + assert isinstance(a, cls),`a` + assert_equal(str(a),'SEQUENCE') + assert_equal(repr(a),"Sequence_Stmt('SEQUENCE')") + +class test_Type_Param_Def_Stmt(NumpyTestCase): # R435 + + def check_simple(self): + cls = Type_Param_Def_Stmt + a = cls('integer ,kind :: a') + assert isinstance(a, cls),`a` + assert_equal(str(a),'INTEGER, KIND :: a') + assert_equal(repr(a),"Type_Param_Def_Stmt(None, Type_Param_Attr_Spec('KIND'), Name('a'))") + + a = cls('integer*2 ,len :: a=3, b=2+c') + assert isinstance(a, cls),`a` + assert_equal(str(a),'INTEGER*2, LEN :: a = 3, b = 2 + c') + +class test_Type_Param_Decl(NumpyTestCase): # R436 + + def check_simple(self): + cls = Type_Param_Decl + a = cls('a=2') + assert isinstance(a, cls),`a` + assert_equal(str(a),'a = 2') + assert_equal(repr(a),"Type_Param_Decl(Name('a'), '=', Int_Literal_Constant('2', None))") + + a = cls('a') + assert isinstance(a, Name),`a` + assert_equal(str(a),'a') + +class test_Type_Param_Attr_Spec(NumpyTestCase): # R437 + + def check_simple(self): + cls = Type_Param_Attr_Spec + a = cls('kind') + assert isinstance(a, cls),`a` + assert_equal(str(a),'KIND') + assert_equal(repr(a),"Type_Param_Attr_Spec('KIND')") + + a = cls('len') + assert isinstance(a, cls),`a` + assert_equal(str(a),'LEN') + +class test_Component_Attr_Spec(NumpyTestCase): # R441 + + def check_simple(self): + cls = Component_Attr_Spec + a = cls('pointer') + assert isinstance(a, cls),`a` + assert_equal(str(a),'POINTER') + assert_equal(repr(a),"Component_Attr_Spec('POINTER')") + + a = cls('allocatable') + assert isinstance(a, cls),`a` + assert_equal(str(a),'ALLOCATABLE') + + a = cls('dimension(a)') + assert isinstance(a, Dimension_Component_Attr_Spec),`a` + assert_equal(str(a),'DIMENSION(a)') + + a = cls('private') + assert isinstance(a, Access_Spec),`a` + assert_equal(str(a),'PRIVATE') + +class test_Component_Decl(NumpyTestCase): # R442 + + def check_simple(self): + cls = Component_Decl + a = cls('a(1)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'a(1)') + assert_equal(repr(a),"Component_Decl(Name('a'), Explicit_Shape_Spec(None, Int_Literal_Constant('1', None)), None, None)") + + a = cls('a(1)*(3)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'a(1)*(3)') + + a = cls('a(1)*(3) = 2') + assert isinstance(a, cls),`a` + assert_equal(str(a),'a(1)*(3) = 2') + + a = cls('a(1) => NULL') + assert isinstance(a, cls),`a` + assert_equal(str(a),'a(1) => NULL') + +class test_Final_Binding(NumpyTestCase): # R454 + + def check_simple(self): + cls = Final_Binding + a = cls('final a, b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'FINAL :: a, b') + assert_equal(repr(a),"Final_Binding('FINAL', Final_Subroutine_Name_List(',', (Name('a'), Name('b'))))") + + a = cls('final::a') + assert isinstance(a,cls),`a` + assert_equal(str(a),'FINAL :: a') + +class test_Derived_Type_Spec(NumpyTestCase): # R455 + + def check_simple(self): + cls = Derived_Type_Spec + a = cls('a(b)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a(b)') + assert_equal(repr(a),"Derived_Type_Spec(Type_Name('a'), Name('b'))") + + a = cls('a(b,c,g=1)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a(b, c, g = 1)') + + a = cls('a') + assert isinstance(a,Name),`a` + assert_equal(str(a),'a') + + a = cls('a()') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a()') + +class test_Type_Param_Spec(NumpyTestCase): # R456 + + def check_type_param_spec(self): + cls = Type_Param_Spec + a = cls('a=1') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a = 1') + assert_equal(repr(a),"Type_Param_Spec(Name('a'), Int_Literal_Constant('1', None))") + + a = cls('k=a') + assert isinstance(a,cls),`a` + assert_equal(str(a),'k = a') + + a = cls('k=:') + assert isinstance(a,cls),`a` + assert_equal(str(a),'k = :') + +class test_Type_Param_Spec_List(NumpyTestCase): # R456-list + + def check_type_param_spec_list(self): + cls = Type_Param_Spec_List + + a = cls('a,b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a, b') + assert_equal(repr(a),"Type_Param_Spec_List(',', (Name('a'), Name('b')))") + + a = cls('a') + assert isinstance(a,Name),`a` + + a = cls('k=a,c,g=1') + assert isinstance(a,cls),`a` + assert_equal(str(a),'k = a, c, g = 1') + +class test_Structure_Constructor_2(NumpyTestCase): # R457.b + + def check_simple(self): + cls = Structure_Constructor_2 + a = cls('k=a') + assert isinstance(a,cls),`a` + assert_equal(str(a),'k = a') + assert_equal(repr(a),"Structure_Constructor_2(Name('k'), Name('a'))") + + a = cls('a') + assert isinstance(a,Name),`a` + assert_equal(str(a),'a') + +class test_Structure_Constructor(NumpyTestCase): # R457 + + def check_structure_constructor(self): + cls = Structure_Constructor + a = cls('t()') + assert isinstance(a,cls),`a` + assert_equal(str(a),'t()') + assert_equal(repr(a),"Structure_Constructor(Type_Name('t'), None)") + + a = cls('t(s=1, a)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'t(s = 1, a)') + + a = cls('a=k') + assert isinstance(a,Structure_Constructor_2),`a` + assert_equal(str(a),'a = k') + assert_equal(repr(a),"Structure_Constructor_2(Name('a'), Name('k'))") + + a = cls('a') + assert isinstance(a,Name),`a` + assert_equal(str(a),'a') + +class test_Component_Spec(NumpyTestCase): # R458 + + def check_simple(self): + cls = Component_Spec + a = cls('k=a') + assert isinstance(a,cls),`a` + assert_equal(str(a),'k = a') + assert_equal(repr(a),"Component_Spec(Name('k'), Name('a'))") + + a = cls('a') + assert isinstance(a,Name),`a` + assert_equal(str(a),'a') + + a = cls('a % b') + assert isinstance(a, Proc_Component_Ref),`a` + assert_equal(str(a),'a % b') + + a = cls('s =a % b') + assert isinstance(a, Component_Spec),`a` + assert_equal(str(a),'s = a % b') + +class test_Component_Spec_List(NumpyTestCase): # R458-list + + def check_simple(self): + cls = Component_Spec_List + a = cls('k=a, b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'k = a, b') + assert_equal(repr(a),"Component_Spec_List(',', (Component_Spec(Name('k'), Name('a')), Name('b')))") + + a = cls('k=a, c') + assert isinstance(a,cls),`a` + assert_equal(str(a),'k = a, c') + +class test_Array_Constructor(NumpyTestCase): # R465 + + def check_simple(self): + cls = Array_Constructor + a = cls('(/a/)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'(/a/)') + assert_equal(repr(a),"Array_Constructor('(/', Name('a'), '/)')") + + a = cls('[a]') + assert isinstance(a,cls),`a` + assert_equal(str(a),'[a]') + assert_equal(repr(a),"Array_Constructor('[', Name('a'), ']')") + + a = cls('[integer::a]') + assert isinstance(a,cls),`a` + assert_equal(str(a),'[INTEGER :: a]') + + a = cls('[integer::a,b]') + assert isinstance(a,cls),`a` + assert_equal(str(a),'[INTEGER :: a, b]') + +class test_Ac_Spec(NumpyTestCase): # R466 + + def check_ac_spec(self): + cls = Ac_Spec + a = cls('integer ::') + assert isinstance(a,cls),`a` + assert_equal(str(a),'INTEGER ::') + assert_equal(repr(a),"Ac_Spec(Intrinsic_Type_Spec('INTEGER', None), None)") + + a = cls('integer :: a,b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'INTEGER :: a, b') + + a = cls('a,b') + assert isinstance(a,Ac_Value_List),`a` + assert_equal(str(a),'a, b') + + a = cls('integer :: a, (a, b, n = 1, 5)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'INTEGER :: a, (a, b, n = 1, 5)') + +class test_Ac_Value_List(NumpyTestCase): # R469-list + + def check_ac_value_list(self): + cls = Ac_Value_List + a = cls('a, b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a, b') + assert_equal(repr(a),"Ac_Value_List(',', (Name('a'), Name('b')))") + + a = cls('a') + assert isinstance(a,Name),`a` + assert_equal(str(a),'a') + +class test_Ac_Implied_Do(NumpyTestCase): # R470 + + def check_ac_implied_do(self): + cls = Ac_Implied_Do + a = cls('( a, b, n = 1, 5 )') + assert isinstance(a,cls),`a` + assert_equal(str(a),'(a, b, n = 1, 5)') + assert_equal(repr(a),"Ac_Implied_Do(Ac_Value_List(',', (Name('a'), Name('b'))), Ac_Implied_Do_Control(Name('n'), [Int_Literal_Constant('1', None), Int_Literal_Constant('5', None)]))") + +class test_Ac_Implied_Do_Control(NumpyTestCase): # R471 + + def check_ac_implied_do_control(self): + cls = Ac_Implied_Do_Control + a = cls('n = 3, 5') + assert isinstance(a,cls),`a` + assert_equal(str(a),'n = 3, 5') + assert_equal(repr(a),"Ac_Implied_Do_Control(Name('n'), [Int_Literal_Constant('3', None), Int_Literal_Constant('5', None)])") + + a = cls('n = 3+1, 5, 1') + assert isinstance(a,cls),`a` + assert_equal(str(a),'n = 3 + 1, 5, 1') + +############################################################################### +############################### SECTION 5 #################################### +############################################################################### + +class test_Type_Declaration_Stmt(NumpyTestCase): # R501 + + def check_simple(self): + cls = Type_Declaration_Stmt + a = cls('integer a') + assert isinstance(a, cls),`a` + assert_equal(str(a), 'INTEGER :: a') + assert_equal(repr(a), "Type_Declaration_Stmt(Intrinsic_Type_Spec('INTEGER', None), None, Entity_Decl(Name('a'), None, None, None))") + + a = cls('integer ,dimension(2):: a*3') + assert isinstance(a, cls),`a` + assert_equal(str(a), 'INTEGER, DIMENSION(2) :: a*3') + + a = cls('real a') + assert isinstance(a, cls),`a` + assert_equal(str(a), 'REAL :: a') + assert_equal(repr(a), "Type_Declaration_Stmt(Intrinsic_Type_Spec('REAL', None), None, Entity_Decl(Name('a'), None, None, None))") + + a = cls('REAL A( LDA, * ), B( LDB, * )') + assert isinstance(a, cls),`a` + + a = cls('DOUBLE PRECISION ALPHA, BETA') + assert isinstance(a, cls),`a` + +class test_Declaration_Type_Spec(NumpyTestCase): # R502 + + def check_simple(self): + cls = Declaration_Type_Spec + a = cls('Integer*2') + assert isinstance(a, Intrinsic_Type_Spec),`a` + assert_equal(str(a), 'INTEGER*2') + + a = cls('type(foo)') + assert isinstance(a, cls),`a` + assert_equal(str(a), 'TYPE(foo)') + assert_equal(repr(a), "Declaration_Type_Spec('TYPE', Type_Name('foo'))") + +class test_Attr_Spec(NumpyTestCase): # R503 + + def check_simple(self): + cls = Attr_Spec + a = cls('allocatable') + assert isinstance(a, cls),`a` + assert_equal(str(a), 'ALLOCATABLE') + + a = cls('dimension(a)') + assert isinstance(a, Dimension_Attr_Spec),`a` + assert_equal(str(a),'DIMENSION(a)') + +class test_Dimension_Attr_Spec(NumpyTestCase): # R503.d + + def check_simple(self): + cls = Dimension_Attr_Spec + a = cls('dimension(a)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'DIMENSION(a)') + assert_equal(repr(a),"Dimension_Attr_Spec('DIMENSION', Explicit_Shape_Spec(None, Name('a')))") + +class test_Intent_Attr_Spec(NumpyTestCase): # R503.f + + def check_simple(self): + cls = Intent_Attr_Spec + a = cls('intent(in)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'INTENT(IN)') + assert_equal(repr(a),"Intent_Attr_Spec('INTENT', Intent_Spec('IN'))") + +class test_Entity_Decl(NumpyTestCase): # 504 + + def check_simple(self): + cls = Entity_Decl + a = cls('a(1)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'a(1)') + assert_equal(repr(a),"Entity_Decl(Name('a'), Explicit_Shape_Spec(None, Int_Literal_Constant('1', None)), None, None)") + + a = cls('a(1)*(3)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'a(1)*(3)') + + a = cls('a(1)*(3) = 2') + assert isinstance(a, cls),`a` + assert_equal(str(a),'a(1)*(3) = 2') + +class test_Access_Spec(NumpyTestCase): # R508 + + def check_simple(self): + cls = Access_Spec + a = cls('private') + assert isinstance(a, cls),`a` + assert_equal(str(a),'PRIVATE') + assert_equal(repr(a),"Access_Spec('PRIVATE')") + + a = cls('public') + assert isinstance(a, cls),`a` + assert_equal(str(a),'PUBLIC') + +class test_Language_Binding_Spec(NumpyTestCase): # R509 + + def check_simple(self): + cls = Language_Binding_Spec + a = cls('bind(c)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'BIND(C)') + assert_equal(repr(a),'Language_Binding_Spec(None)') + + a = cls('bind(c, name="hey")') + assert isinstance(a, cls),`a` + assert_equal(str(a),'BIND(C, NAME = "hey")') + +class test_Explicit_Shape_Spec(NumpyTestCase): # R511 + + def check_simple(self): + cls = Explicit_Shape_Spec + a = cls('a:b') + assert isinstance(a, cls),`a` + assert_equal(str(a),'a : b') + assert_equal(repr(a),"Explicit_Shape_Spec(Name('a'), Name('b'))") + + a = cls('a') + assert isinstance(a, cls),`a` + assert_equal(str(a),'a') + +class test_Upper_Bound(NumpyTestCase): # R513 + + def check_simple(self): + cls = Upper_Bound + a = cls('a') + assert isinstance(a, Name),`a` + assert_equal(str(a),'a') + + self.assertRaises(NoMatchError,cls,'*') + +class test_Assumed_Shape_Spec(NumpyTestCase): # R514 + + def check_simple(self): + cls = Assumed_Shape_Spec + a = cls(':') + assert isinstance(a, cls),`a` + assert_equal(str(a),':') + assert_equal(repr(a),'Assumed_Shape_Spec(None, None)') + + a = cls('a :') + assert isinstance(a, cls),`a` + assert_equal(str(a),'a :') + +class test_Deferred_Shape_Spec(NumpyTestCase): # R515 + + def check_simple(self): + cls = Deferred_Shape_Spec + a = cls(':') + assert isinstance(a, cls),`a` + assert_equal(str(a),':') + assert_equal(repr(a),'Deferred_Shape_Spec(None, None)') + + +class test_Assumed_Size_Spec(NumpyTestCase): # R516 + + def check_simple(self): + cls = Assumed_Size_Spec + a = cls('*') + assert isinstance(a, cls),`a` + assert_equal(str(a),'*') + assert_equal(repr(a),'Assumed_Size_Spec(None, None)') + + a = cls('1:*') + assert isinstance(a, cls),`a` + assert_equal(str(a),'1 : *') + + a = cls('a,1:*') + assert isinstance(a, cls),`a` + assert_equal(str(a),'a, 1 : *') + + a = cls('a:b,1:*') + assert isinstance(a, cls),`a` + assert_equal(str(a),'a : b, 1 : *') + +class test_Access_Stmt(NumpyTestCase): # R518 + + def check_simple(self): + cls = Access_Stmt + a = cls('private') + assert isinstance(a, cls),`a` + assert_equal(str(a),'PRIVATE') + assert_equal(repr(a),"Access_Stmt('PRIVATE', None)") + + a = cls('public a,b') + assert isinstance(a, cls),`a` + assert_equal(str(a),'PUBLIC :: a, b') + + a = cls('public ::a') + assert isinstance(a, cls),`a` + assert_equal(str(a),'PUBLIC :: a') + +class test_Parameter_Stmt(NumpyTestCase): # R538 + + def check_simple(self): + cls = Parameter_Stmt + a = cls('parameter(a=1)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'PARAMETER(a = 1)') + assert_equal(repr(a),"Parameter_Stmt('PARAMETER', Named_Constant_Def(Name('a'), Int_Literal_Constant('1', None)))") + + a = cls('parameter(a=1, b=a+2)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'PARAMETER(a = 1, b = a + 2)') + + a = cls('PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 )') + assert isinstance(a, cls),`a` + assert_equal(str(a),'PARAMETER(ONE = 1.0D+0, ZERO = 0.0D+0)') + +class test_Named_Constant_Def(NumpyTestCase): # R539 + + def check_simple(self): + cls = Named_Constant_Def + a = cls('a=1') + assert isinstance(a, cls),`a` + assert_equal(str(a),'a = 1') + assert_equal(repr(a),"Named_Constant_Def(Name('a'), Int_Literal_Constant('1', None))") + +class test_Pointer_Decl(NumpyTestCase): # R541 + + def check_simple(self): + cls = Pointer_Decl + a = cls('a(:)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'a(:)') + assert_equal(repr(a),"Pointer_Decl(Name('a'), Deferred_Shape_Spec(None, None))") + + a = cls('a(:,:)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'a(:, :)') + +class test_Implicit_Stmt(NumpyTestCase): # R549 + + def check_simple(self): + cls = Implicit_Stmt + a = cls('implicitnone') + assert isinstance(a, cls),`a` + assert_equal(str(a),'IMPLICIT NONE') + assert_equal(repr(a),"Implicit_Stmt('IMPLICIT NONE', None)") + + a = cls('implicit real(a-d), double precision(r-t,x), type(a) (y-z)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'IMPLICIT REAL(A - D), DOUBLE PRECISION(R - T, X), TYPE(a)(Y - Z)') + +class test_Implicit_Spec(NumpyTestCase): # R550 + + def check_simple(self): + cls = Implicit_Spec + a = cls('integer (a-z)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'INTEGER(A - Z)') + assert_equal(repr(a),"Implicit_Spec(Intrinsic_Type_Spec('INTEGER', None), Letter_Spec('A', 'Z'))") + + a = cls('double complex (r,d-g)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'DOUBLE COMPLEX(R, D - G)') + +class test_Letter_Spec(NumpyTestCase): # R551 + + def check_simple(self): + cls = Letter_Spec + a = cls('a-z') + assert isinstance(a, cls),`a` + assert_equal(str(a),'A - Z') + assert_equal(repr(a),"Letter_Spec('A', 'Z')") + + a = cls('d') + assert isinstance(a, cls),`a` + assert_equal(str(a),'D') + +class test_Equivalence_Stmt(NumpyTestCase): # R554 + + def check_simple(self): + cls = Equivalence_Stmt + a = cls('equivalence (a, b ,z)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'EQUIVALENCE(a, b, z)') + assert_equal(repr(a),"Equivalence_Stmt('EQUIVALENCE', Equivalence_Set(Name('a'), Equivalence_Object_List(',', (Name('b'), Name('z')))))") + + a = cls('equivalence (a, b ,z),(b,l)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'EQUIVALENCE(a, b, z), (b, l)') + +class test_Common_Stmt(NumpyTestCase): # R557 + + def check_simple(self): + cls = Common_Stmt + a = cls('common a') + assert isinstance(a, cls),`a` + assert_equal(str(a),'COMMON // a') + assert_equal(repr(a),"Common_Stmt([(None, Name('a'))])") + + a = cls('common // a,b') + assert isinstance(a, cls),`a` + assert_equal(str(a),'COMMON // a, b') + + a = cls('common /name/ a,b') + assert isinstance(a, cls),`a` + assert_equal(str(a),'COMMON /name/ a, b') + + a = cls('common /name/ a,b(4,5) // c, /ljuks/ g(2)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'COMMON /name/ a, b(4, 5) // c /ljuks/ g(2)') + +class test_Common_Block_Object(NumpyTestCase): # R558 + + def check_simple(self): + cls = Common_Block_Object + a = cls('a(2)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'a(2)') + assert_equal(repr(a),"Common_Block_Object(Name('a'), Explicit_Shape_Spec(None, Int_Literal_Constant('2', None)))") + + a = cls('a') + assert isinstance(a, Name),`a` + assert_equal(str(a),'a') + + +############################################################################### +############################### SECTION 6 #################################### +############################################################################### + +class test_Substring(NumpyTestCase): # R609 + + def check_simple(self): + cls = Substring + a = cls('a(:)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'a(:)') + assert_equal(repr(a),"Substring(Name('a'), Substring_Range(None, None))") + + a = cls('a(1:2)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a(1 : 2)') + assert_equal(repr(a),"Substring(Name('a'), Substring_Range(Int_Literal_Constant('1', None), Int_Literal_Constant('2', None)))") + + +class test_Substring_Range(NumpyTestCase): # R611 + + def check_simple(self): + cls = Substring_Range + a = cls(':') + assert isinstance(a, cls),`a` + assert_equal(str(a),':') + assert_equal(repr(a),"Substring_Range(None, None)") + + a = cls('a+1:') + assert isinstance(a, cls),`a` + assert_equal(str(a),'a + 1 :') + + a = cls('a+1: c/foo(g)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'a + 1 : c / foo(g)') + + a = cls('a:b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a : b') + assert_equal(repr(a),"Substring_Range(Name('a'), Name('b'))") + + a = cls('a:') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a :') + + a = cls(':b') + assert isinstance(a,cls),`a` + assert_equal(str(a),': b') + + +class test_Data_Ref(NumpyTestCase): # R612 + + def check_data_ref(self): + cls = Data_Ref + a = cls('a%b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a % b') + assert_equal(repr(a),"Data_Ref('%', (Name('a'), Name('b')))") + + a = cls('a') + assert isinstance(a,Name),`a` + assert_equal(str(a),'a') + +class test_Part_Ref(NumpyTestCase): # R613 + + def check_part_ref(self): + cls = Part_Ref + a = cls('a') + assert isinstance(a, Name),`a` + assert_equal(str(a),'a') + +class test_Type_Param_Inquiry(NumpyTestCase): # R615 + + def check_simple(self): + cls = Type_Param_Inquiry + a = cls('a % b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a % b') + assert_equal(repr(a),"Type_Param_Inquiry(Name('a'), '%', Name('b'))") + + +class test_Array_Section(NumpyTestCase): # R617 + + def check_array_section(self): + cls = Array_Section + a = cls('a(:)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a(:)') + assert_equal(repr(a),"Array_Section(Name('a'), Substring_Range(None, None))") + + a = cls('a(2:)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a(2 :)') + + +class test_Section_Subscript(NumpyTestCase): # R619 + + def check_simple(self): + cls = Section_Subscript + + a = cls('1:2') + assert isinstance(a, Subscript_Triplet),`a` + assert_equal(str(a),'1 : 2') + + a = cls('zzz') + assert isinstance(a, Name),`a` + assert_equal(str(a),'zzz') + +class test_Section_Subscript_List(NumpyTestCase): # R619-list + + def check_simple(self): + cls = Section_Subscript_List + a = cls('a,2') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a, 2') + assert_equal(repr(a),"Section_Subscript_List(',', (Name('a'), Int_Literal_Constant('2', None)))") + + a = cls('::1') + assert isinstance(a,Subscript_Triplet),`a` + assert_equal(str(a),': : 1') + + a = cls('::1, 3') + assert isinstance(a,cls),`a` + assert_equal(str(a),': : 1, 3') + +class test_Subscript_Triplet(NumpyTestCase): # R620 + + def check_simple(self): + cls = Subscript_Triplet + a = cls('a:b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a : b') + assert_equal(repr(a),"Subscript_Triplet(Name('a'), Name('b'), None)") + + a = cls('a:b:1') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a : b : 1') + + a = cls(':') + assert isinstance(a,cls),`a` + assert_equal(str(a),':') + + a = cls('::5') + assert isinstance(a,cls),`a` + assert_equal(str(a),': : 5') + + a = cls(':5') + assert isinstance(a,cls),`a` + assert_equal(str(a),': 5') + + a = cls('a+1 :') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a + 1 :') + +class test_Alloc_Opt(NumpyTestCase): # R624 + + def check_simple(self): + cls = Alloc_Opt + a = cls('stat=a') + assert isinstance(a, cls),`a` + assert_equal(str(a),'STAT = a') + assert_equal(repr(a),"Alloc_Opt('STAT', Name('a'))") + +class test_Nullify_Stmt(NumpyTestCase): # R633 + + def check_simple(self): + cls = Nullify_Stmt + a = cls('nullify (a)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'NULLIFY(a)') + assert_equal(repr(a),"Nullify_Stmt('NULLIFY', Name('a'))") + + a = cls('nullify (a,c)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'NULLIFY(a, c)') + +############################################################################### +############################### SECTION 7 #################################### +############################################################################### + +class test_Primary(NumpyTestCase): # R701 + + def check_simple(self): + cls = Primary + a = cls('a') + assert isinstance(a,Name),`a` + assert_equal(str(a),'a') + + a = cls('(a)') + assert isinstance(a,Parenthesis),`a` + assert_equal(str(a),'(a)') + + a = cls('1') + assert isinstance(a,Int_Literal_Constant),`a` + assert_equal(str(a),'1') + + a = cls('1.') + assert isinstance(a,Real_Literal_Constant),`a` + assert_equal(str(a),'1.') + + a = cls('(1, n)') + assert isinstance(a,Complex_Literal_Constant),`a` + assert_equal(str(a),'(1, n)') + + a = cls('.true.') + assert isinstance(a,Logical_Literal_Constant),`a` + assert_equal(str(a),'.TRUE.') + + a = cls('"hey a()c"') + assert isinstance(a,Char_Literal_Constant),`a` + assert_equal(str(a),'"hey a()c"') + + a = cls('b"0101"') + assert isinstance(a,Binary_Constant),`a` + assert_equal(str(a),'B"0101"') + + a = cls('o"0107"') + assert isinstance(a,Octal_Constant),`a` + assert_equal(str(a),'O"0107"') + + a = cls('z"a107"') + assert isinstance(a,Hex_Constant),`a` + assert_equal(str(a),'Z"A107"') + + a = cls('a % b') + assert isinstance(a,Data_Ref),`a` + assert_equal(str(a),'a % b') + + a = cls('a(:)') + assert isinstance(a,Array_Section),`a` + assert_equal(str(a),'a(:)') + + a = cls('0.0E-1') + assert isinstance(a,Real_Literal_Constant),`a` + assert_equal(str(a),'0.0E-1') + +class test_Parenthesis(NumpyTestCase): # R701.h + + def check_simple(self): + cls = Parenthesis + a = cls('(a)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'(a)') + assert_equal(repr(a),"Parenthesis('(', Name('a'), ')')") + + a = cls('(a+1)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'(a + 1)') + + a = cls('((a))') + assert isinstance(a,cls),`a` + assert_equal(str(a),'((a))') + + a = cls('(a+(a+c))') + assert isinstance(a,cls),`a` + assert_equal(str(a),'(a + (a + c))') + +class test_Level_1_Expr(NumpyTestCase): # R702 + + def check_simple(self): + cls = Level_1_Expr + a = cls('.hey. a') + assert isinstance(a,cls),`a` + assert_equal(str(a),'.HEY. a') + assert_equal(repr(a),"Level_1_Expr('.HEY.', Name('a'))") + + self.assertRaises(NoMatchError,cls,'.not. a') + +class test_Mult_Operand(NumpyTestCase): # R704 + + def check_simple(self): + cls = Mult_Operand + a = cls('a**b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a ** b') + assert_equal(repr(a),"Mult_Operand(Name('a'), '**', Name('b'))") + + a = cls('a**2') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a ** 2') + + a = cls('(a+b)**2') + assert isinstance(a,cls),`a` + assert_equal(str(a),'(a + b) ** 2') + + a = cls('0.0E-1') + assert isinstance(a,Real_Literal_Constant),`a` + assert_equal(str(a),'0.0E-1') + +class test_Add_Operand(NumpyTestCase): # R705 + + def check_simple(self): + cls = Add_Operand + a = cls('a*b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a * b') + assert_equal(repr(a),"Add_Operand(Name('a'), '*', Name('b'))") + + a = cls('a/b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a / b') + + a = cls('a**b') + assert isinstance(a,Mult_Operand),`a` + assert_equal(str(a),'a ** b') + + a = cls('0.0E-1') + assert isinstance(a,Real_Literal_Constant),`a` + assert_equal(str(a),'0.0E-1') + +class test_Level_2_Expr(NumpyTestCase): # R706 + + def check_simple(self): + cls = Level_2_Expr + a = cls('a+b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a + b') + assert_equal(repr(a),"Level_2_Expr(Name('a'), '+', Name('b'))") + + a = cls('a-b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a - b') + + a = cls('a+b+c') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a + b + c') + + a = cls('+a') + assert isinstance(a,Level_2_Unary_Expr),`a` + assert_equal(str(a),'+ a') + + a = cls('+1') + assert isinstance(a,Level_2_Unary_Expr),`a` + assert_equal(str(a),'+ 1') + + a = cls('+a+b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'+ a + b') + + a = cls('0.0E-1') + assert isinstance(a,Real_Literal_Constant),`a` + assert_equal(str(a),'0.0E-1') + + +class test_Level_2_Unary_Expr(NumpyTestCase): + + def check_simple(self): + cls = Level_2_Unary_Expr + a = cls('+a') + assert isinstance(a,cls),`a` + assert_equal(str(a),'+ a') + assert_equal(repr(a),"Level_2_Unary_Expr('+', Name('a'))") + + a = cls('-a') + assert isinstance(a,cls),`a` + assert_equal(str(a),'- a') + + a = cls('+1') + assert isinstance(a,cls),`a` + assert_equal(str(a),'+ 1') + + a = cls('0.0E-1') + assert isinstance(a,Real_Literal_Constant),`a` + assert_equal(str(a),'0.0E-1') + + +class test_Level_3_Expr(NumpyTestCase): # R710 + + def check_simple(self): + cls = Level_3_Expr + a = cls('a//b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a // b') + assert_equal(repr(a),"Level_3_Expr(Name('a'), '//', Name('b'))") + + a = cls('"a"//"b"') + assert isinstance(a,cls),`a` + assert_equal(str(a),'"a" // "b"') + +class test_Level_4_Expr(NumpyTestCase): # R712 + + def check_simple(self): + cls = Level_4_Expr + a = cls('a.eq.b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a .EQ. b') + assert_equal(repr(a),"Level_4_Expr(Name('a'), '.EQ.', Name('b'))") + + a = cls('a.ne.b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a .NE. b') + + a = cls('a.lt.b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a .LT. b') + + a = cls('a.gt.b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a .GT. b') + + a = cls('a.ge.b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a .GE. b') + + a = cls('a==b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a == b') + + a = cls('a/=b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a /= b') + + a = cls('a<b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a < b') + + a = cls('a<=b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a <= b') + + a = cls('a>=b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a >= b') + + a = cls('a>b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a > b') + +class test_And_Operand(NumpyTestCase): # R714 + + def check_simple(self): + cls = And_Operand + a = cls('.not.a') + assert isinstance(a,cls),`a` + assert_equal(str(a),'.NOT. a') + assert_equal(repr(a),"And_Operand('.NOT.', Name('a'))") + +class test_Or_Operand(NumpyTestCase): # R715 + + def check_simple(self): + cls = Or_Operand + a = cls('a.and.b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a .AND. b') + assert_equal(repr(a),"Or_Operand(Name('a'), '.AND.', Name('b'))") + + +class test_Equiv_Operand(NumpyTestCase): # R716 + + def check_simple(self): + cls = Equiv_Operand + a = cls('a.or.b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a .OR. b') + assert_equal(repr(a),"Equiv_Operand(Name('a'), '.OR.', Name('b'))") + + +class test_Level_5_Expr(NumpyTestCase): # R717 + + def check_simple(self): + cls = Level_5_Expr + a = cls('a.eqv.b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a .EQV. b') + assert_equal(repr(a),"Level_5_Expr(Name('a'), '.EQV.', Name('b'))") + + a = cls('a.neqv.b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a .NEQV. b') + + a = cls('a.eq.b') + assert isinstance(a,Level_4_Expr),`a` + assert_equal(str(a),'a .EQ. b') + +class test_Expr(NumpyTestCase): # R722 + + def check_simple(self): + cls = Expr + a = cls('a .op. b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a .OP. b') + assert_equal(repr(a),"Expr(Name('a'), '.OP.', Name('b'))") + + a = cls('a') + assert isinstance(a,Name),`a` + assert_equal(str(a),'a') + + a = cls('3.e2') + assert isinstance(a,Real_Literal_Constant),`a` + + a = cls('0.0E-1') + assert isinstance(a,Real_Literal_Constant),`a` + assert_equal(str(a),'0.0E-1') + + self.assertRaises(NoMatchError,Scalar_Int_Expr,'a,b') + +class test_Assignment_Stmt(NumpyTestCase): # R734 + + def check_simple(self): + cls = Assignment_Stmt + a = cls('a = b') + assert isinstance(a, cls),`a` + assert_equal(str(a),'a = b') + assert_equal(repr(a),"Assignment_Stmt(Name('a'), '=', Name('b'))") + + a = cls('a(3:4) = b+c') + assert isinstance(a, cls),`a` + assert_equal(str(a),'a(3 : 4) = b + c') + + a = cls('a%c = b+c') + assert isinstance(a, cls),`a` + assert_equal(str(a),'a % c = b + c') + +class test_Proc_Component_Ref(NumpyTestCase): # R741 + + def check_proc_component_ref(self): + cls = Proc_Component_Ref + a = cls('a % b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a % b') + assert_equal(repr(a),"Proc_Component_Ref(Name('a'), '%', Name('b'))") + +class test_Where_Stmt(NumpyTestCase): # R743 + + def check_simple(self): + cls = Where_Stmt + a = cls('where (a) c=2') + assert isinstance(a,cls),`a` + assert_equal(str(a),'WHERE (a) c = 2') + assert_equal(repr(a),"Where_Stmt(Name('a'), Assignment_Stmt(Name('c'), '=', Int_Literal_Constant('2', None)))") + +class test_Where_Construct_Stmt(NumpyTestCase): # R745 + + def check_simple(self): + cls = Where_Construct_Stmt + a = cls('where (a)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'WHERE (a)') + assert_equal(repr(a),"Where_Construct_Stmt(Name('a'))") + + +############################################################################### +############################### SECTION 8 #################################### +############################################################################### + +class test_Continue_Stmt(NumpyTestCase): # R848 + + def check_simple(self): + cls = Continue_Stmt + a = cls('continue') + assert isinstance(a, cls),`a` + assert_equal(str(a),'CONTINUE') + assert_equal(repr(a),"Continue_Stmt('CONTINUE')") + +############################################################################### +############################### SECTION 9 #################################### +############################################################################### + +class test_Io_Unit(NumpyTestCase): # R901 + + def check_simple(self): + cls = Io_Unit + a = cls('*') + assert isinstance(a, cls),`a` + assert_equal(str(a),'*') + + a = cls('a') + assert isinstance(a, Name),`a` + assert_equal(str(a),'a') + +class test_Write_Stmt(NumpyTestCase): # R911 + + def check_simple(self): + cls = Write_Stmt + a = cls('write (123)"hey"') + assert isinstance(a, cls),`a` + assert_equal(str(a),'WRITE(UNIT = 123) "hey"') + assert_equal(repr(a),'Write_Stmt(Io_Control_Spec_List(\',\', (Io_Control_Spec(\'UNIT\', Int_Literal_Constant(\'123\', None)),)), Char_Literal_Constant(\'"hey"\', None))') + +class test_Print_Stmt(NumpyTestCase): # R912 + + def check_simple(self): + cls = Print_Stmt + a = cls('print 123') + assert isinstance(a, cls),`a` + assert_equal(str(a),'PRINT 123') + assert_equal(repr(a),"Print_Stmt(Label('123'), None)") + + a = cls('print *,"a=",a') + assert isinstance(a, cls),`a` + assert_equal(str(a),'PRINT *, "a=", a') + +class test_Io_Control_Spec(NumpyTestCase): # R913 + + def check_simple(self): + cls = Io_Control_Spec + a = cls('end=123') + assert isinstance(a, cls),`a` + assert_equal(str(a),'END = 123') + assert_equal(repr(a),"Io_Control_Spec('END', Label('123'))") + +class test_Io_Control_Spec_List(NumpyTestCase): # R913-list + + def check_simple(self): + cls = Io_Control_Spec_List + a = cls('end=123') + assert isinstance(a, cls),`a` + assert_equal(str(a),'END = 123') + assert_equal(repr(a),"Io_Control_Spec_List(',', (Io_Control_Spec('END', Label('123')),))") + + a = cls('123') + assert isinstance(a, cls),`a` + assert_equal(str(a),'UNIT = 123') + + a = cls('123,*') + assert isinstance(a, cls),`a` + assert_equal(str(a),'UNIT = 123, FMT = *') + + a = cls('123,fmt=a') + assert isinstance(a, cls),`a` + assert_equal(str(a),'UNIT = 123, FMT = a') + + if 0: + # see todo note in Io_Control_Spec_List + a = cls('123,a') + assert isinstance(a, cls),`a` + assert_equal(str(a),'UNIT = 123, NML = a') + +class test_Format(NumpyTestCase): # R914 + + def check_simple(self): + cls = Format + a = cls('*') + assert isinstance(a, cls),`a` + assert_equal(str(a),'*') + assert_equal(repr(a),"Format('*')") + + a = cls('a') + assert isinstance(a, Name),`a` + assert_equal(str(a),'a') + + a = cls('123') + assert isinstance(a, Label),`a` + assert_equal(str(a),'123') + +class test_Wait_Stmt(NumpyTestCase): # R921 + + def check_simple(self): + cls = Wait_Stmt + a = cls('wait (123)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'WAIT(UNIT = 123)') + +class test_Wait_Spec(NumpyTestCase): # R922 + + def check_simple(self): + cls = Wait_Spec + a = cls('123') + assert isinstance(a, cls),`a` + assert_equal(str(a),'UNIT = 123') + assert_equal(repr(a),"Wait_Spec('UNIT', Int_Literal_Constant('123', None))") + + a = cls('err=1') + assert isinstance(a, cls),`a` + assert_equal(str(a),'ERR = 1') + +############################################################################### +############################### SECTION 10 #################################### +############################################################################### + + +############################################################################### +############################### SECTION 11 #################################### +############################################################################### + +class test_Use_Stmt(NumpyTestCase): # R1109 + + def check_simple(self): + cls = Use_Stmt + a = cls('use a') + assert isinstance(a, cls),`a` + assert_equal(str(a),'USE :: a') + assert_equal(repr(a),"Use_Stmt(None, Name('a'), '', None)") + + a = cls('use :: a, c=>d') + assert isinstance(a, cls),`a` + assert_equal(str(a),'USE :: a, c => d') + + a = cls('use :: a, operator(.hey.)=>operator(.hoo.)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'USE :: a, OPERATOR(.HEY.) => OPERATOR(.HOO.)') + + a = cls('use, intrinsic :: a, operator(.hey.)=>operator(.hoo.), c=>g') + assert isinstance(a, cls),`a` + assert_equal(str(a),'USE, INTRINSIC :: a, OPERATOR(.HEY.) => OPERATOR(.HOO.), c => g') + +class test_Module_Nature(NumpyTestCase): # R1110 + + def check_simple(self): + cls = Module_Nature + a = cls('intrinsic') + assert isinstance(a, cls),`a` + assert_equal(str(a),'INTRINSIC') + assert_equal(repr(a),"Module_Nature('INTRINSIC')") + + a = cls('non_intrinsic') + assert isinstance(a, cls),`a` + assert_equal(str(a),'NON_INTRINSIC') + +############################################################################### +############################### SECTION 12 #################################### +############################################################################### + +class test_Function_Reference(NumpyTestCase): # R1217 + + def check_simple(self): + cls = Function_Reference + a = cls('f()') + assert isinstance(a,cls),`a` + assert_equal(str(a),'f()') + assert_equal(repr(a),"Function_Reference(Name('f'), None)") + + a = cls('f(2,k=1,a)') + assert isinstance(a,cls),`a` + assert_equal(str(a),'f(2, k = 1, a)') + + +class test_Procedure_Designator(NumpyTestCase): # R1219 + + def check_procedure_designator(self): + cls = Procedure_Designator + a = cls('a%b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a % b') + assert_equal(repr(a),"Procedure_Designator(Name('a'), '%', Name('b'))") + +class test_Actual_Arg_Spec(NumpyTestCase): # R1220 + + def check_simple(self): + cls = Actual_Arg_Spec + a = cls('k=a') + assert isinstance(a,cls),`a` + assert_equal(str(a),'k = a') + assert_equal(repr(a),"Actual_Arg_Spec(Name('k'), Name('a'))") + + a = cls('a') + assert isinstance(a,Name),`a` + assert_equal(str(a),'a') + +class test_Actual_Arg_Spec_List(NumpyTestCase): + + def check_simple(self): + cls = Actual_Arg_Spec_List + a = cls('a,b') + assert isinstance(a,cls),`a` + assert_equal(str(a),'a, b') + assert_equal(repr(a),"Actual_Arg_Spec_List(',', (Name('a'), Name('b')))") + + a = cls('a = k') + assert isinstance(a,Actual_Arg_Spec),`a` + assert_equal(str(a),'a = k') + + a = cls('a = k,b') + assert isinstance(a,Actual_Arg_Spec_List),`a` + assert_equal(str(a),'a = k, b') + + a = cls('a') + assert isinstance(a,Name),`a` + assert_equal(str(a),'a') + +class test_Alt_Return_Spec(NumpyTestCase): # R1222 + + def check_alt_return_spec(self): + cls = Alt_Return_Spec + a = cls('* 123') + assert isinstance(a,cls),`a` + assert_equal(str(a),'*123') + assert_equal(repr(a),"Alt_Return_Spec(Label('123'))") + +class test_Prefix(NumpyTestCase): # R1227 + + def check_simple(self): + cls = Prefix + a = cls('pure recursive') + assert isinstance(a, cls),`a` + assert_equal(str(a),'PURE RECURSIVE') + assert_equal(repr(a), "Prefix(' ', (Prefix_Spec('PURE'), Prefix_Spec('RECURSIVE')))") + + a = cls('integer * 2 pure') + assert isinstance(a, cls),`a` + assert_equal(str(a),'INTEGER*2 PURE') + +class test_Prefix_Spec(NumpyTestCase): # R1228 + + def check_simple(self): + cls = Prefix_Spec + a = cls('pure') + assert isinstance(a, cls),`a` + assert_equal(str(a),'PURE') + assert_equal(repr(a),"Prefix_Spec('PURE')") + + a = cls('elemental') + assert isinstance(a, cls),`a` + assert_equal(str(a),'ELEMENTAL') + + a = cls('recursive') + assert isinstance(a, cls),`a` + assert_equal(str(a),'RECURSIVE') + + a = cls('integer * 2') + assert isinstance(a, Intrinsic_Type_Spec),`a` + assert_equal(str(a),'INTEGER*2') + +class test_Subroutine_Subprogram(NumpyTestCase): # R1231 + + def check_simple(self): + from api import get_reader + reader = get_reader('''\ + subroutine foo + end subroutine foo''') + cls = Subroutine_Subprogram + a = cls(reader) + assert isinstance(a, cls),`a` + assert_equal(str(a),'SUBROUTINE foo\nEND SUBROUTINE foo') + assert_equal(repr(a),"Subroutine_Subprogram(Subroutine_Stmt(None, Name('foo'), None, None), End_Subroutine_Stmt('SUBROUTINE', Name('foo')))") + + reader = get_reader('''\ + subroutine foo + integer a + end subroutine foo''') + cls = Subroutine_Subprogram + a = cls(reader) + assert isinstance(a, cls),`a` + assert_equal(str(a),'SUBROUTINE foo\n INTEGER :: a\nEND SUBROUTINE foo') + +class test_Subroutine_Stmt(NumpyTestCase): # R1232 + + def check_simple(self): + cls = Subroutine_Stmt + a = cls('subroutine foo') + assert isinstance(a, cls),`a` + assert_equal(str(a),'SUBROUTINE foo') + assert_equal(repr(a),"Subroutine_Stmt(None, Name('foo'), None, None)") + + a = cls('pure subroutine foo') + assert isinstance(a, cls),`a` + assert_equal(str(a),'PURE SUBROUTINE foo') + + a = cls('pure subroutine foo(a,b)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'PURE SUBROUTINE foo(a, b)') + + a = cls('subroutine foo() bind(c)') + assert isinstance(a, cls),`a` + assert_equal(str(a),'SUBROUTINE foo BIND(C)') + +class test_End_Subroutine_Stmt(NumpyTestCase): # R1234 + + def check_simple(self): + cls = End_Subroutine_Stmt + a = cls('end subroutine foo') + assert isinstance(a, cls),`a` + assert_equal(str(a),'END SUBROUTINE foo') + assert_equal(repr(a),"End_Subroutine_Stmt('SUBROUTINE', Name('foo'))") + + a = cls('end') + assert isinstance(a, cls),`a` + assert_equal(str(a),'END SUBROUTINE') + + a = cls('endsubroutine') + assert isinstance(a, cls),`a` + assert_equal(str(a),'END SUBROUTINE') + +class test_Return_Stmt(NumpyTestCase): # R1236 + + def check_simple(self): + cls = Return_Stmt + a = cls('return') + assert isinstance(a, cls),`a` + assert_equal(str(a), 'RETURN') + assert_equal(repr(a), 'Return_Stmt(None)') + +class test_Contains(NumpyTestCase): # R1237 + + def check_simple(self): + cls = Contains_Stmt + a = cls('Contains') + assert isinstance(a, cls),`a` + assert_equal(str(a),'CONTAINS') + assert_equal(repr(a),"Contains_Stmt('CONTAINS')") + +if 1: + nof_needed_tests = 0 + nof_needed_match = 0 + total_needs = 0 + total_classes = 0 + for name in dir(): + obj = eval(name) + if not isinstance(obj, ClassType): continue + if not issubclass(obj, Base): continue + clsname = obj.__name__ + if clsname.endswith('Base'): continue + total_classes += 1 + subclass_names = obj.__dict__.get('subclass_names',None) + use_names = obj.__dict__.get('use_names',None) + if not use_names: continue + match = obj.__dict__.get('match',None) + try: + test_cls = eval('test_%s' % (clsname)) + except NameError: + test_cls = None + total_needs += 1 + if match is None: + if test_cls is None: + #print 'Needs tests:', clsname + print 'Needs match implementation:', clsname + nof_needed_tests += 1 + nof_needed_match += 1 + else: + print 'Needs match implementation:', clsname + nof_needed_match += 1 + else: + if test_cls is None: + #print 'Needs tests:', clsname + nof_needed_tests += 1 + continue + print '-----' + print 'Nof match implementation needs:',nof_needed_match,'out of',total_needs + print 'Nof tests needs:',nof_needed_tests,'out of',total_needs + print 'Total number of classes:',total_classes + print '-----' + +if __name__ == "__main__": + NumpyTest().run() diff --git a/numpy/f2py/lib/parser/test_parser.py b/numpy/f2py/lib/parser/test_parser.py new file mode 100644 index 000000000..9f1767a1a --- /dev/null +++ b/numpy/f2py/lib/parser/test_parser.py @@ -0,0 +1,496 @@ +""" +Test parsing single Fortran lines. + +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: May 2006 +----- +""" + +from numpy.testing import * +from block_statements import * +from readfortran import Line, FortranStringReader + + +def parse(cls, line, label='', + isfree=True, isstrict=False): + if label: + line = label + ' : ' + line + reader = FortranStringReader(line, isfree, isstrict) + item = reader.next() + if not cls.match(item.get_line()): + raise ValueError, '%r does not match %s pattern' % (line, cls.__name__) + stmt = cls(item, item) + if stmt.isvalid: + r = str(stmt) + if not isstrict: + r1 = parse(cls, r, isstrict=True) + if r != r1: + raise ValueError, 'Failed to parse %r with %s pattern in pyf mode, got %r' % (r, cls.__name__, r1) + return r + raise ValueError, 'parsing %r with %s pattern failed' % (line, cls.__name__) + +class test_Statements(NumpyTestCase): + + def check_assignment(self): + assert_equal(parse(Assignment,'a=b'), 'a = b') + assert_equal(parse(PointerAssignment,'a=>b'), 'a => b') + assert_equal(parse(Assignment,'a (2)=b(n,m)'), 'a(2) = b(n,m)') + assert_equal(parse(Assignment,'a % 2(2,4)=b(a(i))'), 'a%2(2,4) = b(a(i))') + + def check_assign(self): + assert_equal(parse(Assign,'assign 10 to a'),'ASSIGN 10 TO a') + + def check_call(self): + assert_equal(parse(Call,'call a'),'CALL a') + assert_equal(parse(Call,'call a()'),'CALL a') + assert_equal(parse(Call,'call a(1)'),'CALL a(1)') + assert_equal(parse(Call,'call a(1,2)'),'CALL a(1, 2)') + assert_equal(parse(Call,'call a % 2 ( n , a+1 )'),'CALL a % 2(n, a+1)') + + def check_goto(self): + assert_equal(parse(Goto,'go to 19'),'GO TO 19') + assert_equal(parse(Goto,'goto 19'),'GO TO 19') + assert_equal(parse(ComputedGoto,'goto (1, 2 ,3) a+b(2)'), + 'GO TO (1, 2, 3) a+b(2)') + assert_equal(parse(ComputedGoto,'goto (1, 2 ,3) , a+b(2)'), + 'GO TO (1, 2, 3) a+b(2)') + assert_equal(parse(AssignedGoto,'goto a'),'GO TO a') + assert_equal(parse(AssignedGoto,'goto a ( 1 )'),'GO TO a (1)') + assert_equal(parse(AssignedGoto,'goto a ( 1 ,2)'),'GO TO a (1, 2)') + + def check_continue(self): + assert_equal(parse(Continue,'continue'),'CONTINUE') + + def check_return(self): + assert_equal(parse(Return,'return'),'RETURN') + assert_equal(parse(Return,'return a'),'RETURN a') + assert_equal(parse(Return,'return a+1'),'RETURN a+1') + assert_equal(parse(Return,'return a(c, a)'),'RETURN a(c, a)') + + def check_stop(self): + assert_equal(parse(Stop,'stop'),'STOP') + assert_equal(parse(Stop,'stop 1'),'STOP 1') + assert_equal(parse(Stop,'stop "a"'),'STOP "a"') + assert_equal(parse(Stop,'stop "a b"'),'STOP "a b"') + + def check_print(self): + assert_equal(parse(Print, 'print*'),'PRINT *') + assert_equal(parse(Print, 'print "a b( c )"'),'PRINT "a b( c )"') + assert_equal(parse(Print, 'print 12, a'),'PRINT 12, a') + assert_equal(parse(Print, 'print 12, a , b'),'PRINT 12, a, b') + assert_equal(parse(Print, 'print 12, a(c,1) , b'),'PRINT 12, a(c,1), b') + + def check_read(self): + assert_equal(parse(Read, 'read ( 10 )'),'READ (10)') + assert_equal(parse(Read, 'read ( 10 ) a '),'READ (10) a') + assert_equal(parse(Read, 'read ( 10 ) a , b'),'READ (10) a, b') + assert_equal(parse(Read, 'read *'),'READ *') + assert_equal(parse(Read, 'read 12'),'READ 12') + assert_equal(parse(Read, 'read "a b"'),'READ "a b"') + assert_equal(parse(Read, 'read "a b",a'),'READ "a b", a') + assert_equal(parse(Read, 'read * , a'),'READ *, a') + assert_equal(parse(Read, 'read "hey a" , a'),'READ "hey a", a') + assert_equal(parse(Read, 'read * , a , b'),'READ *, a, b') + assert_equal(parse(Read, 'read ( unit =10 )'),'READ (UNIT = 10)') + + def check_write(self): + assert_equal(parse(Write, 'write ( 10 )'),'WRITE (10)') + assert_equal(parse(Write, 'write ( 10 , a )'),'WRITE (10, a)') + assert_equal(parse(Write, 'write ( 10 ) b'),'WRITE (10) b') + assert_equal(parse(Write, 'write ( 10 ) a(1) , b+2'),'WRITE (10) a(1), b+2') + assert_equal(parse(Write, 'write ( unit=10 )'),'WRITE (UNIT = 10)') + + def check_flush(self): + assert_equal(parse(Flush, 'flush 10'),'FLUSH (10)') + assert_equal(parse(Flush, 'flush (10)'),'FLUSH (10)') + assert_equal(parse(Flush, 'flush (UNIT = 10)'),'FLUSH (UNIT = 10)') + assert_equal(parse(Flush, 'flush (10, err= 23)'),'FLUSH (10, ERR = 23)') + + def check_wait(self): + assert_equal(parse(Wait, 'wait(10)'),'WAIT (10)') + assert_equal(parse(Wait, 'wait(10,err=129)'),'WAIT (10, ERR = 129)') + + def check_contains(self): + assert_equal(parse(Contains, 'contains'),'CONTAINS') + + def check_allocate(self): + assert_equal(parse(Allocate, 'allocate (a)'), 'ALLOCATE (a)') + assert_equal(parse(Allocate, \ + 'allocate (a, stat=b)'), 'ALLOCATE (a, STAT = b)') + assert_equal(parse(Allocate, 'allocate (a,b(:1))'), 'ALLOCATE (a, b(:1))') + assert_equal(parse(Allocate, \ + 'allocate (real(8)::a)'), 'ALLOCATE (REAL(KIND=8) :: a)') + def check_deallocate(self): + assert_equal(parse(Deallocate, 'deallocate (a)'), 'DEALLOCATE (a)') + assert_equal(parse(Deallocate, 'deallocate (a, stat=b)'), 'DEALLOCATE (a, STAT = b)') + + def check_moduleprocedure(self): + assert_equal(parse(ModuleProcedure,\ + 'ModuleProcedure a'), 'MODULE PROCEDURE a') + assert_equal(parse(ModuleProcedure,\ + 'module procedure a , b'), 'MODULE PROCEDURE a, b') + + def check_access(self): + assert_equal(parse(Public,'Public'),'PUBLIC') + assert_equal(parse(Public,'public a'),'PUBLIC a') + assert_equal(parse(Public,'public :: a'),'PUBLIC a') + assert_equal(parse(Public,'public a,b,c'),'PUBLIC a, b, c') + assert_equal(parse(Public,'public :: a(:,:)'),'PUBLIC a(:,:)') + assert_equal(parse(Private,'private'),'PRIVATE') + assert_equal(parse(Private,'private :: a'),'PRIVATE a') + + def check_close(self): + assert_equal(parse(Close,'close (12)'),'CLOSE (12)') + assert_equal(parse(Close,'close (12, err=99)'),'CLOSE (12, ERR = 99)') + assert_equal(parse(Close,'close (12, status = a(1,2))'),'CLOSE (12, STATUS = a(1,2))') + + def check_cycle(self): + assert_equal(parse(Cycle,'cycle'),'CYCLE') + assert_equal(parse(Cycle,'cycle ab'),'CYCLE ab') + + def check_rewind(self): + assert_equal(parse(Rewind,'rewind 1'),'REWIND (1)') + assert_equal(parse(Rewind,'rewind (1)'),'REWIND (1)') + assert_equal(parse(Rewind,'rewind (1, err = 123)'),'REWIND (1, ERR = 123)') + + def check_backspace(self): + assert_equal(parse(Backspace,'backspace 1'),'BACKSPACE (1)') + assert_equal(parse(Backspace,'backspace (1)'),'BACKSPACE (1)') + assert_equal(parse(Backspace,'backspace (1, err = 123)'),'BACKSPACE (1, ERR = 123)') + + def check_endfile(self): + assert_equal(parse(Endfile,'endfile 1'),'ENDFILE (1)') + assert_equal(parse(Endfile,'endfile (1)'),'ENDFILE (1)') + assert_equal(parse(Endfile,'endfile (1, err = 123)'),'ENDFILE (1, ERR = 123)') + + def check_open(self): + assert_equal(parse(Open,'open (1)'),'OPEN (1)') + assert_equal(parse(Open,'open (1, err = 123)'),'OPEN (1, ERR = 123)') + + def check_format(self): + assert_equal(parse(Format,'1: format ()'),'1: FORMAT ()') + assert_equal(parse(Format,'199 format (1)'),'199: FORMAT (1)') + assert_equal(parse(Format,'2 format (1 , SS)'),'2: FORMAT (1, ss)') + + def check_save(self): + assert_equal(parse(Save,'save'), 'SAVE') + assert_equal(parse(Save,'save :: a'), 'SAVE a') + assert_equal(parse(Save,'save a,b'), 'SAVE a, b') + + def check_data(self): + assert_equal(parse(Data,'data a /b/'), 'DATA a / b /') + assert_equal(parse(Data,'data a , c /b/'), 'DATA a, c / b /') + assert_equal(parse(Data,'data a /b ,c/'), 'DATA a / b, c /') + assert_equal(parse(Data,'data a /b/ c,e /d/'), 'DATA a / b / c, e / d /') + assert_equal(parse(Data,'data a(1,2) /b/'), 'DATA a(1,2) / b /') + assert_equal(parse(Data,'data a /b, c(1)/'), 'DATA a / b, c(1) /') + + def check_nullify(self): + assert_equal(parse(Nullify,'nullify(a)'),'NULLIFY (a)') + assert_equal(parse(Nullify,'nullify(a ,b)'),'NULLIFY (a, b)') + + def check_use(self): + assert_equal(parse(Use, 'use a'), 'USE a') + assert_equal(parse(Use, 'use :: a'), 'USE a') + assert_equal(parse(Use, 'use, intrinsic:: a'), 'USE INTRINSIC :: a') + assert_equal(parse(Use, 'use :: a ,only: b'), 'USE a, ONLY: b') + assert_equal(parse(Use, 'use :: a , only: b=>c'), 'USE a, ONLY: b=>c') + assert_equal(parse(Use, 'use :: a , b=>c'), 'USE a, b=>c') + assert_equal(parse(Use,\ + 'use :: a , only: operator(+) , b'),\ + 'USE a, ONLY: operator(+), b') + + def check_exit(self): + assert_equal(parse(Exit,'exit'),'EXIT') + assert_equal(parse(Exit,'exit ab'),'EXIT ab') + + def check_parameter(self): + assert_equal(parse(Parameter,'parameter (a = b(1,2))'), + 'PARAMETER (a = b(1,2))') + assert_equal(parse(Parameter,'parameter (a = b(1,2) , b=1)'), + 'PARAMETER (a = b(1,2), b=1)') + + def check_equivalence(self): + assert_equal(parse(Equivalence,'equivalence (a , b)'),'EQUIVALENCE (a, b)') + assert_equal(parse(Equivalence,'equivalence (a , b) , ( c, d(1) , g )'), + 'EQUIVALENCE (a, b), (c, d(1), g)') + + def check_dimension(self): + assert_equal(parse(Dimension,'dimension a(b)'),'DIMENSION a(b)') + assert_equal(parse(Dimension,'dimension::a(b)'),'DIMENSION a(b)') + assert_equal(parse(Dimension,'dimension a(b) , c(d)'),'DIMENSION a(b), c(d)') + assert_equal(parse(Dimension,'dimension a(b,c)'),'DIMENSION a(b,c)') + + def check_target(self): + assert_equal(parse(Target,'target a(b)'),'TARGET a(b)') + assert_equal(parse(Target,'target::a(b)'),'TARGET a(b)') + assert_equal(parse(Target,'target a(b) , c(d)'),'TARGET a(b), c(d)') + assert_equal(parse(Target,'target a(b,c)'),'TARGET a(b,c)') + + def check_pointer(self): + assert_equal(parse(Pointer,'pointer a=b'),'POINTER a=b') + assert_equal(parse(Pointer,'pointer :: a=b'),'POINTER a=b') + assert_equal(parse(Pointer,'pointer a=b, c=d(1,2)'),'POINTER a=b, c=d(1,2)') + + def check_protected(self): + assert_equal(parse(Protected,'protected a'),'PROTECTED a') + assert_equal(parse(Protected,'protected::a'),'PROTECTED a') + assert_equal(parse(Protected,'protected a , b'),'PROTECTED a, b') + + def check_volatile(self): + assert_equal(parse(Volatile,'volatile a'),'VOLATILE a') + assert_equal(parse(Volatile,'volatile::a'),'VOLATILE a') + assert_equal(parse(Volatile,'volatile a , b'),'VOLATILE a, b') + + def check_value(self): + assert_equal(parse(Value,'value a'),'VALUE a') + assert_equal(parse(Value,'value::a'),'VALUE a') + assert_equal(parse(Value,'value a , b'),'VALUE a, b') + + def check_arithmeticif(self): + assert_equal(parse(ArithmeticIf,'if (a) 1,2,3'),'IF (a) 1, 2, 3') + assert_equal(parse(ArithmeticIf,'if (a(1)) 1,2,3'),'IF (a(1)) 1, 2, 3') + assert_equal(parse(ArithmeticIf,'if (a(1,2)) 1,2,3'),'IF (a(1,2)) 1, 2, 3') + + def check_intrinsic(self): + assert_equal(parse(Intrinsic,'intrinsic a'),'INTRINSIC a') + assert_equal(parse(Intrinsic,'intrinsic::a'),'INTRINSIC a') + assert_equal(parse(Intrinsic,'intrinsic a , b'),'INTRINSIC a, b') + + def check_inquire(self): + assert_equal(parse(Inquire, 'inquire (1)'),'INQUIRE (1)') + assert_equal(parse(Inquire, 'inquire (1, err=123)'),'INQUIRE (1, ERR = 123)') + assert_equal(parse(Inquire, 'inquire (iolength=a) b'),'INQUIRE (IOLENGTH = a) b') + assert_equal(parse(Inquire, 'inquire (iolength=a) b ,c(1,2)'), + 'INQUIRE (IOLENGTH = a) b, c(1,2)') + + def check_sequence(self): + assert_equal(parse(Sequence, 'sequence'),'SEQUENCE') + + def check_external(self): + assert_equal(parse(External,'external a'),'EXTERNAL a') + assert_equal(parse(External,'external::a'),'EXTERNAL a') + assert_equal(parse(External,'external a , b'),'EXTERNAL a, b') + + def check_common(self): + assert_equal(parse(Common, 'common a'),'COMMON a') + assert_equal(parse(Common, 'common a , b'),'COMMON a, b') + assert_equal(parse(Common, 'common a , b(1,2)'),'COMMON a, b(1,2)') + assert_equal(parse(Common, 'common // a'),'COMMON a') + assert_equal(parse(Common, 'common / name/ a'),'COMMON / name / a') + assert_equal(parse(Common, 'common / name/ a , c'),'COMMON / name / a, c') + assert_equal(parse(Common, 'common / name/ a /foo/ c(1) ,d'), + 'COMMON / name / a / foo / c(1), d') + assert_equal(parse(Common, 'common / name/ a, /foo/ c(1) ,d'), + 'COMMON / name / a / foo / c(1), d') + + def check_optional(self): + assert_equal(parse(Optional,'optional a'),'OPTIONAL a') + assert_equal(parse(Optional,'optional::a'),'OPTIONAL a') + assert_equal(parse(Optional,'optional a , b'),'OPTIONAL a, b') + + def check_intent(self): + assert_equal(parse(Intent,'intent (in) a'),'INTENT (IN) a') + assert_equal(parse(Intent,'intent(in)::a'),'INTENT (IN) a') + assert_equal(parse(Intent,'intent(in) a , b'),'INTENT (IN) a, b') + assert_equal(parse(Intent,'intent (in, out) a'),'INTENT (IN, OUT) a') + + def check_entry(self): + assert_equal(parse(Entry,'entry a'), 'ENTRY a') + assert_equal(parse(Entry,'entry a()'), 'ENTRY a') + assert_equal(parse(Entry,'entry a(b)'), 'ENTRY a (b)') + assert_equal(parse(Entry,'entry a(b,*)'), 'ENTRY a (b, *)') + assert_equal(parse(Entry,'entry a bind(c , name="a b")'), + 'ENTRY a BIND (C, NAME = "a b")') + assert_equal(parse(Entry,'entry a result (b)'), 'ENTRY a RESULT (b)') + assert_equal(parse(Entry,'entry a bind(d) result (b)'), + 'ENTRY a RESULT (b) BIND (D)') + assert_equal(parse(Entry,'entry a result (b) bind( c )'), + 'ENTRY a RESULT (b) BIND (C)') + assert_equal(parse(Entry,'entry a(b,*) result (g)'), + 'ENTRY a (b, *) RESULT (g)') + + def check_import(self): + assert_equal(parse(Import,'import'),'IMPORT') + assert_equal(parse(Import,'import a'),'IMPORT a') + assert_equal(parse(Import,'import::a'),'IMPORT a') + assert_equal(parse(Import,'import a , b'),'IMPORT a, b') + + def check_forall(self): + assert_equal(parse(ForallStmt,'forall (i = 1:n(k,:) : 2) a(i) = i*i*b(i)'), + 'FORALL (i = 1 : n(k,:) : 2) a(i) = i*i*b(i)') + assert_equal(parse(ForallStmt,'forall (i=1:n,j=2:3) a(i) = b(i,i)'), + 'FORALL (i = 1 : n, j = 2 : 3) a(i) = b(i,i)') + assert_equal(parse(ForallStmt,'forall (i=1:n,j=2:3, 1+a(1,2)) a(i) = b(i,i)'), + 'FORALL (i = 1 : n, j = 2 : 3, 1+a(1,2)) a(i) = b(i,i)') + + def check_specificbinding(self): + assert_equal(parse(SpecificBinding,'procedure a'),'PROCEDURE a') + assert_equal(parse(SpecificBinding,'procedure :: a'),'PROCEDURE a') + assert_equal(parse(SpecificBinding,'procedure , NOPASS :: a'),'PROCEDURE , NOPASS :: a') + assert_equal(parse(SpecificBinding,'procedure , public, pass(x ) :: a'),'PROCEDURE , PUBLIC, PASS (x) :: a') + assert_equal(parse(SpecificBinding,'procedure(n) a'),'PROCEDURE (n) a') + assert_equal(parse(SpecificBinding,'procedure(n),pass :: a'), + 'PROCEDURE (n) , PASS :: a') + assert_equal(parse(SpecificBinding,'procedure(n) :: a'), + 'PROCEDURE (n) a') + assert_equal(parse(SpecificBinding,'procedure a= >b'),'PROCEDURE a => b') + assert_equal(parse(SpecificBinding,'procedure(n),pass :: a =>c'), + 'PROCEDURE (n) , PASS :: a => c') + + def check_genericbinding(self): + assert_equal(parse(GenericBinding,'generic :: a=>b'),'GENERIC :: a => b') + assert_equal(parse(GenericBinding,'generic, public :: a=>b'),'GENERIC, PUBLIC :: a => b') + assert_equal(parse(GenericBinding,'generic, public :: a(1,2)=>b ,c'), + 'GENERIC, PUBLIC :: a(1,2) => b, c') + + def check_finalbinding(self): + assert_equal(parse(FinalBinding,'final a'),'FINAL a') + assert_equal(parse(FinalBinding,'final::a'),'FINAL a') + assert_equal(parse(FinalBinding,'final a , b'),'FINAL a, b') + + def check_allocatable(self): + assert_equal(parse(Allocatable,'allocatable a'),'ALLOCATABLE a') + assert_equal(parse(Allocatable,'allocatable :: a'),'ALLOCATABLE a') + assert_equal(parse(Allocatable,'allocatable a (1,2)'),'ALLOCATABLE a (1,2)') + assert_equal(parse(Allocatable,'allocatable a (1,2) ,b'),'ALLOCATABLE a (1,2), b') + + def check_asynchronous(self): + assert_equal(parse(Asynchronous,'asynchronous a'),'ASYNCHRONOUS a') + assert_equal(parse(Asynchronous,'asynchronous::a'),'ASYNCHRONOUS a') + assert_equal(parse(Asynchronous,'asynchronous a , b'),'ASYNCHRONOUS a, b') + + def check_bind(self): + assert_equal(parse(Bind,'bind(c) a'),'BIND (C) a') + assert_equal(parse(Bind,'bind(c) :: a'),'BIND (C) a') + assert_equal(parse(Bind,'bind(c) a ,b'),'BIND (C) a, b') + assert_equal(parse(Bind,'bind(c) /a/'),'BIND (C) / a /') + assert_equal(parse(Bind,'bind(c) /a/ ,b'),'BIND (C) / a /, b') + assert_equal(parse(Bind,'bind(c,name="hey") a'),'BIND (C, NAME = "hey") a') + + def check_else(self): + assert_equal(parse(Else,'else'),'ELSE') + assert_equal(parse(ElseIf,'else if (a) then'),'ELSE IF (a) THEN') + assert_equal(parse(ElseIf,'else if (a.eq.b(1,2)) then'), + 'ELSE IF (a.eq.b(1,2)) THEN') + + def check_case(self): + assert_equal(parse(Case,'case (1)'),'CASE ( 1 )') + assert_equal(parse(Case,'case (1:)'),'CASE ( 1 : )') + assert_equal(parse(Case,'case (:1)'),'CASE ( : 1 )') + assert_equal(parse(Case,'case (1:2)'),'CASE ( 1 : 2 )') + assert_equal(parse(Case,'case (a(1,2))'),'CASE ( a(1,2) )') + assert_equal(parse(Case,'case ("ab")'),'CASE ( "ab" )') + assert_equal(parse(Case,'case default'),'CASE DEFAULT') + assert_equal(parse(Case,'case (1:2 ,3:4)'),'CASE ( 1 : 2, 3 : 4 )') + assert_equal(parse(Case,'case (a(1,:):)'),'CASE ( a(1,:) : )') + assert_equal(parse(Case,'case default'),'CASE DEFAULT') + + def check_where(self): + assert_equal(parse(WhereStmt,'where (1) a=1'),'WHERE ( 1 ) a = 1') + assert_equal(parse(WhereStmt,'where (a(1,2)) a=1'),'WHERE ( a(1,2) ) a = 1') + + def check_elsewhere(self): + assert_equal(parse(ElseWhere,'else where'),'ELSE WHERE') + assert_equal(parse(ElseWhere,'elsewhere (1)'),'ELSE WHERE ( 1 )') + assert_equal(parse(ElseWhere,'elsewhere(a(1,2))'),'ELSE WHERE ( a(1,2) )') + + def check_enumerator(self): + assert_equal(parse(Enumerator,'enumerator a'), 'ENUMERATOR a') + assert_equal(parse(Enumerator,'enumerator:: a'), 'ENUMERATOR a') + assert_equal(parse(Enumerator,'enumerator a,b'), 'ENUMERATOR a, b') + assert_equal(parse(Enumerator,'enumerator a=1'), 'ENUMERATOR a=1') + assert_equal(parse(Enumerator,'enumerator a=1 , b=c(1,2)'), 'ENUMERATOR a=1, b=c(1,2)') + + def check_fortranname(self): + assert_equal(parse(FortranName,'fortranname a'),'FORTRANNAME a') + + def check_threadsafe(self): + assert_equal(parse(Threadsafe,'threadsafe'),'THREADSAFE') + + def check_depend(self): + assert_equal(parse(Depend,'depend( a) b'), 'DEPEND ( a ) b') + assert_equal(parse(Depend,'depend( a) ::b'), 'DEPEND ( a ) b') + assert_equal(parse(Depend,'depend( a,c) b,e'), 'DEPEND ( a, c ) b, e') + + def check_check(self): + assert_equal(parse(Check,'check(1) a'), 'CHECK ( 1 ) a') + assert_equal(parse(Check,'check(1) :: a'), 'CHECK ( 1 ) a') + assert_equal(parse(Check,'check(b(1,2)) a'), 'CHECK ( b(1,2) ) a') + assert_equal(parse(Check,'check(a>1) :: a'), 'CHECK ( a>1 ) a') + + def check_callstatement(self): + assert_equal(parse(CallStatement,'callstatement (*func)()',isstrict=1), + 'CALLSTATEMENT (*func)()') + assert_equal(parse(CallStatement,'callstatement i=1;(*func)()',isstrict=1), + 'CALLSTATEMENT i=1;(*func)()') + + def check_callprotoargument(self): + assert_equal(parse(CallProtoArgument,'callprotoargument int(*), double'), + 'CALLPROTOARGUMENT int(*), double') + + def check_pause(self): + assert_equal(parse(Pause,'pause'),'PAUSE') + assert_equal(parse(Pause,'pause 1'),'PAUSE 1') + assert_equal(parse(Pause,'pause "hey"'),'PAUSE "hey"') + assert_equal(parse(Pause,'pause "hey pa"'),'PAUSE "hey pa"') + + def check_integer(self): + assert_equal(parse(Integer,'integer'),'INTEGER') + assert_equal(parse(Integer,'integer*4'),'INTEGER*4') + assert_equal(parse(Integer,'integer*4 a'),'INTEGER*4 a') + assert_equal(parse(Integer,'integer*4, a'),'INTEGER*4 a') + assert_equal(parse(Integer,'integer*4 a ,b'),'INTEGER*4 a, b') + assert_equal(parse(Integer,'integer*4 :: a ,b'),'INTEGER*4 a, b') + assert_equal(parse(Integer,'integer*4 a(1,2)'),'INTEGER*4 a(1,2)') + assert_equal(parse(Integer,'integer*4 :: a(1,2),b'),'INTEGER*4 a(1,2), b') + assert_equal(parse(Integer,'integer*4 external :: a'), + 'INTEGER*4, external :: a') + assert_equal(parse(Integer,'integer*4, external :: a'), + 'INTEGER*4, external :: a') + assert_equal(parse(Integer,'integer*4 external , intent(in) :: a'), + 'INTEGER*4, external, intent(in) :: a') + assert_equal(parse(Integer,'integer(kind=4)'),'INTEGER(KIND=4)') + assert_equal(parse(Integer,'integer ( kind = 4)'),'INTEGER(KIND=4)') + assert_equal(parse(Integer,'integer(kind=2+2)'),'INTEGER(KIND=2+2)') + assert_equal(parse(Integer,'integer(kind=f(4,5))'),'INTEGER(KIND=f(4,5))') + + def check_character(self): + assert_equal(parse(Character,'character'),'CHARACTER') + assert_equal(parse(Character,'character*2'),'CHARACTER(LEN=2)') + assert_equal(parse(Character,'character**'),'CHARACTER(LEN=*)') + assert_equal(parse(Character,'character*(2)'),'CHARACTER(LEN=2)') + assert_equal(parse(Character,'character*(len =2)'),'CHARACTER(LEN=2)') + assert_equal(parse(Character,'character*(len =2),'),'CHARACTER(LEN=2)') + assert_equal(parse(Character,'character*(len =:)'),'CHARACTER(LEN=:)') + assert_equal(parse(Character,'character(len =2)'),'CHARACTER(LEN=2)') + assert_equal(parse(Character,'character(2)'),'CHARACTER(LEN=2)') + assert_equal(parse(Character,'character(kind=2)'),'CHARACTER(KIND=2)') + assert_equal(parse(Character,'character(kind=2,len=3)'), + 'CHARACTER(LEN=3, KIND=2)') + assert_equal(parse(Character,'character(lEN=3,kind=2)'), + 'CHARACTER(LEN=3, KIND=2)') + assert_equal(parse(Character,'character(len=3,kind=2)', isstrict=True), + 'CHARACTER(LEN=3, KIND=2)') + assert_equal(parse(Character,'chaRACTER(len=3,kind=fA(1,2))', isstrict=True), + 'CHARACTER(LEN=3, KIND=fA(1,2))') + assert_equal(parse(Character,'character(len=3,kind=fA(1,2))'), + 'CHARACTER(LEN=3, KIND=fa(1,2))') + + def check_implicit(self): + assert_equal(parse(Implicit,'implicit none'),'IMPLICIT NONE') + assert_equal(parse(Implicit,'implicit'),'IMPLICIT NONE') + assert_equal(parse(Implicit,'implicit integer (i-m)'), + 'IMPLICIT INTEGER ( i-m )') + assert_equal(parse(Implicit,'implicit integer (i-m,p,q-r)'), + 'IMPLICIT INTEGER ( i-m, p, q-r )') + assert_equal(parse(Implicit,'implicit integer (i-m), real (z)'), + 'IMPLICIT INTEGER ( i-m ), REAL ( z )') + +if __name__ == "__main__": + NumpyTest().run() diff --git a/numpy/f2py/lib/parser/typedecl_statements.py b/numpy/f2py/lib/parser/typedecl_statements.py new file mode 100644 index 000000000..7414a6d2d --- /dev/null +++ b/numpy/f2py/lib/parser/typedecl_statements.py @@ -0,0 +1,563 @@ +""" +Fortran type declaration statements. + +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: May 2006 +----- +""" + +__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, is_name, CHAR_BIT, parse_array_spec + +# Intrinsic type specification statements + +class TypeDeclarationStatement(Statement): + """ + <declaration-type-spec> [ [, <attr-spec>] :: ] <entity-decl-list> + <declaration-type-spec> = <intrinsic-type-spec> + | TYPE ( <derived-type-spec> ) + | CLASS ( <derived-type-spec> ) + | CLASS ( * ) + + <derived-type-spec> = <type-name> [ ( <type-param-spec-list> ) ] + <type-param-spec> = [ <keyword> = ] <type-param-value> + <type-param-value> = <scalar-int-expr> | * | : + + <intrinsic-type-spec> = INTEGER [<kind-selector>] + | REAL [<kind-selector>] + | DOUBLE PRECISION + | COMPLEX [<kind-selector>] + | CHARACTER [<char-selector>] + | 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> ) + | ( KIND = <scalar-int-initialization-expr> [, LEN = <type-param-value>] ) + <length-selector> = ( [ LEN = ] <type-param-value> ) + | * <char-length> [ , ] + <char-length> = ( <type-param-value> ) | <scalar-int-literal-constant> + + <attr-spec> = <access-spec> | ALLOCATABLE | ASYNCHRONOUS + | DIMENSION ( <array-spec> ) | EXTERNAL + | INTENT ( <intent-spec> ) | INTRINSIC + | <language-binding-spec> | OPTIONAL + | PARAMETER | POINTER | PROTECTED | SAVE + | TARGET | VALUE | VOLATILE + <entity-decl> = <object-name> [ ( <array-spec> ) ] [ * <char-length> ] [ <initialization> ] + | <function-name> [ * <char-length> ] + <initialization> = = <initialization-expr> + | => NULL + <access-spec> = PUBLIC | PRIVATE + <language-binding-spec> = BIND ( C [ , NAME = <scalar-char-initialization-expr>] ) + <array-spec> = <explicit-shape-spec-list> + | <assumed-shape-spec-list> + | <deferred-shape-spec-list> + | <assumed-size-spec> + <explicit-shape-spec> = [ <lower-bound> : ] <upper-bound> + <assumed-shape-spec> = [ <lower-bound> ] : + <deferred-shape-spec> = : + <assumed-size-spec> = [ <explicit-shape-spec-list> , ] [ <lower-bound> : ] * + <bound> = <specification-expr> + + <int-literal-constant> = <digit-string> [ _ <kind-param> ] + <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 + apply_map = item.apply_map + clsname = self.__class__.__name__.lower() + line = item.get_line() + from block_statements import Function + + if not line.lower().startswith(clsname): + i = 0 + j = 0 + for c in line: + i += 1 + if c==' ': continue + j += 1 + if j==len(clsname): + break + line = line[:i].replace(' ','') + line[i:] + + assert line.lower().startswith(clsname),`line,clsname` + line = line[len(clsname):].lstrip() + + if line.startswith('('): + i = line.find(')') + selector = apply_map(line[:i+1].strip()) + line = line[i+1:].lstrip() + elif line.startswith('*'): + selector = '*' + line = line[1:].lstrip() + if line.startswith('('): + i = line.find(')') + selector += apply_map(line[:i+1].rstrip()) + line = line[i+1:].lstrip() + else: + m = re.match(r'\d+(_\w+|)|[*]',line) + if not m: + self.isvalid = False + return + i = m.end() + selector += line[:i].rstrip() + line = line[i:].lstrip() + else: + selector = '' + + fm = Function.match(line) + if fm: + l2 = line[:fm.end()] + m2 = re.match(r'.*?\b(?P<name>\w+)\Z',l2) + if not m2: + self.isvalid = False + return + fname = m2.group('name') + fitem = item.copy(clsname+selector+' :: '+fname, + apply_map=True) + self.parent.put_item(fitem) + item.clone(line) + self.isvalid = False + return + + if line.startswith(','): + line = line[1:].lstrip() + + self.raw_selector = selector + if isinstance(self, Character): + self.selector = self._parse_char_selector(selector) + else: + self.selector = self._parse_kind_selector(selector) + + i = line.find('::') + if i==-1: + self.attrspec = [] + self.entity_decls = split_comma(line, self.item) + else: + self.attrspec = split_comma(line[:i].rstrip(), self.item) + self.entity_decls = split_comma(line[i+2:].lstrip(), self.item) + for entity in self.entity_decls: + if not is_entity_decl(entity): + self.isvalid = False + return + + if isinstance(self.parent, Function) \ + and self.parent.name in self.entity_decls: + 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 '','' + length,kind = '','' + if selector.startswith('*'): + length = selector[1:].lstrip() + else: + assert selector[0]+selector[-1]=='()',`selector` + l = selector[1:-1].strip() + if l.lower().startswith('kind'): + l = l[4:].lstrip() + assert l.startswith('='),`l` + kind = l[1:].lstrip() + else: + kind = l + return length,kind + + def _parse_char_selector(self, selector): + if not selector: + return '','' + if selector.startswith('*'): + l = selector[1:].lstrip() + if l.startswith('('): + if l.endswith(','): l = l[:-1].rstrip() + assert l.endswith(')'),`l` + l = l[1:-1].strip() + if l.lower().startswith('len'): + l = l[3:].lstrip()[1:].lstrip() + kind='' + else: + assert selector[0]+selector[-1]=='()',`selector` + l = split_comma(selector[1:-1].strip(), self.item) + if len(l)==1: + l = l[0] + if l.lower().startswith('len'): + l=l[3:].lstrip() + assert l.startswith('='),`l` + l=l[1:].lstrip() + kind = '' + elif l.lower().startswith('kind'): + kind = l[4:].lstrip()[1:].lstrip() + l = '' + else: + kind = '' + else: + assert len(l)==2 + if l[0].lower().startswith('len'): + assert l[1].lower().startswith('kind'),`l` + kind = l[1][4:].lstrip()[1:].lstrip() + l = l[0][3:].lstrip()[1:].lstrip() + elif l[0].lower().startswith('kind'): + assert l[1].lower().startswith('len'),`l` + kind = l[0][4:].lstrip()[1:].lstrip() + l = l[1][3:].lstrip()[1:].lstrip() + else: + if l[1].lower().startswith('kind'): + kind = l[1][4:].lstrip()[1:].lstrip() + l = l[0] + else: + kind = l[1] + l = l[0] + return l,kind + + def tostr(self): + clsname = self.__class__.__name__.upper() + s = '' + length, kind = self.selector + if isinstance(self, Character): + if length and kind: + s += '(LEN=%s, KIND=%s)' % (length,kind) + elif length: + s += '(LEN=%s)' % (length) + elif kind: + s += '(KIND=%s)' % (kind) + else: + if isinstance(self, Type): + s += '(%s)' % (kind) + else: + if length: + s += '*%s' % (length) + if kind: + s += '(KIND=%s)' % (kind) + + return clsname + s + + def tofortran(self,isfix=None): + tab = self.get_indent_tab(isfix=isfix) + s = self.tostr() + if self.attrspec: + s += ', ' + ', '.join(self.attrspec) + if self.entity_decls: + s += ' ::' + if self.entity_decls: + s += ' ' + ', '.join(self.entity_decls) + return tab + s + + def __str__(self): + return self.tofortran() + + def __eq__(self, other): + if self.__class__ is not other.__class__: + return False + return self.selector==other.selector + + def astypedecl(self): + 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: + return + variables = self.parent.a.variables + typedecl = self.astypedecl() + attrspec = self.attrspec[:] + try: + access_spec = [a for a in attrspec if a.lower() in ['private','public']][0] + attrspec.remove(access_spec) + except IndexError: + access_spec = None + for item in self.entity_decls: + name, array_spec, char_length, value = self._parse_entity(item) + var = self.parent.get_variable(name) + var.add_parent(self) + if char_length: + var.set_length(char_length) + else: + var.set_type(typedecl) + var.update(self.attrspec) + if array_spec: + var.set_bounds(array_spec) + if value: + var.set_init(value) + if access_spec is not None: + l = getattr(self.parent.a,access_spec.lower() + '_id_list') + l.append(name) + var.analyze() + return + + def _parse_entity(self, line): + m = name_re(line) + assert m,`line,self.item,self.__class__.__name__` + name = line[:m.end()] + line = line[m.end():].lstrip() + array_spec = None + item = self.item.copy(line) + line = item.get_line() + if line.startswith('('): + i = line.find(')') + assert i!=-1,`line` + array_spec = parse_array_spec(line[1:i].strip(), item) + line = line[i+1:].lstrip() + char_length = None + if line.startswith('*'): + i = line.find('=') + if i==-1: + char_length = item.apply_map(line[1:].lstrip()) + line = '' + else: + char_length = item.apply_map(line[1:i].strip()) + line = line[i:] + value = None + if line.startswith('='): + 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_byte_size(self): + length, kind = self.selector + if length: return int(length) + if kind: return int(kind) + return self.default_kind + + def get_bit_size(self): + return CHAR_BIT * int(self.get_byte_size()) + + 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_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_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_byte_size(self): + return self.default_kind + + def get_zero_value(self): + return '0.0D0' + +class Complex(TypeDeclarationStatement): + match = re.compile(r'complex\b',re.I).match + default_kind = 4 + + def get_byte_size(self): + length, kind = self.selector + if length: return int(length) + if kind: return 2*int(kind) + return 2*self.default_kind + + 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_part_typedecl(self): + bz = self.get_byte_size()/2 + return Real(self.parent, self.item.copy('REAL*%s' % (bz))) + +class DoubleComplex(TypeDeclarationStatement): + # not in standard + match = re.compile(r'double\s*complex\b',re.I).match + default_kind = 8 + + def get_byte_size(self): + return 2*self.default_kind + + def get_zero_value(self): + return '(0.0D0,0.0D0)' + +class Logical(TypeDeclarationStatement): + match = re.compile(r'logical\b',re.I).match + default_kind = 4 + + def get_zero_value(self): + return ".FALSE." + +class Character(TypeDeclarationStatement): + match = re.compile(r'character\b',re.I).match + default_kind = 1 + + def get_bit_size(self): + length = self.get_length() + if length=='*': + return 0 # model for character*(*) + return CHAR_BIT * int(length) * int(self.get_kind()) + + 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' + +class Type(TypeDeclarationStatement): + match = re.compile(r'type\s*\(', re.I).match + + def get_zero_value(self): + type_decl = self.get_type_decl(self.name) + 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): + return self.get_type_decl(self.name).get_bit_size() + +TypeStmt = Type + +class Class(TypeDeclarationStatement): + match = re.compile(r'class\s*\(', re.I).match + +class Implicit(Statement): + """ + IMPLICIT <implicit-spec-list> + IMPLICIT NONE + <implicit-spec> = <declaration-type-spec> ( <letter-spec-list> ) + <letter-spec> = <letter> [ - <letter> ] + """ + match = re.compile(r'implicit\b',re.I).match + + letters = string.lowercase + + def process_item(self): + line = self.item.get_line()[8:].lstrip() + if line.lower()=='none': + self.items = [] + return + items = [] + for item in split_comma(line, self.item): + i = item.find('(') + assert i!=-1 and item.endswith(')'),`item` + specs = [] + for spec in split_comma(item[i+1:-1].strip(), self.item): + if '-' in spec: + s,e = spec.lower().split('-') + s = s.strip() + e = e.strip() + assert s in self.letters and e in self.letters,`s,e` + else: + e = s = spec.lower().strip() + assert s in self.letters,`s,e` + specs.append((s,e)) + tspec = item[:i].rstrip() + stmt = None + for cls in declaration_type_spec: + if cls.match(tspec): + stmt = cls(self, self.item.copy(tspec)) + if stmt.isvalid: + break + assert stmt is not None,`item,line` + items.append((stmt,specs)) + self.items = items + return + + def tofortran(self, isfix=None): + tab = self.get_indent_tab(isfix=isfix) + if not self.items: + return tab + 'IMPLICIT NONE' + l = [] + for stmt,specs in self.items: + l1 = [] + for s,e in specs: + if s==e: + l1.append(s) + else: + l1.append(s + '-' + e) + l.append('%s ( %s )' % (stmt.tostr(), ', '.join(l1))) + return tab + 'IMPLICIT ' + ', '.join(l) + + def analyze(self): + implicit_rules = self.parent.a.implicit_rules + if not self.items: + if implicit_rules: + self.warning('overriding previously set implicit rule mapping'\ + ' %r.' % (implicit_rules)) + self.parent.a.implicit_rules = None + return + if implicit_rules is None: + self.warning('overriding previously set IMPLICIT NONE') + self.parent.a.implicit_rules = implicit_rules = {} + for stmt,specs in self.items: + for s,e in specs: + for l in string.lowercase[string.lowercase.index(s.lower()):\ + string.lowercase.index(e.lower())+1]: + implicit_rules[l] = stmt + return + +intrinsic_type_spec = [ \ + Integer , Real, + DoublePrecision, Complex, DoubleComplex, Character, Logical, Byte + ] +declaration_type_spec = intrinsic_type_spec + [ TypeStmt, Class ] diff --git a/numpy/f2py/lib/parser/utils.py b/numpy/f2py/lib/parser/utils.py new file mode 100644 index 000000000..ac2cfce8e --- /dev/null +++ b/numpy/f2py/lib/parser/utils.py @@ -0,0 +1,177 @@ +""" +Various utility functions. + +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: May 2006 +----- +""" + +__all__ = ['split_comma', 'specs_split_comma', + 'ParseError','AnalyzeError', + 'get_module_file','parse_bind','parse_result','is_name','parse_array_spec', + 'CHAR_BIT','str2stmt'] + +import re +import os, glob + +class ParseError(Exception): + pass + +class AnalyzeError(Exception): + pass + +is_name = re.compile(r'^[a-z_]\w*$',re.I).match +name_re = re.compile(r'[a-z_]\w*',re.I).match +is_entity_decl = re.compile(r'^[a-z_]\w*',re.I).match +is_int_literal_constant = re.compile(r'^\d+(_\w+|)$').match + +def split_comma(line, item = None, comma=',', keep_empty=False): + items = [] + if item is None: + for s in line.split(comma): + s = s.strip() + if not s and not keep_empty: continue + items.append(s) + return items + newitem = item.copy(line, True) + apply_map = newitem.apply_map + for s in newitem.get_line().split(comma): + s = apply_map(s).strip() + if not s and not keep_empty: continue + items.append(s) + return items + +def parse_array_spec(line, item = None): + items = [] + for spec in split_comma(line, item): + items.append(tuple(split_comma(spec, item, comma=':', keep_empty=True))) + return items + +def specs_split_comma(line, item = None, upper=False): + specs0 = split_comma(line, item) + specs = [] + for spec in specs0: + i = spec.find('=') + if i!=-1: + kw = spec[:i].strip().upper() + v = spec[i+1:].strip() + specs.append('%s = %s' % (kw, v)) + else: + if upper: + spec = spec.upper() + specs.append(spec) + return specs + +def parse_bind(line, item = None): + if not line.lower().startswith('bind'): + return None, line + if item is not None: + newitem = item.copy(line, apply_map=True) + newline = newitem.get_line() + else: + newitem = None + newline = newline[4:].lstrip() + i = newline.find(')') + assert i!=-1,`newline` + args = [] + for a in specs_split_comma(newline[1:i].strip(), newitem, upper=True): + args.append(a) + rest = newline[i+1:].lstrip() + if item is not None: + rest = newitem.apply_map(rest) + return args, rest + +def parse_result(line, item = None): + if not line.lower().startswith('result'): + return None, line + line = line[6:].lstrip() + i = line.find(')') + assert i != -1,`line` + name = line[1:i].strip() + assert is_name(name),`name` + 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)): + stmt = content[i] + if isinstance(stmt, classes): + stmts.append(stmt) + indices.append(i) + indices.reverse() + for i in indices: + del content[i] + return stmts + + +def get_module_files(directory, _cache={}): + if _cache.has_key(directory): + return _cache[directory] + module_line = re.compile(r'(\A|^)module\s+(?P<name>\w+)\s*(!.*|)$',re.I | re.M) + d = {} + for fn in glob.glob(os.path.join(directory,'*.f90')): + f = open(fn,'r') + for name in module_line.findall(f.read()): + name = name[1] + if d.has_key(name): + print d[name],'already defines',name + continue + d[name] = fn + _cache[directory] = d + return d + +def get_module_file(name, directory, _cache={}): + fn = _cache.get(name, None) + if fn is not None: + return fn + if name.endswith('_module'): + f1 = os.path.join(directory,name[:-7]+'.f90') + if os.path.isfile(f1): + _cache[name] = fn + return f1 + pattern = re.compile(r'\s*module\s+(?P<name>[a-z]\w*)', re.I).match + for fn in glob.glob(os.path.join(directory,'*.f90')): + f = open(fn,'r') + for line in f: + m = pattern(line) + if m and m.group('name')==name: + _cache[name] = fn + f.close() + 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() diff --git a/numpy/f2py/lib/py_wrap.py b/numpy/f2py/lib/py_wrap.py new file mode 100644 index 000000000..47c8437ad --- /dev/null +++ b/numpy/f2py/lib/py_wrap.py @@ -0,0 +1,128 @@ +__all__ = ['PythonWrapperModule'] + +import re +import os +import sys + +from parser.api import * +from wrapper_base import * +from py_wrap_type import * +from py_wrap_subprogram import * + +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 "numpy/arrayscalars.h" + +%(header_list)s + +%(typedef_list)s + +%(extern_list)s + +%(c_code_list)s + +%(capi_code_list)s + +%(objdecl_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); + import_array(); + if (PyErr_Occurred()) { + PyErr_SetString(PyExc_ImportError, "failed to load array module."); + goto capi_err; + } + %(module_init_list)s + return; +capi_err: + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_RuntimeError, "failed to initialize %(modulename)s module."); + } + return; +} +#ifdef __cplusplus +} +#endif +''' + + main_fortran_template = '''\ +%(fortran_code_list)s +''' + + + + def __init__(self, modulename): + WrapperBase.__init__(self) + self.modulename = modulename + self.cname = 'f2py_' + modulename + + self.defined_cpp_code = [] + self.defined_c_code = [] + self.defined_types = [] + self.defined_capi_codes = [] + + + self.header_list = [] + self.typedef_list = [] + self.extern_list = [] + self.objdecl_list = [] + self.c_code_list = [] + self.capi_code_list = [] + + self.module_method_list = [] + self.module_init_list = [] + + self.fortran_code_list = [] + + self.list_names = ['header', 'typedef', 'extern', 'objdecl', + 'c_code','capi_code','module_method','module_init', + 'fortran_code'] + self.isf90 = False + return + + def add(self, block): + if isinstance(block, BeginSource): + for name, moduleblock in block.a.module.items(): + self.add(moduleblock) + #for name, subblock in block.a.external_subprogram.items(): + # self.add(subblock) + elif isinstance(block, Subroutine): + PythonCAPISubProgram(self, block) + elif isinstance(block, Function): + fcode = block.subroutine_wrapper_code() + self.fortran_code_list.append(fcode) + wrapper_block = block.subroutine_wrapper() + PythonCAPISubProgram(self, wrapper_block) + elif isinstance(block, Module): + self.isf90 = True + for name,declblock in block.a.type_decls.items(): + self.add(declblock) + for name,subblock in block.a.module_subprogram.items(): + self.add(subblock) + elif isinstance(block, tuple([TypeDecl]+declaration_type_spec)): + if isinstance(block, (TypeDecl, TypeStmt)): + self.isf90 = True + PythonCAPIType(self, block) + 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) diff --git a/numpy/f2py/lib/py_wrap_subprogram.py b/numpy/f2py/lib/py_wrap_subprogram.py new file mode 100644 index 000000000..8dd0c3efb --- /dev/null +++ b/numpy/f2py/lib/py_wrap_subprogram.py @@ -0,0 +1,210 @@ +__all__ = ['PythonCAPISubProgram'] + +import sys + +from parser.api import TypeDecl, TypeStmt, Module +from wrapper_base import * +from py_wrap_type import * + +class PythonCAPISubProgram(WrapperBase): + """ + Fortran subprogram hooks. + """ + + header_template_f77 = '''\ +#define %(name)s_f F_FUNC(%(name)s, %(NAME)s) +''' + extern_template_f77 = '''\ +extern void %(name)s_f(%(ctype_args_f_clist)s); +''' + objdecl_template_doc = '''\ +static char %(cname)s__doc[] = ""; +''' + module_method_template = '''\ +{"%(pyname)s", (PyCFunction)%(cname)s, METH_VARARGS | METH_KEYWORDS, %(cname)s__doc},''' + + capi_code_template = '''\ +static PyObject* %(cname)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[] = {%(kw_clist+optkw_clist+extrakw_clist+["NULL"])s}; + if (PyArg_ParseTupleAndKeywords(capi_args,capi_keywds, + "%(pyarg_format_elist)s", + %(["capi_kwlist"]+pyarg_obj_clist)s)) { + %(frompyobj_list)s + %(call_list)s + f2py_success = !PyErr_Occurred(); + if (f2py_success) { + %(pyobjfrom_list)s + capi_buildvalue = Py_BuildValue("%(return_format_elist)s" + %(return_obj_clist)s); + %(clean_pyobjfrom_list)s + } + %(clean_call_list)s + %(clean_frompyobj_list)s + } + return capi_buildvalue; +} +''' + + header_template_module = ''' +#define %(name)s_f (*%(name)s_func_ptr) +#define %(init_func)s_f F_FUNC(%(init_func)s, %(INIT_FUNC)s) +''' + typedef_template_module = ''' +typedef void (*%(name)s_functype)(%(ctype_args_f_clist)s); +typedef void (*%(init_func)s_c_functype)(%(name)s_functype); +''' + extern_template_module = '''\ +extern void %(init_func)s_f(%(init_func)s_c_functype); +static %(name)s_functype %(name)s_func_ptr; +''' + objdecl_template_module = ''' +''' + fortran_code_template_module = ''' + subroutine %(init_func)s(init_func_c) + use %(mname)s + external init_func_c + call init_func_c(%(name)s) + end +''' + c_code_template_module = ''' +static void %(init_func)s_c(%(name)s_functype func_ptr) { + %(name)s_func_ptr = func_ptr; +} +''' + module_init_template_module = ''' +%(init_func)s_f(%(init_func)s_c); +''' + + def __init__(self, parent, block): + WrapperBase.__init__(self) + self.name = name = pyname = block.name + self.cname = cname = '%s_%s' % (parent.cname,name) + + defined = parent.defined_capi_codes + if cname in defined: + return + defined.append(cname) + + self.info('Generating interface for %s %s: %s' % (parent.modulename, block.__class__.__name__, cname)) + self.parent = parent + + if pyname.startswith('f2pywrap_'): + pyname = pyname[9:] + self.pyname = pyname + + self.header_template = '' + self.extern_template = '' + self.module_init_template = '' + self.typedef_template = '' + self.c_code_template = '' + self.objdecl_template = '' + self.fortran_code_template = '' + + WrapperCPPMacro(parent, 'F_FUNC') + + if isinstance(block.parent, Module): + self.mname = block.parent.name + self.init_func = '%s_init' % (name) + self.typedef_template += self.typedef_template_module + self.header_template += self.header_template_module + self.fortran_code_template += self.fortran_code_template_module + self.module_init_template += self.module_init_template_module + self.objdecl_template += self.objdecl_template_module + self.c_code_template += self.c_code_template_module + self.extern_template += self.extern_template_module + else: + self.extern_template += self.extern_template_f77 + self.header_template += self.header_template_f77 + + self.objdecl_template += self.objdecl_template_doc + + self.decl_list = [] + self.kw_list = [] + self.optkw_list = [] + self.extrakw_list = [] + self.pyarg_format_list = [] + self.pyarg_obj_list = [] + self.frompyobj_list = [] + self.call_list = [] + self.pyobjfrom_list = [] + self.return_format_list = [] + self.return_obj_list = [] + self.buildvalue_list = [] + self.clean_pyobjfrom_list = [] + self.clean_call_list = [] + self.clean_frompyobj_list = [] + + args_f = [] + extra_args_f = [] + ctype_args_f = [] + extra_ctype_args_f = [] + argindex = -1 + for argname in block.args: + argindex += 1 + var = block.a.variables[argname] + typedecl = var.get_typedecl() + PythonCAPIType(parent, typedecl) + ti = PyTypeInterface(typedecl) + if var.is_intent_in(): + self.kw_list.append('"%s"' % (argname)) + + if var.is_scalar(): + if isinstance(typedecl, TypeStmt): + if var.is_intent_in(): + self.pyarg_format_list.append('O&') + self.pyarg_obj_list.append('\npyobj_to_%s_inplace, &%s' % (ti.ctype, argname)) + else: + self.frompyobj_list.append('%s = (%s*)pyobj_from_%s(NULL);' % (argname,ti.otype,ti.ctype)) + if not var.is_intent_out(): + self.clean_frompyobj_list.append('Py_DECREF(%s);' % (argname)) + self.decl_list.append('%s* %s = NULL;' % (ti.otype, argname)) + args_f.append('%s->data' % (argname)) # is_scalar + ctype_args_f.append(ti.ctype) + else: + if var.is_intent_in(): + self.pyarg_format_list.append('O&') + self.pyarg_obj_list.append('\npyobj_to_%s, &%s' % (ti.ctype, argname)) + assert not isinstance(typedecl, TypeDecl) + if ti.ctype=='f2py_string0': + if not var.is_intent_in(): + assert not var.is_intent_out(),'intent(out) not implemented for "%s"' % (var) + self.decl_list.append('%s %s = {NULL,0};' % (ti.ctype, argname)) + args_f.append('%s.data' % argname) # is_scalar + ctype_args_f.append('char*') + extra_ctype_args_f.append('int') + extra_args_f.append('%s.len' % argname) + self.clean_frompyobj_list.append(\ + 'if (%s.len) free(%s.data);' % (argname,argname)) + else: + self.decl_list.append('%s %s;' % (ti.ctype, argname)) + args_f.append('&'+argname) # is_scalar + ctype_args_f.append(ti.ctype+'*') + if var.is_intent_out(): # and is_scalar + if isinstance(typedecl, TypeStmt): + self.return_format_list.append('N') + self.return_obj_list.append('\n%s' % (argname)) + else: + self.return_format_list.append('O&') + self.return_obj_list.append('\npyobj_from_%s, &%s' % (ti.ctype, argname)) + else: + print `ti,var.dimension,var.bounds` + assert var.is_scalar(),'array support not implemented: "%s"' % (var) + + self.call_list.append('%s_f(%s);' % (name,', '.join(args_f+extra_args_f))) + + self.ctype_args_f_list = ctype_args_f + extra_ctype_args_f + if not self.ctype_args_f_list: + self.ctype_args_f_list.append('void') + + + self.clean_pyobjfrom_list.reverse() + self.clean_call_list.reverse() + self.clean_frompyobj_list.reverse() + + if self.return_obj_list: self.return_obj_list.insert(0,'') + + parent.apply_templates(self) + return diff --git a/numpy/f2py/lib/py_wrap_type.py b/numpy/f2py/lib/py_wrap_type.py new file mode 100644 index 000000000..7b90e7ed1 --- /dev/null +++ b/numpy/f2py/lib/py_wrap_type.py @@ -0,0 +1,753 @@ +__all__ = ['PythonCAPIType', 'PyTypeInterface'] + +from wrapper_base import * +from parser.api import CHAR_BIT, Module, declaration_type_spec, \ + TypeDecl, TypeStmt, Subroutine, Function, Integer, Real,\ + DoublePrecision, Complex, DoubleComplex, Logical, Character, \ + Byte + +class PyTypeInterface: + + def __init__(self, typedecl): + if isinstance(typedecl, TypeStmt): + typedecl = typedecl.get_type_decl(typedecl.name) + self._typedecl = typedecl + if isinstance(typedecl, TypeDecl): + self.name = name = typedecl.name + tname = 'f2py_type_%s_' % (name) + else: + if isinstance(typedecl,(Integer,Byte)): + tname = 'npy_int' + elif isinstance(typedecl,(Real, DoublePrecision)): + tname = 'npy_float' + elif isinstance(typedecl,(Complex, DoubleComplex)): + tname = 'npy_complex' + elif isinstance(typedecl,Logical): + tname = 'f2py_bool' + elif isinstance(typedecl,Character): + tname = 'f2py_string' + else: + raise NotImplementedError,`typedecl.__class__` + bitsize = typedecl.get_bit_size() + self.ctype = ctype = '%s%s' % (tname,bitsize) + self.bits = bitsize + self.bytes = bitsize / CHAR_BIT + + if isinstance(typedecl, TypeDecl): + self.otype = '%sObject' % (ctype) + self.ftype = 'TYPE(%s)' % (name) + return + def __repr__(self): return '%s(%r)' % (self.__class__.__name__, self._typedecl) + def __str__(self): + s = [] + for k,v in self.__dict__.items(): + if k.startswith('_'): continue + s.append('%s=%s' % (k,v)) + return 'PyTypeInterface(%s)' % (', '.join(s)) + +class PythonCAPIType(WrapperBase): + """ + Fortran type hooks. + """ + def __init__(self, parent, typedecl): + WrapperBase.__init__(self) + if isinstance(typedecl, tuple(declaration_type_spec)): + if isinstance(typedecl, TypeStmt): + type_decl = typedecl.get_type_decl(typedecl.name) + assert type_decl is not None,"%s %s" % (typedecl,typedecl.name) + PythonCAPIDerivedType(parent, type_decl) + else: + PythonCAPIIntrinsicType(parent, typedecl) + elif isinstance(typedecl, TypeDecl): + PythonCAPIDerivedType(parent, typedecl) + else: + raise NotImplementedError,`self.__class__,typedecl.__class__` + return + +class PythonCAPIIntrinsicType(WrapperBase): + """ + Fortran intrinsic type hooks. + """ + + capi_code_template_scalar = ''' +static PyObject* pyobj_from_%(ctype)s(%(ctype)s* value) { + PyObject* obj = PyArrayScalar_New(%(Cls)s); +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + fprintf(stderr,"pyobj_from_%(ctype)s(value=%%"%(CTYPE)s_FMT")\\n",*value); +#endif + if (obj==NULL) /* TODO: set exception */ return NULL; + PyArrayScalar_ASSIGN(obj,%(Cls)s,*value); + return obj; +} + +static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) { + int return_value = 0; +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + fprintf(stderr,"pyobj_to_%(ctype)s(type=%%s)\\n",PyString_AS_STRING(PyObject_Repr(PyObject_Type(obj)))); +#endif + if (obj==NULL) ; + else if (PyArray_IsScalar(obj,%(Cls)s)) { + *value = PyArrayScalar_VAL(obj,%(Cls)s); + return_value = 1; + } + else if (PySequence_Check(obj)) { + if (PySequence_Size(obj)==1) + return_value = pyobj_to_%(ctype)s(PySequence_GetItem(obj,0),value); + } else { + PyObject* sc = Py%(Cls)sArrType_Type.tp_new( + &Py%(Cls)sArrType_Type,Py_BuildValue("(O)",obj),NULL); + if (sc==NULL) ; + else if (PyArray_IsScalar(sc, Generic)) + return_value = pyobj_to_%(ctype)s(sc,value); + else + return_value = pyobj_to_%(ctype)s(PyArray_ScalarFromObject(sc),value); + } + if (!return_value && !PyErr_Occurred()) { + PyObject* r = PyString_FromString("Failed to convert "); + PyString_ConcatAndDel(&r, PyObject_Repr(PyObject_Type(obj))); + PyString_ConcatAndDel(&r, PyString_FromString(" to C %(ctype)s")); + PyErr_SetObject(PyExc_TypeError,r); + } +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + if (PyErr_Occurred()) { + if (return_value) + fprintf(stderr,"pyobj_to_%(ctype)s:INCONSISTENCY with return_value=%%d and PyErr_Occurred()=%%p\\n",return_value, PyErr_Occurred()); + else + fprintf(stderr,"pyobj_to_%(ctype)s: PyErr_Occurred()=%%p\\n", PyErr_Occurred()); + } else { + if (return_value) + fprintf(stderr,"pyobj_to_%(ctype)s: value=%%"%(CTYPE)s_FMT"\\n", *value); + else + fprintf(stderr,"pyobj_to_%(ctype)s:INCONSISTENCY with return_value=%%d and PyErr_Occurred()=%%p\\n",return_value, PyErr_Occurred()); + } +#endif + return return_value; +} +''' + + capi_code_template_complex_scalar = ''' +static PyObject* pyobj_from_%(ctype)s(%(ctype)s* value) { + PyObject* obj = PyArrayScalar_New(%(Cls)s); +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + fprintf(stderr,"pyobj_from_%(ctype)s(value=(%%"%(FCTYPE)s_FMT",%%"%(FCTYPE)s_FMT"))\\n",value->real, value->imag); +#endif + if (obj==NULL) /* TODO: set exception */ return NULL; + PyArrayScalar_ASSIGN(obj,%(Cls)s,*value); + return obj; +} + +static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) { + int return_value = 0; +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + fprintf(stderr,"pyobj_to_%(ctype)s(type=%%s)\\n",PyString_AS_STRING(PyObject_Repr(PyObject_Type(obj)))); +#endif + if (obj==NULL) ; + else if (PyArray_IsScalar(obj,%(Cls)s)) { + value->real = PyArrayScalar_VAL(obj,%(Cls)s).real; + value->imag = PyArrayScalar_VAL(obj,%(Cls)s).imag; + return_value = 1; + } + else if (PySequence_Check(obj)) { + if (PySequence_Size(obj)==1) + return_value = pyobj_to_%(ctype)s(PySequence_GetItem(obj,0),value); + else if (PySequence_Size(obj)==2) { + return_value = pyobj_to_%(fctype)s(PySequence_GetItem(obj,0),&(value->real)) + && pyobj_to_%(fctype)s(PySequence_GetItem(obj,1),&(value->imag)); + } + } else { + PyObject* sc = Py%(Cls)sArrType_Type.tp_new( + &Py%(Cls)sArrType_Type,Py_BuildValue("(O)",obj),NULL); + if (sc==NULL) ; + else if (PyArray_IsScalar(sc, Generic)) + return_value = pyobj_to_%(ctype)s(sc,value); + else + return_value = pyobj_to_%(ctype)s(PyArray_ScalarFromObject(sc),value); + } + if (!return_value && !PyErr_Occurred()) { + PyObject* r = PyString_FromString("Failed to convert "); + PyString_ConcatAndDel(&r, PyObject_Repr(PyObject_Type(obj))); + PyString_ConcatAndDel(&r, PyString_FromString(" to C %(ctype)s")); + PyErr_SetObject(PyExc_TypeError,r); + } +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + if (PyErr_Occurred()) { + if (return_value) + fprintf(stderr,"pyobj_to_%(ctype)s:INCONSISTENCY with return_value=%%d and PyErr_Occurred()=%%p\\n",return_value, PyErr_Occurred()); + else + fprintf(stderr,"pyobj_to_%(ctype)s: PyErr_Occurred()=%%p\\n", PyErr_Occurred()); + } else { + if (return_value) + fprintf(stderr,"pyobj_to_%(ctype)s: value=(%%"%(FCTYPE)s_FMT",%%"%(FCTYPE)s_FMT")\\n", + value->real, value->imag); + else + fprintf(stderr,"pyobj_to_%(ctype)s:INCONSISTENCY with return_value=%%d and PyErr_Occurred()=%%p\\n",return_value, PyErr_Occurred()); + } +#endif + return return_value; +} +''' + + capi_code_template_logical_scalar = ''' +static PyObject* pyobj_from_%(ctype)s(%(ctype)s* value) { +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + fprintf(stderr,"pyobj_from_%(ctype)s(value=%%"%(ICTYPE)s_FMT")\\n",*value); +#endif + if (*value) { + PyArrayScalar_RETURN_TRUE; + } else { + PyArrayScalar_RETURN_FALSE; + } +} +static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) { + int return_value = 0; +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + fprintf(stderr,"pyobj_to_%(ctype)s(type=%%s)\\n",PyString_AS_STRING(PyObject_Repr(PyObject_Type(obj)))); +#endif + if (obj==NULL) ; + else if (PyArray_IsScalar(obj,Bool)) { + *value = PyArrayScalar_VAL(obj,Bool); + return_value = 1; + } else { + switch (PyObject_IsTrue(obj)) { + case 0: *value = 0; return_value = 1; break; + case -1: break; + default: *value = 1; return_value = 1; + } + } + if (!return_value && !PyErr_Occurred()) { + PyObject* r = PyString_FromString("Failed to convert "); + PyString_ConcatAndDel(&r, PyObject_Repr(PyObject_Type(obj))); + PyString_ConcatAndDel(&r, PyString_FromString(" to C %(ctype)s")); + PyErr_SetObject(PyExc_TypeError,r); + } +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + if (PyErr_Occurred()) { + if (return_value) + fprintf(stderr,"pyobj_to_%(ctype)s:INCONSISTENCY with return_value=%%d and PyErr_Occurred()=%%p\\n",return_value, PyErr_Occurred()); + else + fprintf(stderr,"pyobj_to_%(ctype)s: PyErr_Occurred()=%%p\\n", PyErr_Occurred()); + } else { + if (return_value) + fprintf(stderr,"pyobj_to_%(ctype)s: value=%%"%(ICTYPE)s_FMT"\\n", *value); + else + fprintf(stderr,"pyobj_to_%(ctype)s:INCONSISTENCY with return_value=%%d and PyErr_Occurred()=%%p\\n",return_value, PyErr_Occurred()); + } +#endif + return return_value; +} +''' + capi_code_template_string_scalar = ''' +static PyObject* pyobj_from_%(ctype)s(%(ctype)s* value) { +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + fprintf(stderr,"pyobj_from_%(ctype)s(value->data=\'%%s\')\\n",value->data); +#endif + PyArray_Descr* descr = PyArray_DescrNewFromType(NPY_STRING); + descr->elsize = %(bytes)s; + PyObject* obj = PyArray_Scalar(value->data, descr, NULL); + if (obj==NULL) /* TODO: set exception */ return NULL; + return obj; +} + +static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) { + int return_value = 0; +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + fprintf(stderr,"pyobj_to_%(ctype)s(type=%%s)\\n",PyString_AS_STRING(PyObject_Repr(PyObject_Type(obj)))); +#endif + if (PyString_Check(obj)) { + int s = PyString_GET_SIZE(obj); + memset(value->data, (int)\' \',%(bytes)s); + return_value = !! strncpy(value->data,PyString_AS_STRING(obj),%(bytes)s); + if (return_value && s<%(bytes)s) { + memset(value->data + s, (int)\' \',%(bytes)s-s); + } + } else { + return_value = pyobj_to_%(ctype)s(PyObject_Str(obj), value); + } + if (!return_value && !PyErr_Occurred()) { + PyObject* r = PyString_FromString("Failed to convert "); + PyString_ConcatAndDel(&r, PyObject_Repr(PyObject_Type(obj))); + PyString_ConcatAndDel(&r, PyString_FromString(" to C %(ctype)s")); + PyErr_SetObject(PyExc_TypeError,r); + } +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + if (PyErr_Occurred()) { + if (return_value) + fprintf(stderr,"pyobj_to_%(ctype)s:INCONSISTENCY with return_value=%%d and PyErr_Occurred()=%%p\\n",return_value, PyErr_Occurred()); + else + fprintf(stderr,"pyobj_to_%(ctype)s: PyErr_Occurred()=%%p\\n", PyErr_Occurred()); + } else { + if (return_value) + fprintf(stderr,"pyobj_to_%(ctype)s: value->data=\'%%s\'\\n", value->data); + else + fprintf(stderr,"pyobj_to_%(ctype)s:INCONSISTENCY with return_value=%%d and PyErr_Occurred()=%%p\\n",return_value, PyErr_Occurred()); + } +#endif + return return_value; +} +''' + capi_code_template_string0_scalar = ''' +static PyObject* pyobj_from_%(ctype)s(%(ctype)s* value) { +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + fprintf(stderr,"pyobj_from_%(ctype)s(value->len=%%d, value->data=\'%%s\')\\n",value->len, value->data); +#endif + PyArray_Descr* descr = PyArray_DescrNewFromType(NPY_STRING); + descr->elsize = value->len; + PyObject* obj = PyArray_Scalar(value->data, descr, NULL); + if (obj==NULL) /* TODO: set exception */ return NULL; + return obj; +} + +static int pyobj_to_%(ctype)s(PyObject *obj, %(ctype)s* value) { + int return_value = 0; +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + fprintf(stderr,"pyobj_to_%(ctype)s(type=%%s)\\n",PyString_AS_STRING(PyObject_Repr(PyObject_Type(obj)))); +#endif + if (PyString_Check(obj)) { + value->len = PyString_GET_SIZE(obj); + value->data = malloc(value->len*sizeof(char)); + return_value = !! strncpy(value->data,PyString_AS_STRING(obj),value->len); + } else { + return_value = pyobj_to_%(ctype)s(PyObject_Str(obj), value); + } + if (!return_value && !PyErr_Occurred()) { + PyObject* r = PyString_FromString("Failed to convert "); + PyString_ConcatAndDel(&r, PyObject_Repr(PyObject_Type(obj))); + PyString_ConcatAndDel(&r, PyString_FromString(" to C %(ctype)s")); + PyErr_SetObject(PyExc_TypeError,r); + } +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + if (PyErr_Occurred()) { + if (return_value) + fprintf(stderr,"pyobj_to_%(ctype)s:INCONSISTENCY with return_value=%%d and PyErr_Occurred()=%%p\\n",return_value, PyErr_Occurred()); + else + fprintf(stderr,"pyobj_to_%(ctype)s: PyErr_Occurred()=%%p\\n", PyErr_Occurred()); + } else { + if (return_value) + fprintf(stderr,"pyobj_to_%(ctype)s: value->len=%%d, value->data=\'%%s\'\\n", value->len, value->data); + else + fprintf(stderr,"pyobj_to_%(ctype)s:INCONSISTENCY with return_value=%%d and PyErr_Occurred()=%%p\\n",return_value, PyErr_Occurred()); + } +#endif + return return_value; +} +''' + def __init__(self, parent, typedecl): + WrapperBase.__init__(self) + self.name = name = typedecl.name + ti = PyTypeInterface(typedecl) + self.ctype = ctype = ti.ctype + + defined = parent.defined_types + if ctype in defined: + return + defined.append(ctype) + + self.info('Generating interface for %s: %s' % (typedecl.__class__.__name__, ctype)) + self.parent = parent + if isinstance(typedecl, (Integer,Byte,Real,DoublePrecision)): + self.Cls = ctype[4].upper() + ctype[5:] + self.capi_code_template = self.capi_code_template_scalar + elif isinstance(typedecl, (Complex,DoubleComplex)): + self.Cls = ctype[4].upper() + ctype[5:] + PythonCAPIIntrinsicType(parent, typedecl.get_part_typedecl()) + ti1 = PyTypeInterface(typedecl.get_part_typedecl()) + self.fctype = ti1.ctype + self.capi_code_template = self.capi_code_template_complex_scalar + elif isinstance(typedecl, Logical): + self.ictype = 'npy_int%s' % (typedecl.get_bit_size()) + self.header_template = '#define %(ctype)s %(ictype)s' + self.capi_code_template = self.capi_code_template_logical_scalar + elif isinstance(typedecl, Character): + self.bits = bits = typedecl.get_bit_size() + if bits: + self.bytes = bits/CHAR_BIT + self.header_template = ''' +#include <string.h> +typedef struct { char data[%(bytes)s]; } %(ctype)s; +''' + self.capi_code_template = self.capi_code_template_string_scalar + else: + self.header_template = ''' +#include <string.h> +typedef struct { char* data; size_t len; } %(ctype)s; +''' + self.capi_code_template = self.capi_code_template_string0_scalar + else: + raise NotImplementedError,`name,ctype` + parent.apply_templates(self) + return + +class PythonCAPIDerivedType(WrapperBase): + """ + Fortran 90 derived type hooks. + """ + + header_template_wrapper = '''\ +#define %(otype)s_Check(obj) \\ + PyObject_TypeCheck((PyObject*)obj, &%(otype)sType) +#define %(init_func)s_f \\ + F_FUNC(%(init_func)s,%(INIT_FUNC)s) +''' + + typedef_template_wrapper = '''\ +typedef void * %(ctype)s; +typedef struct { + PyObject_HEAD + %(ptrstruct_list)s + %(ctype)s data; +} %(otype)s; +typedef void (*%(init_func)s_c_functype)(%(init_func_c_ctype_arg_clist)s); +''' + + typedef_template_importer = '''\ +typedef void * %(ctype)s; +typedef struct { + PyObject_HEAD + %(ptrstruct_list)s + %(ctype)s data; +} %(otype)s; +typedef int (*pyobj_to_%(ctype)s_inplace_functype)(PyObject*, %(otype)s** ); +typedef int (*pyobj_to_%(ctype)s_functype)(PyObject*, %(otype)s* ); +typedef PyObject* (*pyobj_from_%(ctype)s_functype)(%(ctype)s*); +#define %(otype)sType (*(PyTypeObject *)PyArray_API[0]) +#define pyobj_from_%(ctype)s ((pyobj_from_%(ctype)s_functype)PyArray_API[1]) +#define pyobj_to_%(ctype)s_inplace ((pyobj_to_%(ctype)s_inplace_functype)PyArray_API[2]) +''' + + extern_template_wrapper = '''\ +static PyTypeObject %(otype)sType; +extern void %(init_func)s_f(%(init_func)s_c_functype, void*, %(ctype)s); +''' + + objdecl_template_wrapper = '''\ +static PyMethodDef %(otype)s_methods[] = { + %(type_method_list)s + {NULL} /* Sentinel */ +}; + +static PyGetSetDef %(otype)s_getseters[] = { + %(type_getseters_list)s + {NULL} /* Sentinel */ +}; + +static PyTypeObject %(otype)sType = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "%(modulename)s.%(name)s", /*tp_name*/ + sizeof(%(otype)s), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)%(otype)s_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + %(otype)s_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "Fortran derived type %(name)s objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + %(otype)s_methods, /* tp_methods */ + 0 /*%(otype)s_members*/, /* tp_members */ + %(otype)s_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)%(otype)s_init, /* tp_init */ + 0, /* tp_alloc */ + %(otype)s_new, /* tp_new */ +}; + +void *F2PY_%(otype)s_API[] = { + (void *) &%(otype)sType, + (void *) pyobj_from_%(ctype)s, + (void *) pyobj_to_%(ctype)s_inplace +}; +''' + + objdecl_template_importer = '''\ +static void **F2PY_%(otype)s_API; +''' + module_init_template_wrapper = '''\ +if (PyType_Ready(&%(otype)sType) < 0) goto capi_err; +PyModule_AddObject(f2py_module, "%(name)s", (PyObject *)&%(otype)sType); +{ + PyObject* c_api = PyCObject_FromVoidPtr((void *)F2PY_%(otype)s_API, NULL); + PyModule_AddObject(f2py_module, "_%(NAME)s_API", c_api); + if (PyErr_Occurred()) goto capi_err; +} +''' + module_init_template_importer = '''\ +{ + PyObject *c_api = NULL; + PyObject *wrappermodule = PyImport_ImportModule("%(wrappermodulename)s"); + if (wrappermodule == NULL) goto capi_%(name)s_err; + c_api = PyObject_GetAttrString(wrappermodule, "_%(NAME)s_API"); + if (c_api == NULL) {Py_DECREF(wrappermodule); goto capi_%(name)s_err;} + if (PyCObject_Check(c_api)) { + F2PY_%(otype)s_API = (void **)PyCObject_AsVoidPtr(c_api); + } + Py_DECREF(c_api); + Py_DECREF(wrappermodule); + if (F2PY_%(otype)s_API != NULL) goto capi_%(name)s_ok; +capi_%(name)s_err: + PyErr_Print(); + PyErr_SetString(PyExc_ImportError, "%(wrappermodulename)s failed to import"); + return; +capi_%(name)s_ok: + c_api = PyCObject_FromVoidPtr((void *)F2PY_%(otype)s_API, NULL); + PyModule_AddObject(f2py_module, "_%(NAME)s_API", c_api); + if (PyErr_Occurred()) goto capi_err; +} +''' + + c_code_template_wrapper = '''\ +static void %(init_func)s_c( + %(init_func_c_arg_clist)s) { + %(init_func_c_body_list)s +} +''' + + capi_code_template_wrapper = '''\ +static void %(otype)s_dealloc(%(otype)s* self) { + if (self->data) + PyMem_Free(self->data); + self->ob_type->tp_free((PyObject*)self); +} + +static int pyobj_to_%(ctype)s_inplace(PyObject *obj, + %(otype)s** value_ptr) { + int return_value = 0; +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + fprintf(stderr,"pyobj_to_%(ctype)s(type=%%s)\\n",PyString_AS_STRING(PyObject_Repr(PyObject_Type(obj)))); +#endif + if (%(otype)s_Check(obj)) { + *value_ptr = (%(otype)s*)obj; + return_value = 1; + } +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + fprintf(stderr,"pyobj_to_%(ctype)s: return_value=%%d, PyErr_Occurred()=%%p\\n", return_value, PyErr_Occurred()); +#endif + return return_value; +} + +static int pyobj_to_%(ctype)s(PyObject *obj, + %(ctype)s* value_ptr) { + int return_value = 0; +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + fprintf(stderr,"pyobj_to_%(ctype)s(type=%%s)\\n",PyString_AS_STRING(PyObject_Repr(PyObject_Type(obj)))); +#endif + if (%(otype)s_Check(obj)) { + if (!memcpy(value_ptr,((%(otype)s *)obj)->data, %(bytes)s)) { + PyErr_SetString(PyExc_MemoryError, + "failed to copy %(name)s instance memory to %(ctype)s object."); + } else { + return_value = 1; + } + } +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + fprintf(stderr,"pyobj_to_%(ctype)s: return_value=%%d, PyErr_Occurred()=%%p\\n", return_value, PyErr_Occurred()); +#endif + return return_value; +} + +static PyObject* pyobj_from_%(ctype)s(%(ctype)s* value_ptr) { + %(otype)s* obj = (%(otype)s*)(%(otype)sType.tp_alloc(&%(otype)sType, 0)); + if (obj == NULL) + return NULL; + obj->data = PyMem_Malloc(%(bytes)s); + if (obj->data == NULL) { + Py_DECREF(obj); + return PyErr_NoMemory(); + } + if (value_ptr) { + if (!memcpy(obj->data, value_ptr, %(bytes)s)) { + PyErr_SetString(PyExc_MemoryError, + "failed to copy %(ctype)s object memory to %(name)s instance."); + } + } + %(init_func)s_f(%(init_func)s_c, obj, obj->data); + return (PyObject*)obj; +} + +static PyObject * %(otype)s_new(PyTypeObject *type, + PyObject *args, PyObject *kwds) +{ + return pyobj_from_%(ctype)s(NULL); +} + +static int %(otype)s_init(%(otype)s *self, + PyObject *capi_args, PyObject *capi_kwds) +{ + int return_value = 0; +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + fprintf(stderr,"%(otype)s_init()\\n"); +#endif + if (!PyArg_ParseTuple(capi_args,"%(attr_format_elist)s" + %(attr_init_clist)s)) + return_value = -1; + +#if defined(F2PY_DEBUG_PYOBJ_TOFROM) + fprintf(stderr,"%(otype)s_init: return_value=%%d, PyErr_Occurred()=%%p\\n", return_value, PyErr_Occurred()); +#endif + return return_value; +} + +static PyObject * %(otype)s_as_tuple(%(otype)s * self) { + return Py_BuildValue("%(as_tuple_format_elist)s" + %(as_tuple_arg_clist)s); +} + +static PyObject * %(otype)s_repr(PyObject * self) { + PyObject* r = PyString_FromString("%(name)s("); + PyString_ConcatAndDel(&r, PyObject_Repr(%(otype)s_as_tuple((%(otype)s*)self))); + PyString_ConcatAndDel(&r, PyString_FromString(")")); + return r; +} + +%(getset_func_list)s +''' + + fortran_code_template_wrapper = '''\ + subroutine %(init_func)s(init_func_c, self, obj) + %(use_stmt_list)s + %(type_decl_list)s + external init_func_c +! self is %(otype)s + external self + %(ftype)s obj + call init_func_c(%(init_func_f_arg_clist)s) + end +''' + + #module_method_template = '''''' + + _defined = [] + def __init__(self, parent, typedecl): + WrapperBase.__init__(self) + ti = PyTypeInterface(typedecl) + self.ctype = ctype = ti.ctype + defined = parent.defined_types + if ctype in defined: + return + defined.append(ctype) + + + + implement_wrappers = True + if isinstance(typedecl.parent,Module) and typedecl.parent.name!=parent.modulename: + implement_wrappers = False + self.info('Using api for %s.%s: %s' % (parent.modulename, typedecl.name, ctype)) + self.wrappermodulename = typedecl.parent.name + else: + self.info('Generating interface for %s.%s: %s' % (parent.modulename, typedecl.name, ctype)) + + parent.isf90 = True + self.parent = parent + self.name = name = typedecl.name + self.otype = otype = ti.otype + self.ctype = ctype = ti.ctype + self.ctype_ptrs = self.ctype + '_ptrs' + self.ftype = ti.ftype + self.bytes = bytes = ti.bytes + + if not implement_wrappers: + self.typedef_template = self.typedef_template_importer + self.objdecl_template = self.objdecl_template_importer + self.module_init_template = self.module_init_template_importer + else: + self.header_template = self.header_template_wrapper + self.typedef_template = self.typedef_template_wrapper + self.extern_template = self.extern_template_wrapper + self.objdecl_template = self.objdecl_template_wrapper + self.module_init_template = self.module_init_template_wrapper + self.c_code_template = self.c_code_template_wrapper + self.capi_code_template = self.capi_code_template_wrapper + self.fortran_code_template = self.fortran_code_template_wrapper + WrapperCPPMacro(parent, 'F_FUNC') + + self.init_func_f_arg_list = ['self'] + self.init_func_c_arg_list = ['%s *self' % (otype)] + self.init_func_c_ctype_arg_list = ['%s *' % (otype)] + self.init_func_c_body_list = [] + self.ptrstruct_list = [] + self.attr_decl_list = [] + self.attr_format_list = [] + self.attr_init_list = [] + self.as_tuple_format_list = [] + self.as_tuple_arg_list = [] + self.getset_func_list = [] + self.type_getseters_list = [] + for n in typedecl.a.component_names: + v = typedecl.a.components[n] + t = v.get_typedecl() + ti1 = PyTypeInterface(t) + PythonCAPIType(parent, t) + ct = ti1.ctype + parent.add(t) + self.ptrstruct_list.append('%s* %s_ptr;' % (ct, n)) + self.init_func_f_arg_list.append('obj %% %s' % (n)) + self.init_func_c_arg_list.append('\n%s * %s_ptr' % (ct, n)) + self.init_func_c_ctype_arg_list.append('\n%s *' % (ct)) + self.init_func_c_body_list.append('''\ +if (!((void*)%(n)s_ptr >= self->data + && (void*)%(n)s_ptr < self->data + %(bytes)s )) + fprintf(stderr,"INCONSISTENCY IN %(name)s WRAPPER: " + "self->data=%%p <= %(n)s_ptr=%%p < self->data+%(bytes)s=%%p\\n", + self->data, %(n)s_ptr, self->data + %(bytes)s); +self->%(n)s_ptr = %(n)s_ptr; +''' % (locals())) + self.attr_format_list.append('O&') + self.attr_init_list.append('\npyobj_to_%s, self->%s_ptr' % (ct,n)) + self.as_tuple_format_list.append('O&') + self.as_tuple_arg_list.append('\npyobj_from_%s, self->%s_ptr' % (ct, n)) + self.getset_func_list.append('''\ +static PyObject * %(otype)s_get_%(n)s(%(otype)s *self, + void *closure) { + return pyobj_from_%(ct)s(self->%(n)s_ptr); +} +static int %(otype)s_set_%(n)s(%(otype)s *self, + PyObject *value, void *closure) +{ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, + "Cannot delete %(name)s attribute %(n)s"); + return -1; + } + if (pyobj_to_%(ct)s(value, self->%(n)s_ptr)) + return 0; + return -1; +} +''' % (locals())) + self.type_getseters_list.append('{"%(n)s",(getter)%(otype)s_get_%(n)s, (setter)%(otype)s_set_%(n)s,\n "component %(n)s",NULL},' % (locals())) + if self.attr_init_list: self.attr_init_list.insert(0,'') + if self.as_tuple_arg_list: self.as_tuple_arg_list.insert(0,'') + self.init_func = self.ctype + '_init' + + self.type_method_list = [] + self.type_method_list.append('{"as_tuple",(PyCFunction)%(otype)s_as_tuple,METH_NOARGS,\n "Return %(name)s components as tuple."},' % (self.__dict__)) + + self.use_stmt_list = [] + self.type_decl_list = [] + if isinstance(typedecl.parent, Module): + self.use_stmt_list.append('use %s' % (typedecl.parent.name)) + elif isinstance(typedecl.parent, (Subroutine, Function)): + self.type_decl_list.append(typedecl.asfix()) + else: + raise NotImplementedError,'types declared in '+typedecl.parent.__class__.__name__ + parent.apply_templates(self) + return diff --git a/numpy/f2py/lib/setup.py b/numpy/f2py/lib/setup.py new file mode 100644 index 000000000..cd63b07cd --- /dev/null +++ b/numpy/f2py/lib/setup.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python +def configuration(parent_package='',top_path=None): + from numpy.distutils.misc_util import Configuration + config = Configuration('lib',parent_package,top_path) + config.add_subpackage('parser') + config.add_data_files('*.txt','parser/*.txt') + config.add_data_dir('src') + return config + +if __name__ == "__main__": + from numpy.distutils.core import setup + setup(configuration=configuration) diff --git a/numpy/f2py/lib/src/F_FUNC.cpp b/numpy/f2py/lib/src/F_FUNC.cpp new file mode 100644 index 000000000..edaa98064 --- /dev/null +++ b/numpy/f2py/lib/src/F_FUNC.cpp @@ -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 diff --git a/numpy/f2py/lib/src/pyobj_to_string_len.c b/numpy/f2py/lib/src/pyobj_to_string_len.c new file mode 100644 index 000000000..306c961a3 --- /dev/null +++ b/numpy/f2py/lib/src/pyobj_to_string_len.c @@ -0,0 +1,11 @@ +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; +} diff --git a/numpy/f2py/lib/tests/test_derived_scalar.py b/numpy/f2py/lib/tests/test_derived_scalar.py new file mode 100644 index 000000000..c57778020 --- /dev/null +++ b/numpy/f2py/lib/tests/test_derived_scalar.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python +""" +Tests for intent(in,out) derived type arguments in Fortran subroutine's. + +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: Oct 2006 +----- +""" + +import os +import sys +from numpy.testing import * +set_package_path() +from lib.main import build_extension, compile +restore_path() + +fortran_code = ''' +subroutine foo(a) + type myt + integer flag + end type myt + type(myt) a +!f2py intent(in,out) a + a % flag = a % flag + 1 +end +function foo2(a) + type myt + integer flag + end type myt + type(myt) a + type(myt) foo2 + foo2 % flag = a % flag + 2 +end +''' + +m, = compile(fortran_code, 'test_derived_scalar_ext') + +from numpy import * + +class test_m(NumpyTestCase): + + def check_foo_simple(self, level=1): + a = m.myt(2) + assert_equal(a.flag,2) + assert isinstance(a,m.myt),`a` + r = m.foo(a) + assert isinstance(r,m.myt),`r` + assert r is a + assert_equal(r.flag,3) + assert_equal(a.flag,3) + + a.flag = 5 + assert_equal(r.flag,5) + + #s = m.foo((5,)) + + def check_foo2_simple(self, level=1): + a = m.myt(2) + assert_equal(a.flag,2) + assert isinstance(a,m.myt),`a` + r = m.foo2(a) + assert isinstance(r,m.myt),`r` + assert r is not a + assert_equal(a.flag,2) + assert_equal(r.flag,4) + + +if __name__ == "__main__": + NumpyTest().run() diff --git a/numpy/f2py/lib/tests/test_module_module.py b/numpy/f2py/lib/tests/test_module_module.py new file mode 100644 index 000000000..4d242ed54 --- /dev/null +++ b/numpy/f2py/lib/tests/test_module_module.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python +""" +Tests for module with scalar derived types and subprograms. + +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: Oct 2006 +----- +""" + +import os +import sys +from numpy.testing import * + +set_package_path() +from lib.main import build_extension, compile +restore_path() + +fortran_code = ''' +module test_module_module_ext2 + type rat + integer n,d + end type rat + contains + subroutine foo2() + print*,"In foo2" + end subroutine foo2 +end module +module test_module_module_ext + contains + subroutine foo + use test_module_module_ext2 + print*,"In foo" + call foo2 + end subroutine foo + subroutine bar(a) + use test_module_module_ext2 + type(rat) a + print*,"In bar,a=",a + end subroutine bar +end module test_module_module_ext +''' + +m,m2 = compile(fortran_code, modulenames=['test_module_module_ext', + 'test_module_module_ext2', + ]) + +from numpy import * + +class test_m(NumpyTestCase): + + def check_foo_simple(self, level=1): + foo = m.foo + foo() + +if __name__ == "__main__": + NumpyTest().run() diff --git a/numpy/f2py/lib/tests/test_module_scalar.py b/numpy/f2py/lib/tests/test_module_scalar.py new file mode 100644 index 000000000..e11a1e0ae --- /dev/null +++ b/numpy/f2py/lib/tests/test_module_scalar.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +""" +Tests for module with scalar derived types and subprograms. + +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: Oct 2006 +----- +""" + +import os +import sys +from numpy.testing import * +set_package_path() +from lib.main import build_extension, compile +restore_path() + +fortran_code = ''' +module test_module_scalar_ext + + contains + subroutine foo(a) + integer a +!f2py intent(in,out) a + a = a + 1 + end subroutine foo + function foo2(a) + integer a + integer foo2 + foo2 = a + 2 + end function foo2 +end module test_module_scalar_ext +''' + +m, = compile(fortran_code, modulenames = ['test_module_scalar_ext']) + +from numpy import * + +class test_m(NumpyTestCase): + + def check_foo_simple(self, level=1): + foo = m.foo + r = foo(2) + assert isinstance(r,int32),`type(r)` + assert_equal(r,3) + + def check_foo2_simple(self, level=1): + foo2 = m.foo2 + r = foo2(2) + assert isinstance(r,int32),`type(r)` + assert_equal(r,4) + +if __name__ == "__main__": + NumpyTest().run() diff --git a/numpy/f2py/lib/tests/test_scalar_function_in.py b/numpy/f2py/lib/tests/test_scalar_function_in.py new file mode 100644 index 000000000..9c5cd8aba --- /dev/null +++ b/numpy/f2py/lib/tests/test_scalar_function_in.py @@ -0,0 +1,532 @@ +#!/usr/bin/env python +""" +Tests for intent(in) arguments in subroutine-wrapped Fortran functions. + +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: Oct 2006 +----- +""" + +import os +import sys +from numpy.testing import * + +set_package_path() +from lib.main import build_extension, compile +restore_path() + +fortran_code = '''\ +! -*- f77 -*- + function fooint1(a) + integer*1 a + integer*1 fooint1 + fooint1 = a + 1 + end + function fooint2(a) + integer*2 a + integer*2 fooint2 + fooint2 = a + 1 + end + function fooint4(a) + integer*4 a + integer*4 fooint4 + fooint4 = a + 1 + end + function fooint8(a) + integer*8 a + integer*8 fooint8 + fooint8 = a + 1 + end + function foofloat4(a) + real*4 a + real*4 foofloat4 + foofloat4 = a + 1.0e0 + end + function foofloat8(a) + real*8 a + real*8 foofloat8 + foofloat8 = a + 1.0d0 + end + function foocomplex8(a) + complex*8 a + complex*8 foocomplex8 + foocomplex8 = a + 1.0e0 + end + function foocomplex16(a) + complex*16 a + complex*16 foocomplex16 + foocomplex16 = a + 1.0d0 + end + function foobool1(a) + logical*1 a + logical*1 foobool1 + foobool1 = .not. a + end + function foobool2(a) + logical*2 a + logical*2 foobool2 + foobool2 = .not. a + end + function foobool4(a) + logical*4 a + logical*4 foobool4 + foobool4 = .not. a + end + function foobool8(a) + logical*8 a + logical*8 foobool8 + foobool8 = .not. a + end + function foostring1(a) + character*1 a + character*1 foostring1 + foostring1 = "1" + end + function foostring5(a) + character*5 a + character*5 foostring5 + foostring5 = a + foostring5(1:2) = "12" + end +! function foostringstar(a) +! character*(*) a +! character*(*) foostringstar +! if (len(a).gt.0) then +! foostringstar = a +! foostringstar(1:1) = "1" +! endif +! end +''' + +m, = compile(fortran_code, 'test_scalar_function_in_ext') + +from numpy import * + +class test_m(NumpyTestCase): + + def check_foo_integer1(self, level=1): + i = int8(2) + e = int8(3) + func = m.fooint1 + assert isinstance(i,int8),`type(i)` + r = func(i) + assert isinstance(r,int8),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + r = func(2) + assert isinstance(r,int8),`type(r)` + assert_equal(r,e) + + for intx in [int64,int16,int32]: + r = func(intx(2)) + assert isinstance(r,int8),`type(r)` + assert_equal(r,e) + + r = func(2.0) + assert isinstance(r,int8),`type(r)` + assert_equal(r,e) + + r = func(2.2) + assert isinstance(r,int8),`type(r)` + assert_equal(r,e) + + r = func([2]) + assert isinstance(r,int8),`type(r)` + assert_equal(r,e) + + self.assertRaises(TypeError,lambda :func(2.2j)) + self.assertRaises(TypeError,lambda :func([2,1])) + self.assertRaises(TypeError,lambda :func({})) + + def check_foo_integer2(self, level=1): + i = int16(2) + e = int16(3) + func = m.fooint2 + assert isinstance(i,int16),`type(i)` + r = func(i) + assert isinstance(r,int16),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + r = func(2) + assert isinstance(r,int16),`type(r)` + assert_equal(r,e) + + for intx in [int8,int64,int32]: + r = func(intx(2)) + assert isinstance(r,int16),`type(r)` + assert_equal(r,e) + + r = func(2.0) + assert isinstance(r,int16),`type(r)` + assert_equal(r,e) + + r = func(2.2) + assert isinstance(r,int16),`type(r)` + assert_equal(r,e) + + r = func([2]) + assert isinstance(r,int16),`type(r)` + assert_equal(r,e) + + self.assertRaises(TypeError,lambda :func(2.2j)) + self.assertRaises(TypeError,lambda :func([2,1])) + self.assertRaises(TypeError,lambda :func({})) + + def check_foo_integer4(self, level=1): + i = int32(2) + e = int32(3) + func = m.fooint4 + assert isinstance(i,int32),`type(i)` + r = func(i) + assert isinstance(r,int32),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + r = func(2) + assert isinstance(r,int32),`type(r)` + assert_equal(r,e) + + for intx in [int8,int16,int64]: + r = func(intx(2)) + assert isinstance(r,int32),`type(r)` + assert_equal(r,e) + + r = func(2.0) + assert isinstance(r,int32),`type(r)` + assert_equal(r,e) + + r = func(2.2) + assert isinstance(r,int32),`type(r)` + assert_equal(r,e) + + r = func([2]) + assert isinstance(r,int32),`type(r)` + assert_equal(r,e) + + self.assertRaises(TypeError,lambda :func(2.2j)) + self.assertRaises(TypeError,lambda :func([2,1])) + self.assertRaises(TypeError,lambda :func({})) + + def check_foo_integer8(self, level=1): + i = int64(2) + e = int64(3) + func = m.fooint8 + assert isinstance(i,int64),`type(i)` + r = func(i) + assert isinstance(r,int64),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + r = func(2) + assert isinstance(r,int64),`type(r)` + assert_equal(r,e) + + r = func(2.0) + assert isinstance(r,int64),`type(r)` + assert_equal(r,e) + + r = func(2.2) + assert isinstance(r,int64),`type(r)` + assert_equal(r,e) + + for intx in [int8,int16,int32]: + r = func(intx(2)) + assert isinstance(r,int64),`type(r)` + assert_equal(r,e) + + r = func([2]) + assert isinstance(r,int64),`type(r)` + assert_equal(r,e) + + self.assertRaises(TypeError,lambda :func(2.2j)) + self.assertRaises(TypeError,lambda :func([2,1])) + self.assertRaises(TypeError,lambda :func({})) + + def check_foo_real4(self, level=1): + i = float32(2) + e = float32(3) + func = m.foofloat4 + assert isinstance(i,float32),`type(i)` + r = func(i) + assert isinstance(r,float32),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + r = func(2) + assert isinstance(r,float32),`type(r)` + assert_equal(r,e) + + r = func(2.0) + assert isinstance(r,float32),`type(r)` + assert_equal(r,e) + + r = func(2.2) + assert isinstance(r,float32),`type(r)` + assert_equal(r,e+float32(0.2)) + + r = func(float64(2.0)) + assert isinstance(r,float32),`type(r)` + assert_equal(r,e) + + r = func([2]) + assert isinstance(r,float32),`type(r)` + assert_equal(r,e) + + self.assertRaises(TypeError,lambda :func(2.2j)) + self.assertRaises(TypeError,lambda :func([2,1])) + self.assertRaises(TypeError,lambda :func({})) + + def check_foo_real8(self, level=1): + i = float64(2) + e = float64(3) + func = m.foofloat8 + assert isinstance(i,float64),`type(i)` + r = func(i) + assert isinstance(r,float64),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + r = func(2) + assert isinstance(r,float64),`type(r)` + assert_equal(r,e) + + r = func(2.0) + assert isinstance(r,float64),`type(r)` + assert_equal(r,e) + + r = func(2.2) + assert isinstance(r,float64),`type(r)` + assert_equal(r,e+float64(0.2)) + + r = func(float32(2.0)) + assert isinstance(r,float64),`type(r)` + assert_equal(r,e) + + r = func([2]) + assert isinstance(r,float64),`type(r)` + assert_equal(r,e) + + self.assertRaises(TypeError,lambda :func(2.2j)) + self.assertRaises(TypeError,lambda :func([2,1])) + self.assertRaises(TypeError,lambda :func({})) + + def check_foo_complex8(self, level=1): + i = complex64(2) + e = complex64(3) + func = m.foocomplex8 + assert isinstance(i,complex64),`type(i)` + r = func(i) + assert isinstance(r,complex64),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + r = func(2) + assert isinstance(r,complex64),`type(r)` + assert_equal(r,e) + + r = func(2.0) + assert isinstance(r,complex64),`type(r)` + assert_equal(r,e) + + r = func(2.2) + assert isinstance(r,complex64),`type(r)` + assert_equal(r,e+complex64(0.2)) + + r = func(2+1j) + assert isinstance(r,complex64),`type(r)` + assert_equal(r,e+complex64(1j)) + + r = func(complex128(2.0)) + assert isinstance(r,complex64),`type(r)` + assert_equal(r,e) + + r = func([2]) + assert isinstance(r,complex64),`type(r)` + assert_equal(r,e) + + r = func([2,3]) + assert isinstance(r,complex64),`type(r)` + assert_equal(r,e+complex64(3j)) + + self.assertRaises(TypeError,lambda :func([2,1,3])) + self.assertRaises(TypeError,lambda :func({})) + + def check_foo_complex16(self, level=1): + i = complex128(2) + e = complex128(3) + func = m.foocomplex16 + assert isinstance(i,complex128),`type(i)` + r = func(i) + assert isinstance(r,complex128),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + r = func(2) + assert isinstance(r,complex128),`type(r)` + assert_equal(r,e) + + r = func(2.0) + assert isinstance(r,complex128),`type(r)` + assert_equal(r,e) + + r = func(2.2) + assert isinstance(r,complex128),`type(r)` + assert_equal(r,e+complex128(0.2)) + + r = func(2+1j) + assert isinstance(r,complex128),`type(r)` + assert_equal(r,e+complex128(1j)) + + r = func([2]) + assert isinstance(r,complex128),`type(r)` + assert_equal(r,e) + + r = func([2,3]) + assert isinstance(r,complex128),`type(r)` + assert_equal(r,e+complex128(3j)) + + r = func(complex64(2.0)) + assert isinstance(r,complex128),`type(r)` + assert_equal(r,e) + + self.assertRaises(TypeError,lambda :func([2,1,3])) + self.assertRaises(TypeError,lambda :func({})) + + def check_foo_bool1(self, level=1): + i = bool8(True) + e = bool8(False) + func = m.foobool1 + assert isinstance(i,bool8),`type(i)` + r = func(i) + assert isinstance(r,bool8),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + for tv in [1,2,2.1,-1j,[0],True]: + r = func(tv) + assert isinstance(r,bool8),`type(r)` + assert_equal(r,e) + + for fv in [0,0.0,0j,False,(),{},[]]: + r = func(fv) + assert isinstance(r,bool8),`type(r)` + assert_equal(r,not e) + + def check_foo_bool2(self, level=1): + i = bool8(True) + e = bool8(False) + func = m.foobool2 + assert isinstance(i,bool8),`type(i)` + r = func(i) + assert isinstance(r,bool8),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + for tv in [1,2,2.1,-1j,[0],True]: + r = func(tv) + assert isinstance(r,bool8),`type(r)` + assert_equal(r,e) + + for fv in [0,0.0,0j,False,(),{},[]]: + r = func(fv) + assert isinstance(r,bool8),`type(r)` + assert_equal(r,not e) + + def check_foo_bool4(self, level=1): + i = bool8(True) + e = bool8(False) + func = m.foobool4 + assert isinstance(i,bool8),`type(i)` + r = func(i) + assert isinstance(r,bool8),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + for tv in [1,2,2.1,-1j,[0],True]: + r = func(tv) + assert isinstance(r,bool8),`type(r)` + assert_equal(r,e) + + for fv in [0,0.0,0j,False,(),{},[]]: + r = func(fv) + assert isinstance(r,bool8),`type(r)` + assert_equal(r,not e) + + def check_foo_bool8(self, level=1): + i = bool8(True) + e = bool8(False) + func = m.foobool8 + assert isinstance(i,bool8),`type(i)` + r = func(i) + assert isinstance(r,bool8),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + for tv in [1,2,2.1,-1j,[0],True]: + r = func(tv) + assert isinstance(r,bool8),`type(r)` + assert_equal(r,e) + + for fv in [0,0.0,0j,False,(),{},[]]: + r = func(fv) + assert isinstance(r,bool8),`type(r)` + assert_equal(r,not e) + + def check_foo_string1(self, level=1): + i = string0('a') + e = string0('1') + func = m.foostring1 + assert isinstance(i,string0),`type(i)` + r = func(i) + assert isinstance(r,string0),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + r = func('ab') + assert isinstance(r,string0),`type(r)` + assert_equal(r,e) + + r = func('') + assert isinstance(r,string0),`type(r)` + assert_equal(r,e) + + def check_foo_string5(self, level=1): + i = string0('abcde') + e = string0('12cde') + func = m.foostring5 + assert isinstance(i,string0),`type(i)` + r = func(i) + assert isinstance(r,string0),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + r = func('abc') + assert isinstance(r,string0),`type(r)` + assert_equal(r,'12c ') + + r = func('abcdefghi') + assert isinstance(r,string0),`type(r)` + assert_equal(r,'12cde') + + r = func([1]) + assert isinstance(r,string0),`type(r)` + assert_equal(r,'12] ') + + def _check_foo_string0(self, level=1): + i = string0('abcde') + e = string0('12cde') + func = m.foostringstar + r = func('abcde') + assert_equal(r,'1bcde') + r = func('') + assert_equal(r,'') + +if __name__ == "__main__": + NumpyTest().run() diff --git a/numpy/f2py/lib/tests/test_scalar_in_out.py b/numpy/f2py/lib/tests/test_scalar_in_out.py new file mode 100644 index 000000000..b73036848 --- /dev/null +++ b/numpy/f2py/lib/tests/test_scalar_in_out.py @@ -0,0 +1,529 @@ +#!/usr/bin/env python +""" +Tests for intent(in,out) arguments in Fortran subroutine's. + +----- +Permission to use, modify, and distribute this software is given under the +terms of the NumPy License. See http://scipy.org. + +NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. +Author: Pearu Peterson <pearu@cens.ioc.ee> +Created: Oct 2006 +----- +""" + +import os +import sys +from numpy.testing import * + +set_package_path() +from lib.main import build_extension, compile +restore_path() + +fortran_code = ''' + subroutine fooint1(a) + integer*1 a +!f2py intent(in,out) a + a = a + 1 + end + subroutine fooint2(a) + integer*2 a +!f2py intent(in,out) a + a = a + 1 + end + subroutine fooint4(a) + integer*4 a +!f2py intent(in,out) a + a = a + 1 + end + subroutine fooint8(a) + integer*8 a +!f2py intent(in,out) a + a = a + 1 + end + subroutine foofloat4(a) + real*4 a +!f2py intent(in,out) a + a = a + 1.0e0 + end + subroutine foofloat8(a) + real*8 a +!f2py intent(in,out) a + a = a + 1.0d0 + end + subroutine foocomplex8(a) + complex*8 a +!f2py intent(in,out) a + a = a + 1.0e0 + end + subroutine foocomplex16(a) + complex*16 a +!f2py intent(in,out) a + a = a + 1.0d0 + end + subroutine foobool1(a) + logical*1 a +!f2py intent(in,out) a + a = .not. a + end + subroutine foobool2(a) + logical*2 a +!f2py intent(in,out) a + a = .not. a + end + subroutine foobool4(a) + logical*4 a +!f2py intent(in,out) a + a = .not. a + end + subroutine foobool8(a) + logical*8 a +!f2py intent(in,out) a + a = .not. a + end + subroutine foostring1(a) + character*1 a +!f2py intent(in,out) a + a = "1" + end + subroutine foostring5(a) + character*5 a +!f2py intent(in,out) a + a(1:2) = "12" + end + subroutine foostringstar(a) + character*(*) a +!f2py intent(in,out) a + if (len(a).gt.0) then + a(1:1) = "1" + endif + end +''' + +m, = compile(fortran_code, 'test_scalar_in_out_ext', source_ext = '.f') + +from numpy import * + +class test_m(NumpyTestCase): + + def check_foo_integer1(self, level=1): + i = int8(2) + e = int8(3) + func = m.fooint1 + assert isinstance(i,int8),`type(i)` + r = func(i) + assert isinstance(r,int8),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + r = func(2) + assert isinstance(r,int8),`type(r)` + assert_equal(r,e) + + for intx in [int64,int16,int32]: + r = func(intx(2)) + assert isinstance(r,int8),`type(r)` + assert_equal(r,e) + + r = func(2.0) + assert isinstance(r,int8),`type(r)` + assert_equal(r,e) + + r = func(2.2) + assert isinstance(r,int8),`type(r)` + assert_equal(r,e) + + r = func([2]) + assert isinstance(r,int8),`type(r)` + assert_equal(r,e) + + self.assertRaises(TypeError,lambda :func(2.2j)) + self.assertRaises(TypeError,lambda :func([2,1])) + self.assertRaises(TypeError,lambda :func({})) + + def check_foo_integer2(self, level=1): + i = int16(2) + e = int16(3) + func = m.fooint2 + assert isinstance(i,int16),`type(i)` + r = func(i) + assert isinstance(r,int16),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + r = func(2) + assert isinstance(r,int16),`type(r)` + assert_equal(r,e) + + for intx in [int8,int64,int32]: + r = func(intx(2)) + assert isinstance(r,int16),`type(r)` + assert_equal(r,e) + + r = func(2.0) + assert isinstance(r,int16),`type(r)` + assert_equal(r,e) + + r = func(2.2) + assert isinstance(r,int16),`type(r)` + assert_equal(r,e) + + r = func([2]) + assert isinstance(r,int16),`type(r)` + assert_equal(r,e) + + self.assertRaises(TypeError,lambda :func(2.2j)) + self.assertRaises(TypeError,lambda :func([2,1])) + self.assertRaises(TypeError,lambda :func({})) + + def check_foo_integer4(self, level=1): + i = int32(2) + e = int32(3) + func = m.fooint4 + assert isinstance(i,int32),`type(i)` + r = func(i) + assert isinstance(r,int32),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + r = func(2) + assert isinstance(r,int32),`type(r)` + assert_equal(r,e) + + for intx in [int8,int16,int64]: + r = func(intx(2)) + assert isinstance(r,int32),`type(r)` + assert_equal(r,e) + + r = func(2.0) + assert isinstance(r,int32),`type(r)` + assert_equal(r,e) + + r = func(2.2) + assert isinstance(r,int32),`type(r)` + assert_equal(r,e) + + r = func([2]) + assert isinstance(r,int32),`type(r)` + assert_equal(r,e) + + self.assertRaises(TypeError,lambda :func(2.2j)) + self.assertRaises(TypeError,lambda :func([2,1])) + self.assertRaises(TypeError,lambda :func({})) + + def check_foo_integer8(self, level=1): + i = int64(2) + e = int64(3) + func = m.fooint8 + assert isinstance(i,int64),`type(i)` + r = func(i) + assert isinstance(r,int64),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + r = func(2) + assert isinstance(r,int64),`type(r)` + assert_equal(r,e) + + r = func(2.0) + assert isinstance(r,int64),`type(r)` + assert_equal(r,e) + + r = func(2.2) + assert isinstance(r,int64),`type(r)` + assert_equal(r,e) + + for intx in [int8,int16,int32]: + r = func(intx(2)) + assert isinstance(r,int64),`type(r)` + assert_equal(r,e) + + r = func([2]) + assert isinstance(r,int64),`type(r)` + assert_equal(r,e) + + self.assertRaises(TypeError,lambda :func(2.2j)) + self.assertRaises(TypeError,lambda :func([2,1])) + self.assertRaises(TypeError,lambda :func({})) + + def check_foo_real4(self, level=1): + i = float32(2) + e = float32(3) + func = m.foofloat4 + assert isinstance(i,float32),`type(i)` + r = func(i) + assert isinstance(r,float32),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + r = func(2) + assert isinstance(r,float32),`type(r)` + assert_equal(r,e) + + r = func(2.0) + assert isinstance(r,float32),`type(r)` + assert_equal(r,e) + + r = func(2.2) + assert isinstance(r,float32),`type(r)` + assert_equal(r,e+float32(0.2)) + + r = func(float64(2.0)) + assert isinstance(r,float32),`type(r)` + assert_equal(r,e) + + r = func([2]) + assert isinstance(r,float32),`type(r)` + assert_equal(r,e) + + self.assertRaises(TypeError,lambda :func(2.2j)) + self.assertRaises(TypeError,lambda :func([2,1])) + self.assertRaises(TypeError,lambda :func({})) + + def check_foo_real8(self, level=1): + i = float64(2) + e = float64(3) + func = m.foofloat8 + assert isinstance(i,float64),`type(i)` + r = func(i) + assert isinstance(r,float64),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + r = func(2) + assert isinstance(r,float64),`type(r)` + assert_equal(r,e) + + r = func(2.0) + assert isinstance(r,float64),`type(r)` + assert_equal(r,e) + + r = func(2.2) + assert isinstance(r,float64),`type(r)` + assert_equal(r,e+float64(0.2)) + + r = func(float32(2.0)) + assert isinstance(r,float64),`type(r)` + assert_equal(r,e) + + r = func([2]) + assert isinstance(r,float64),`type(r)` + assert_equal(r,e) + + self.assertRaises(TypeError,lambda :func(2.2j)) + self.assertRaises(TypeError,lambda :func([2,1])) + self.assertRaises(TypeError,lambda :func({})) + + def check_foo_complex8(self, level=1): + i = complex64(2) + e = complex64(3) + func = m.foocomplex8 + assert isinstance(i,complex64),`type(i)` + r = func(i) + assert isinstance(r,complex64),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + r = func(2) + assert isinstance(r,complex64),`type(r)` + assert_equal(r,e) + + r = func(2.0) + assert isinstance(r,complex64),`type(r)` + assert_equal(r,e) + + r = func(2.2) + assert isinstance(r,complex64),`type(r)` + assert_equal(r,e+complex64(0.2)) + + r = func(2+1j) + assert isinstance(r,complex64),`type(r)` + assert_equal(r,e+complex64(1j)) + + r = func(complex128(2.0)) + assert isinstance(r,complex64),`type(r)` + assert_equal(r,e) + + r = func([2]) + assert isinstance(r,complex64),`type(r)` + assert_equal(r,e) + + r = func([2,3]) + assert isinstance(r,complex64),`type(r)` + assert_equal(r,e+complex64(3j)) + + self.assertRaises(TypeError,lambda :func([2,1,3])) + self.assertRaises(TypeError,lambda :func({})) + + def check_foo_complex16(self, level=1): + i = complex128(2) + e = complex128(3) + func = m.foocomplex16 + assert isinstance(i,complex128),`type(i)` + r = func(i) + assert isinstance(r,complex128),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + r = func(2) + assert isinstance(r,complex128),`type(r)` + assert_equal(r,e) + + r = func(2.0) + assert isinstance(r,complex128),`type(r)` + assert_equal(r,e) + + r = func(2.2) + assert isinstance(r,complex128),`type(r)` + assert_equal(r,e+complex128(0.2)) + + r = func(2+1j) + assert isinstance(r,complex128),`type(r)` + assert_equal(r,e+complex128(1j)) + + r = func([2]) + assert isinstance(r,complex128),`type(r)` + assert_equal(r,e) + + r = func([2,3]) + assert isinstance(r,complex128),`type(r)` + assert_equal(r,e+complex128(3j)) + + r = func(complex64(2.0)) + assert isinstance(r,complex128),`type(r)` + assert_equal(r,e) + + self.assertRaises(TypeError,lambda :func([2,1,3])) + self.assertRaises(TypeError,lambda :func({})) + + def check_foo_bool1(self, level=1): + i = bool8(True) + e = bool8(False) + func = m.foobool1 + assert isinstance(i,bool8),`type(i)` + r = func(i) + assert isinstance(r,bool8),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + for tv in [1,2,2.1,-1j,[0],True]: + r = func(tv) + assert isinstance(r,bool8),`type(r)` + assert_equal(r,e) + + for fv in [0,0.0,0j,False,(),{},[]]: + r = func(fv) + assert isinstance(r,bool8),`type(r)` + assert_equal(r,not e) + + def check_foo_bool2(self, level=1): + i = bool8(True) + e = bool8(False) + func = m.foobool2 + assert isinstance(i,bool8),`type(i)` + r = func(i) + assert isinstance(r,bool8),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + for tv in [1,2,2.1,-1j,[0],True]: + r = func(tv) + assert isinstance(r,bool8),`type(r)` + assert_equal(r,e) + + for fv in [0,0.0,0j,False,(),{},[]]: + r = func(fv) + assert isinstance(r,bool8),`type(r)` + assert_equal(r,not e) + + def check_foo_bool4(self, level=1): + i = bool8(True) + e = bool8(False) + func = m.foobool4 + assert isinstance(i,bool8),`type(i)` + r = func(i) + assert isinstance(r,bool8),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + for tv in [1,2,2.1,-1j,[0],True]: + r = func(tv) + assert isinstance(r,bool8),`type(r)` + assert_equal(r,e) + + for fv in [0,0.0,0j,False,(),{},[]]: + r = func(fv) + assert isinstance(r,bool8),`type(r)` + assert_equal(r,not e) + + def check_foo_bool8(self, level=1): + i = bool8(True) + e = bool8(False) + func = m.foobool8 + assert isinstance(i,bool8),`type(i)` + r = func(i) + assert isinstance(r,bool8),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + for tv in [1,2,2.1,-1j,[0],True]: + r = func(tv) + assert isinstance(r,bool8),`type(r)` + assert_equal(r,e) + + for fv in [0,0.0,0j,False,(),{},[]]: + r = func(fv) + assert isinstance(r,bool8),`type(r)` + assert_equal(r,not e) + + def check_foo_string1(self, level=1): + i = string0('a') + e = string0('1') + func = m.foostring1 + assert isinstance(i,string0),`type(i)` + r = func(i) + assert isinstance(r,string0),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + r = func('ab') + assert isinstance(r,string0),`type(r)` + assert_equal(r,e) + + r = func('') + assert isinstance(r,string0),`type(r)` + assert_equal(r,e) + + def check_foo_string5(self, level=1): + i = string0('abcde') + e = string0('12cde') + func = m.foostring5 + assert isinstance(i,string0),`type(i)` + r = func(i) + assert isinstance(r,string0),`type(r)` + assert i is not r,`id(i),id(r)` + assert_equal(r,e) + + r = func('abc') + assert isinstance(r,string0),`type(r)` + assert_equal(r,'12c ') + + r = func('abcdefghi') + assert isinstance(r,string0),`type(r)` + assert_equal(r,'12cde') + + r = func([1]) + assert isinstance(r,string0),`type(r)` + assert_equal(r,'12] ') + + def check_foo_string0(self, level=1): + i = string0('abcde') + e = string0('12cde') + func = m.foostringstar + r = func('abcde') + assert_equal(r,'1bcde') + r = func('') + assert_equal(r,'') + +if __name__ == "__main__": + NumpyTest().run() diff --git a/numpy/f2py/lib/wrapper_base.py b/numpy/f2py/lib/wrapper_base.py new file mode 100644 index 000000000..3164e817f --- /dev/null +++ b/numpy/f2py/lib/wrapper_base.py @@ -0,0 +1,178 @@ +import os +import sys +import re + +__all__ = ['WrapperBase','WrapperCPPMacro','WrapperCCode'] + +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_'): + try: + return self.generate_pyobj_to_ctype_c(name[9:]) + except NotImplementedError: + pass + elif name.startswith('pyobj_from_'): + try: + return self.generate_pyobj_from_ctype_c(name[11:]) + except NotImplementedError: + pass + 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 resolve_dependencies(self, parent, body): + assert isinstance(body, str),type(body) + for d in self.get_dependencies(body): + if d.endswith('.cpp'): + WrapperCPPMacro(parent, d[:-4]) + elif d.endswith('.c'): + WrapperCCode(parent, d[:-2]) + else: + self.warning('Unknown dependence: %r.' % (d)) + return + + 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' + realname_lower = realname.lower() + parent = getattr(self,'parent',None) + if hasattr(self, realname): + attr = getattr(self, realname) + elif hasattr(self, realname_lower): + attr = getattr(self, realname_lower).upper() + elif hasattr(parent, realname): + attr = getattr(parent, realname) + elif hasattr(parent, realname_lower): + attr = getattr(parent, realname_lower).upper() + 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 + + def apply_templates(self, child): + for n in self.list_names: + l = getattr(self,n + '_list') + c = child.apply_attributes(getattr(child, n+'_template','')) + if c: + l.append(c) + return + +class WrapperCPPMacro(WrapperBase): + """ + CPP macros + """ + def __init__(self, parent, name): + WrapperBase.__init__(self) + defined = parent.defined_cpp_code + if name in defined: + return + defined.append(name) + + body = self.get_resource_content(name,'.cpp') + if body is None: + self.warning('Failed to get CPP macro %r content.' % (name)) + return + self.resolve_dependencies(parent, body) + parent.header_list.append(body) + return + +class WrapperCCode(WrapperBase): + """ + C code + """ + def __init__(self, parent, name): + WrapperBase.__init__(self) + defined = parent.defined_c_code + if name in defined: + return + defined.append(name) + + body = self.get_resource_content(name,'.c') + if body is None: + self.warning('Failed to get C code %r content.' % (name)) + return + if isinstance(body, dict): + for k,v in body.items(): + self.resolve_dependencies(parent, v) + for k,v in body.items(): + l = getattr(parent,k+'_list') + l.append(v) + else: + self.resolve_dependencies(parent, body) + parent.c_code_list.append(body) + return + + def generate_pyobj_to_ctype_c(self, ctype): + from generate_pyobj_tofrom_funcs import pyobj_to_npy_scalar, pyobj_to_f2py_string + if ctype.startswith('npy_'): + return pyobj_to_npy_scalar(ctype) + elif ctype.startswith('f2py_string'): + return pyobj_to_f2py_string(ctype) + raise NotImplementedError,`ctype` + + def generate_pyobj_from_ctype_c(self, ctype): + from generate_pyobj_tofrom_funcs import pyobj_from_npy_scalar + if ctype.startswith('npy_'): + return pyobj_from_npy_scalar(ctype) + raise NotImplementedError,`ctype` |