diff --git a/README.md b/README.md index df5a3fd..d0969c7 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,10 @@ Dependencies Installing IRPF90 ----------------- +``pip install irpf90`` + +or + ``${IRPF90_HOME}`` is the location of your irpf90 directory:: ``` bash diff --git a/example/Makefile b/example/Makefile index 437a0ad..c026e2a 100644 --- a/example/Makefile +++ b/example/Makefile @@ -1,13 +1,69 @@ -IRPF90 = python ../src/irpf90.py -I input -a -d -j -FC = ifort -FCFLAGS= -O2 -NINJA = ninja -j 1 -v +IRPF90= irpf90 +IRPF90FLAGS= -I ./ -I input/ +BUILD_SYSTEM= make -SRC= -OBJ= -LIB= +.EXPORT_ALL_VARIABLES: -include irpf90.make +AR = ar +CC = gcc +CFLAGS = -O2 +CXX = g++ +CXXFLAGS = -O2 +FC = gfortran +FCFLAGS = -O2 +LIB = +RANLIB = ranlib -irpf90.make: $(wildcard *.irp.f) - $(IRPF90) +OBJ = +SRC = + +# Dark magic below modify with caution! +# "You are Not Expected to Understand This" +# . +# /^\ . +# /\ "V", +# /__\ I O o +# //..\\ I . +# \].`[/ I +# /l\/j\ (] . O +# /. ~~ ,\/I . +# \\L__j^\/I o +# \/--v} I o . +# | | I _________ +# | | I c(` ')o +# | l I \. ,/ +# _/j L l\_! _//^---^\\_ + + +ifeq ($(BUILD_SYSTEM),ninja) + BUILD_FILE=IRPF90_temp/build.ninja + IRPF90FLAGS += -j +else ifeq ($(BUILD_SYSTEM),make) + BUILD_FILE=IRPF90_temp/build.make + BUILD_SYSTEM += -j +else +DUMMY: + $(error 'Wrong BUILD_SYSTEM: $(BUILD_SYSTEM)') +endif + +define run_and_touch + $(BUILD_SYSTEM) -C $(dir $(1) ) -f $(notdir $(1) ) $(addprefix $(CURDIR)/, $(2)) && touch $(2) +endef + +EXE := $(shell egrep -r '^\s*program' *.irp.f | awk '{print $$2}') + +.PHONY: all + +all: $(BUILD_FILE) + $(call run_and_touch, $<, $(EXE)) + +.NOTPARALLEL: $(EXE) +$(EXE): $(BUILD_FILE) + $(call run_and_touch, $<, $(EXE)) +$(BUILD_FILE): $(shell find . -maxdepth 2 -path ./IRPF90_temp -prune -o -name '*.irp.f' -print) + $(IRPF90) $(IRPF90FLAGS) + +clean: + rm -f -- $(BUILD_FILE) $(EXE) $(shell find IRPF90_temp -type f \( -name "*.o" -o -name "*.mod" -name "*.a" \) -delete;) +veryclean: clean + rm -rf IRPF90_temp/ IRPF90_man/ irpf90_entities dist tags diff --git a/example/irp_example1.irp.f b/example/irp_example1.irp.f index 9569645..82df790 100644 --- a/example/irp_example1.irp.f +++ b/example/irp_example1.irp.f @@ -1,12 +1,8 @@ program irp_example1 -! integer :: x(W) BEGIN_SHELL [ /bin/bash ] echo print *, \'Compiled by `whoami` on `date`\' echo print *, \'$FC $FCFLAGS\' echo print *, \'$IRPF90\' END_SHELL print *, 't = ', t - - print *, 'v=', v -! print *, u2 end diff --git a/example/uvwt.irp.f b/example/uvwt.irp.f index c5fd5b8..082f229 100644 --- a/example/uvwt.irp.f +++ b/example/uvwt.irp.f @@ -1,4 +1,4 @@ -BEGIN_PROVIDER [ integer, t ] +BEGIN_PROVIDER [integer, t ] t = u1+v+4 END_PROVIDER @@ -7,6 +7,7 @@ BEGIN_PROVIDER [integer,w] END_PROVIDER BEGIN_PROVIDER [ integer, v ] + implicit none v = u2+w+2 END_PROVIDER @@ -18,6 +19,7 @@ END_PROVIDER BEGIN_PROVIDER [ integer, u2 ] integer :: fu u2 = fu(d3,d4) + !df END_PROVIDER integer function fu(x,y) diff --git a/pip/LICENSE.txt b/pip/LICENSE.txt new file mode 100644 index 0000000..63bb6f7 --- /dev/null +++ b/pip/LICENSE.txt @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/pip/MANIFEST.in b/pip/MANIFEST.in new file mode 100644 index 0000000..fdafccf --- /dev/null +++ b/pip/MANIFEST.in @@ -0,0 +1,2 @@ +include irpf90 README.md irpman irp_indent + diff --git a/src/cython_setup.py b/pip/irpf90 similarity index 68% rename from src/cython_setup.py rename to pip/irpf90 index 6bb2e85..bccc151 100755 --- a/src/cython_setup.py +++ b/pip/irpf90 @@ -24,29 +24,9 @@ # 31062 Toulouse Cedex 4 # scemama@irsamc.ups-tlse.fr -from distutils.core import setup -from distutils.extension import Extension -from Cython.Distutils import build_ext -import os - -to_remove = """cython_setup.py version.py command_line.py""".split() -ext_modules = [] - -files = os.listdir('.') -for file in to_remove: - files.remove(file) - -for file in files: - if file.endswith(".py"): - module = file.split('.')[0] - ext_modules += [ Extension(module,[file]) ] - -setup( - name = 'IRPF90 extensions', - cmdclass = {'build_ext': build_ext}, - ext_modules = ext_modules -) - - +def main(): + import irpf90_libs.irpf90 + irpf90_libs.irpf90.main() +main() diff --git a/src/locks.py b/pip/irpf90_indent old mode 100644 new mode 100755 similarity index 62% rename from src/locks.py rename to pip/irpf90_indent index 892d0cd..c9353e7 --- a/src/locks.py +++ b/pip/irpf90_indent @@ -24,35 +24,9 @@ # 31062 Toulouse Cedex 4 # scemama@irsamc.ups-tlse.fr +def main(): + import irpf90_libs.irpf90_indent + irpf90_libs.irpf90_indent.main() -from command_line import command_line +main() -from irpf90_t import * -from util import * -from variables import variables -FILENAME=irpdir+'irp_locks.irp.F90' - -def create(): - out = [] - l = variables.keys() - l.sort - for v in l: - var = variables[v] - out += var.locker - - out += [ -"subroutine irp_init_locks_%s()"%(irp_id), -" implicit none" ] - for v in l: - out += [ " call irp_lock_%s(.True.)"%v ] - out += [ " call irp_lock_%s(.False.)"%v ] - out += [ "end subroutine" ] - out = map(lambda x: "%s\n"%(x),out) - if not same_file(FILENAME,out): - file = open(FILENAME,'w') - file.writelines(out) - file.close() - -if __name__ == '__main__': - create() - diff --git a/pip/irpf90_libs b/pip/irpf90_libs new file mode 120000 index 0000000..5cd551c --- /dev/null +++ b/pip/irpf90_libs @@ -0,0 +1 @@ +../src \ No newline at end of file diff --git a/src/error.py b/pip/irpman old mode 100644 new mode 100755 similarity index 53% rename from src/error.py rename to pip/irpman index 811759c..9aedc6f --- a/src/error.py +++ b/pip/irpman @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/bin/bash # IRPF90 is a Fortran90 preprocessor written in Python for programming using # the Implicit Reference to Parameters (IRP) method. # Copyright (C) 2009 Anthony SCEMAMA @@ -24,43 +24,41 @@ # 31062 Toulouse Cedex 4 # scemama@irsamc.ups-tlse.fr +# Define auto-completion for bash -import sys -from irpf90_t import * -from command_line import command_line -do_warnings = command_line.do_warnings +function run () +{ +cat << EOF | exec python - $@ +import sys, os -###################################################################### -def fail(line,message): - print """ -Error: ------ -""" - print message, '\n' - if line is not None: - assert isinstance(line,Line) - print "file %s ; line %d :\n %s"%(line.filename,line.i,line.text) - sys.exit(1) +from irpf90_libs.irpf90_t import mandir +filename = sys.argv[1].lower()+".l" +if filename not in os.listdir(mandir): + print "%s does not exist"%(sys.argv[1]) + sys.exit(-1) +os.system("man ./"+mandir+sys.argv[1].lower()+".l") +EOF +} -###################################################################### -def warn(line,message): - if not command_line.do_warnings: - return - if line is not None: - assert isinstance(line,Line) - print """ -Warning: -------- -""" - print message, '\n' - print "file %s, line %d:\n %s"%(line.filename,line.i,line.text) - else: - print "Warning: %s"%(message) +case "$0" in + *irpman) + if [[ -z $1 ]] ; then + echo "To activate auto-completion in bash:" + echo "source " $0 + else + run $@ + fi + ;; + *) + _irpman_complete() + { + local cur + COMPREPLY=() + cur=${COMP_WORDS[COMP_CWORD]} + COMPREPLY=( $(compgen -W "`[[ -f tags ]] && cat tags | cut -d' ' -f 1`" -- "$cur" ) ) + } && complete -F _irpman_complete irpman + ;; -###################################################################### -if __name__ == '__main__': - line = Empty_line(3,"empty", "testfile") - fail(line, "Message") - +esac diff --git a/pip/setup.cfg b/pip/setup.cfg new file mode 100644 index 0000000..b88034e --- /dev/null +++ b/pip/setup.cfg @@ -0,0 +1,2 @@ +[metadata] +description-file = README.md diff --git a/pip/setup.py b/pip/setup.py new file mode 100644 index 0000000..034284e --- /dev/null +++ b/pip/setup.py @@ -0,0 +1,16 @@ +from distutils.core import setup + +setup( + name = 'irpf90', + packages = ['irpf90_libs'], # this must be the same as the name above + version = '1.6.9', + description = 'IRPF90 is a Fortran90 preprocessor written in Python for programming using the Implicit Reference to Parameters (IRP) method. It simplifies the development of large fortran codes in the field of scientific high performance computing.', + author = 'Anthony Scemama', + author_email = 'scemama@irsamc.ups-tlse.fr', + url = 'http://irpf90.ups-tlse.fr', # use the URL to the github repo + download_url = 'https://github.com/scemama/irpf90/archive/v1.6.9.tar.gz', # I'll explain this in a second + keywords = ['programming', 'fortran', 'IRP'], # arbitrary keywords + classifiers = [], + scripts = ["irpf90", "irpman", "irpf90_indent"], +) + diff --git a/src/.style.yapf b/src/.style.yapf new file mode 100644 index 0000000..e9aaba7 --- /dev/null +++ b/src/.style.yapf @@ -0,0 +1,3 @@ +[style] +based_on_style = pep8 +COLUMN_LIMIT = 100 diff --git a/src/Makefile b/src/Makefile index 366d8aa..41ae891 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,21 +1,7 @@ PYTHON=python PYVERSION=$(shell $(PYTHON) -c "import sys; print(sys.version[:3])") -HAS_CYTHON=$(shell bash -c "which cython &> /dev/null && echo 1 || echo 0") -ifneq ($(HAS_CYTHON),0) - -../bin/irpf90: irpf90.so - rm ../bin/irpf90 ; cd ../bin ; ln -s ../src/irpf90_python.exe irpf90 - -irpf90.so : $(wildcard *.py) irpf90.c - ./cython_setup.py build_ext --inplace - -irpf90.c: irpf90.py - cython --embed irpf90.py - -else ../bin/irpf90: irpf90_python.exe rm ../bin/irpf90 ; cd ../bin ; ln -s ../src/irpf90_python.exe irpf90 -endif clean: rm -f *.c *.so *.pyc *.pyo 2>/dev/null diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/build_file.py b/src/build_file.py new file mode 100644 index 0000000..2dcbd0f --- /dev/null +++ b/src/build_file.py @@ -0,0 +1,537 @@ +#!/usr/bin/env python +# IRPF90 is a Fortran90 preprocessor written in Python for programming using +# the Implicit Reference to Parameters (IRP) method. +# Copyright (C) 2009 Anthony SCEMAMA +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Anthony Scemama +# LCPQ - IRSAMC - CNRS +# Universite Paul Sabatier +# 118, route de Narbonne +# 31062 Toulouse Cedex 4 +# scemama@irsamc.ups-tlse.fr + +import os, sys +import irpf90_t +from command_line import command_line + +from os.path import basename + +irpdir = irpf90_t.irpdir +mandir = irpf90_t.mandir +irp_id = irpf90_t.irp_id + +cwd = os.getcwd() + +def dress(f, in_root=False): + #(str,bool) -> str + """ Transfoms the filename into $PWD/IRPF90_temp/f + + Note: + In root=True resurn $PWD/f + """ + + pwd = os.getcwd() + if in_root: + result = os.path.join(pwd, f) + else: + result = os.path.join(pwd, irpdir, f) + return os.path.normpath(result) + + +def create_build_touches(l_irp_m, ninja): + + irp_id = irpf90_t.irp_id + name = "irp_touches" + short_target_o = "%s.irp.o" % name + short_target_F90 = "%s.irp.F90" % name + target_o = dress(short_target_o) + target_F90 = dress(short_target_F90) + + list_of_modules_irp = ' '.join(l_irp_m) + + result_ninja = '\n'.join([ + "build {target_o}: compile_fortran_{irp_id} {target_F90} | {list_of_modules_irp}", + " short_in = {short_target_F90}", + " short_out = {short_target_o}", + "" + ]) + + result_make = '\n'.join([ + "{target_o}: {target_F90} | {list_of_modules_irp}", + '\t@printf "F: {short_target_F90} -> {short_target_o}\\n"', + "\t@$(FC) $(FCFLAGS) -c $^ -o $@", "" + ]) + + result = result_ninja if ninja else result_make + + return result.format(**locals()) + + +def create_build_archive(l_irp_o, l_usr_o_wo_main, l_ext_o, l_irp_sup_o, ninja=True): + # (List[str] * 6 ) -> str + """Create the build command for the irp_touches.o file and the irpf90.a library. + + - the touch file need all the irp_module. + - the archive file need all the object. + + """ + + irp_id = irpf90_t.irp_id + short_lib = "irpf90.a" + lib = dress(short_lib) + + list_of_object = ' '.join(l_irp_o + l_usr_o_wo_main + l_ext_o + l_irp_sup_o) + + result_ninja = '\n'.join([ + "build {lib}: archive_{irp_id} {list_of_object}", + " short_out = {short_lib}", + ""]) + + result_make = '\n'.join([ + "{lib}: {list_of_object}", + '\t@printf "Archive: {short_lib}\\n"', + "\t@$(AR) cr $@ $^", ""]) + + result = result_ninja if ninja else result_make + return result.format(**locals()) + + +def create_build_link(t, l_irp_m, l_usr_m, l_ext_m, ninja=True): + # (Module, List[str], List[str]) -> str + """ Create the build command who will link the .o file into the target executable + + To link we need the .o file corresponding to the target, and the ar lib. + """ + + irp_id = irpf90_t.irp_id + + filename = t.filename + progname = t.prog_name + + basename = os.path.basename(filename) + if basename != progname: + from util import logger + logger.info('program-name `{0}` != file-name `{1}` (using file-name for now...)'.format(progname,basename)) + + target = dress(filename, in_root=True) + short_target = filename + short_target_o = "%s.irp.o" % filename + + target_o = dress(short_target_o) + + list_of_module = ' '.join(l_irp_m + l_usr_m + l_ext_m) + irp_lib = dress("irpf90.a") + + result_ninja = '\n'.join([ + "build {target}: link_{irp_id} {target_o} {irp_lib} | {list_of_module}", + " short_out = {short_target}", + ""]) + + result_make = '\n'.join([ + "{target}:{target_o} {irp_lib} | {list_of_module}", + '\t@printf "Link: {short_target}\\n"', + "\t@$(FC) $^ $(LIB) -o $@", + ""]) + + result = result_ninja if ninja else result_make + + return result.format(**locals()) + + +def create_build_compile(t, l_module, l_ext_modfile=[], ninja=True): + # (Module, List[Module], List[str], bool) -> str + """Create the build command for the module t. + + - The module can produce a .MOD file + - The module can Need another .MOD file. + This .MOD file can be produced by: + 1) a file generated by IRP_F90 preprocessor. + 2) a file defined by the user but a .irp.f90 file. + 3) a file not handle at all by IRPF90. + + - The fortran90 file maybe created by the Python module need no dependency. + + """ + + irp_id = irpf90_t.irp_id + name = t.filename + + short_target = name + target = dress(name, in_root=True) + + short_target_o = "%s.irp.o" % name + short_target_F90 = "%s.irp.F90" % name + + target_o = dress(short_target_o) + target_F90 = dress(short_target_F90) + + # Here is the hack. We don't check MOD files, but the associated .o. + # MOD name are not part of the standart. + + needed_modules = [dress(x, in_root=True) for x in l_ext_modfile] + + # Expensive and stupid. We can create a dict to do the loockup only once + for m in t.needed_modules_usr: + # m is name + for x in l_module: + if m in x.gen_mod and x.filename != t.filename: + needed_modules.append("%s.irp.o" % x.filename) + + from util import uniquify + needed_modules = uniquify(needed_modules) + + needed_modules_irp = [ + "%s.irp.module.o" % (x.filename) for x in l_module if x.name in t.needed_modules_irp + ] + + if t.has_irp_module: + short_target_module_F90 = "%s.irp.module.F90" % name + short_target_module_o = "%s.irp.module.o" % name + + target_module_o = dress(short_target_module_o) + target_module_F90 = dress(short_target_module_F90) + needed_modules_irp += [target_module_o] + + list_of_modules = ' '.join(map(dress, needed_modules)) + list_of_modules_irp = ' '.join(map(dress, needed_modules_irp)) + + inline_include = True + if not inline_include: + #Wrong name, this not work! + #list_of_includes = ' '.join(map(lambda x: dress(x, in_root=True), t.includes)) + raise NotImplemented + else: + #The include have already by included + list_of_includes = ' ' + + l_build = [ + "build {target_o}: compile_fortran_{irp_id} {target_F90} | {list_of_includes} {list_of_modules} {list_of_modules_irp}", + " short_in = {short_target_F90}", + " short_out = {short_target}", + "" + ] + + l_build_make = [ + "{target_o}: {target_F90} | {list_of_includes} {list_of_modules} {list_of_modules_irp}", + '\t@printf "F: {short_target_F90} -> {short_target}\\n"', + "\t@$(FC) $(FCFLAGS) -c $^ -o $@", "" + ] + + # No need of module when compiling the irp_module. + if t.has_irp_module: + l_build += [ + "build {target_module_o}: compile_fortran_{irp_id} {target_module_F90} | {list_of_includes} {list_of_modules} ", + " short_in = {short_target_module_F90}", + " short_out = {short_target_module_o}", + "" + ] + + l_build_make += [ + "{target_module_o}: {target_module_F90} | {list_of_includes} {list_of_modules}", + '\t@printf "F: {short_target_module_F90} -> {short_target_module_o}\\n"', + "\t@$(FC) $(FCFLAGS) -c $^ -o $@", "" + ] + + l_cur = l_build if ninja else l_build_make + return '\n'.join(l_cur).format(**locals()) + + +def create_build_remaining(f,ninja): + """ + Create the build command for the remaining file f. f is a file name (str). + """ + + irp_id = irpf90_t.irp_id + + t, extension = f.rsplit('.', 1) + t1 = dress(t, in_root=True) + t2 = dress(t, in_root=False) + target_i = f + target_o = "%s.o" % t + + if not target_o.startswith(os.path.join(cwd, irpdir)): + target_o = target_o.replace(cwd, os.path.join(cwd, irpdir)) + + short_target_o = os.path.split(target_o)[1] + short_target_i = os.path.split(target_i)[1] + + if extension.lower() in ['f', 'f90']: + result = ["build {target_o}: compile_fortran_{irp_id} {target_i}"] + elif extension.lower() in ['c']: + result = ["build {target_o}: compile_c_{irp_id} {target_i}"] + elif extension.lower() in ['cxx', 'cpp']: + result = ["build {target_o}: compile_cxx_{irp_id} {target_i}"] + + result += [" short_in = {short_target_i}", " short_out = {short_target_o}", ""] + return '\n'.join(result).format(**locals()) + + +def create_makefile(d_flags,d_var,irpf90_flags,ninja=True): + + result = ["IRPF90= irpf90", + "IRPF90FLAGS= %s" % irpf90_flags, + "BUILD_SYSTEM= %s" % ('ninja' if ninja else 'make'), + ""] + + # Export all the env variable used by irpf90 + result += ['.EXPORT_ALL_VARIABLES:', + '', + '\n'.join("{0} = {1}".format(k, v) for k, v in sorted(d_flags.iteritems())), + '', + '\n'.join("{0} = {1}".format(k, ' '.join(v)) for k, v in sorted(d_var.iteritems())), + ''] + + result += [ r'# Dark magic below modify with caution!', + r'# "You are Not Expected to Understand This"', + r"# .", + r"# /^\ .", + r'# /\ "V",', + r"# /__\ I O o", + r"# //..\\ I .", + r"# \].`[/ I", + r"# /l\/j\ (] . O", + r"# /. ~~ ,\/I .", + r"# \\L__j^\/I o", + r"# \/--v} I o .", + r"# | | I _________", + r"# | | I c(` ')o", + r"# | l I \. ,/", + r"# _/j L l\_! _//^---^\\_", + r""] + + result += ["", + "ifeq ($(BUILD_SYSTEM),ninja)", + "\tBUILD_FILE=IRPF90_temp/build.ninja", + "\tIRPF90FLAGS += -j", + "else ifeq ($(BUILD_SYSTEM),make)", + "\tBUILD_FILE=IRPF90_temp/build.make", + "\tBUILD_SYSTEM += -j", + "else", + "DUMMY:", + "\t$(error 'Wrong BUILD_SYSTEM: $(BUILD_SYSTEM)')", + "endif"] + + result += ["", + "define run_and_touch", + " $(BUILD_SYSTEM) -C $(dir $(1) ) -f $(notdir $(1) ) $(addprefix $(CURDIR)/, $(2)) && touch $(2)", + "endef", + "", + "EXE := $(shell egrep -ri '^\s*program' *.irp.f | cut -d'.' -f1)", + "", + ".PHONY: all", + "", + "all: $(BUILD_FILE)", + "\t$(call run_and_touch, $<, $(EXE))", + "", + ".NOTPARALLEL: $(EXE)", + "$(EXE): $(BUILD_FILE)", + "\t$(call run_and_touch, $<, $(EXE))", + + "$(BUILD_FILE): $(shell find . -maxdepth 2 -path ./IRPF90_temp -prune -o -name '*.irp.f' -print)", + "\t$(IRPF90) $(IRPF90FLAGS)", + "", + "clean:", + '\trm -f -- $(BUILD_FILE) $(EXE)' + '\t$(shell find IRPF90_temp -type f \\( -name "*.o" -o -name "*.mod" -name "*.a" \\) -delete;)', + "veryclean: clean", + "\trm -rf IRPF90_temp/ IRPF90_man/ irpf90_entities dist tags"] + + import util + data = '%s\n' % '\n'.join(result) + util.lazy_write_file('Makefile',data,conservative=True) + +def create_make_all_clean(l_main): + # + '''Create the ALL and CLEAN target of Makefile + + Note: Portability doesn't mater. -delete is maybe not posix + but -exec rm {} + is far more ugly! + + ''' + + l_executable =' '.join(dress( t.filename, in_root=True) for t in l_main) + + output = [".PHONY : all", + "all: {l_executable}", + "", + ".PHONY: clean", + "clean:", + '\tfind . -type f \( -name "*.o" -o -name "*.mod" \) -delete; rm -f {l_executable} --' + ""] + + return [ '\n'.join(output).format(**locals())] + +def create_var_and_rule(d_flags, ninja): + + output = ['\n'.join("{0} = {1}".format(k, v) for k, v in d_flags.iteritems())] + + if ninja: + output += ["builddir = %s" % os.path.join(cwd, irpdir)] + + # Rules + t = [ + "rule compile_fortran_{irp_id}", + " command = $FC $FCFLAGS -c $in -o $out", + " description = F : $short_in -> $short_out", + "", + "rule compile_c_{irp_id}", + " command = $CC $CFLAGS -c $in -o $out", + " description = C : $short_in -> $short_out", + "", + "rule compile_cxx_{irp_id}", + " command = $CXX $CXXFLAGS -c $in -o $out", + " description = C++ : $short_in -> $short_out", + "", + "rule archive_{irp_id}", + " command = $AR cr $out $in", + " description = Archive: $short_out", + "", + "rule link_{irp_id}", + " command = $FC $FCFLAGS $in $LIB -o $out", + " description = Link: $short_out", + "" + ] + + output += ['\n'.join(t).format(irp_id=irpf90_t.irp_id, **d_flags)] + + return output + + +# Environment variables + +d_default = { + "FC": "gfortran", + "FCFLAGS": "-O2", + "AR": "ar", + "RANLIB": " ranlib", + "CC": "gcc", + "CFLAGS": "-O2", + "CXX": "g++", + "CXXFLAGS": "-O2", + "LIB": ""} + +d_flags = dict() +for k, v in d_default.iteritems(): + d_flags[k] = os.environ[k] if k in os.environ else v + +include_dir = ' ' + ' '.join(["-I %s" % (i) for i in command_line.include_dir]) + +d_var = dict() +for k in ['SRC', 'OBJ']: + d_var[k] = os.environ[k].split() if k in os.environ else [] + + +def create_generalmakefile(ninja): + create_makefile(d_flags,d_var, include_dir,ninja) + +def run(d_module, ninja): + #(Dict[str,Module],bool) -> str + """Wrote the ninja file needed to compile the program + + Note: + - FC,AR,CC,CXX,LIB, FCFLAGS, CFLAGS, CXXFLAGS are compiler enviroment read + - SRC,OBJ: Are the not irp.f file defined by the user + """ + + # Add required flags + + for k in ['FCFLAGS', 'CFLAGS', 'CXXFLAGS']: + d_flags[k] += include_dir + + # Each python module can produce one or two .F90/.o file and maybe one .MOD file: + # + # No usr defined module and no IRP-F90 provider declaration: + # - One .F90 - No .MOD file + # Usr defined module AND no IRP-F90 provider: + # - One .F90 - One. MOD file + # No usr define module AND IRP-F90 provider: + # - Two .F90 - One. MOD file + + # Each python module can depend of different module: + # - IRP created one + # - usr declared + # - external (don't know by IRP) + + # Each python module can need 3 type of .MOD file + l_mod = list(d_module.values()) + + # Modules that are not targets + l_mod_no_main = filter(lambda m: not m.is_main, l_mod) + l_mod_main = filter(lambda m: m.is_main, l_mod) + + # List irp supl object/source files + l_irp_sup_o = ["irp_touches.irp.o"] + l_irp_sup_s = ["irp_touches.irp.F90"] + + if command_line.do_assert: + l_irp_sup_o += ["irp_stack.irp.o"] + l_irp_sup_s += ["irp_stack.irp.F90"] + + if command_line.do_openmp: + l_irp_sup_o += ["irp_locks.irp.o"] + l_irp_sup_s += ["irp_locks.irp.F90"] + + if command_line.do_profile: + l_irp_sup_o += ["irp_profile.irp.o", "irp_rdtsc.o"] + l_irp_sup_s += ["irp_profile.irp.F90", "irp_rdtsc.c"] + + l_irp_sup_o = map(dress, l_irp_sup_o) + l_irp_sup_s = map(dress, l_irp_sup_s) + + # List of extrernal object/source file + l_ext_o = l_ext_m = map(lambda x: dress(x, in_root=True), d_var['OBJ']) + l_ext_s = map(lambda x: dress(x, in_root=True), d_var['SRC']) + + # List of object create by the IRP-F90 + l_irp_o = l_irp_m = map(dress, + ["%s.irp.module.o" % (m.filename) for m in l_mod if m.has_irp_module]) + + # List of object create by the USR. Maybe he have a module, maybe not. + l_usr_o_wo_main = map(dress, ["%s.irp.o" % (m.filename) for m in l_mod_no_main]) + l_usr_m = map(dress, ["%s.irp.o" % (m.filename) for m in l_mod if m.needed_modules_usr]) + + #-=~=~= + # O U T P U T + #~=~=~= + + output = create_var_and_rule(d_flags, ninja) + if not ninja: + output += create_make_all_clean(l_mod_main) + + # Create all the .irp.F90 -> .o + for m in l_mod: + output.append(create_build_compile(m, l_mod, l_ext_m, ninja)) + + output.append(create_build_touches(l_irp_m,ninja)) + # All the objects. Kind of, only need usr without main for the static library + output.append(create_build_archive(l_irp_o, l_usr_o_wo_main, l_ext_o, l_irp_sup_o, ninja)) + + for i in l_mod_main: + # All the mod (overshoot) + output.append(create_build_link(i, l_irp_m, l_usr_m, l_ext_m, ninja)) + + # Remaining files + for i in l_irp_sup_s[1:]+l_ext_s: + output.append(create_build_remaining(i, ninja)) + + filename = os.path.join(irpdir, "build.ninja" if ninja else "build.make") + + data = '%s\n' % '\n\n'.join(output) + import util + util.lazy_write_file(filename,data,touch=True) + + return diff --git a/src/checkpoint.py b/src/checkpoint.py deleted file mode 100644 index 9a8358a..0000000 --- a/src/checkpoint.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env python -# IRPF90 is a Fortran90 preprocessor written in Python for programming using -# the Implicit Reference to Parameters (IRP) method. -# Copyright (C) 2009 Anthony SCEMAMA -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Anthony Scemama -# LCPQ - IRSAMC - CNRS -# Universite Paul Sabatier -# 118, route de Narbonne -# 31062 Toulouse Cedex 4 -# scemama@irsamc.ups-tlse.fr - - -from irpf90_t import * -from util import * -from variables import variables -from modules import modules - -CHECKPOINT_UNIT_NUMBER=63 - -FILENAME=irpdir+'irp_checkpoint.irp.F90' - -def create(): - out_write = [ "subroutine irp_checkpoint_write" ] - l = variables.keys() - l.sort - main_modules = filter(lambda x: modules[x].is_main, modules) - for m in filter(lambda x: not modules[x].is_main, modules): - out_write += [ " use %s"%(modules[m].name) ] - out_write += [ " implicit none" ] - out_write += [ " integer, parameter :: iunit = %d"%(CHECKPOINT_UNIT_NUMBER) ] - out_write += [ " open(unit=%d,file='irp_checkpoint.dat',status='UNKNOWN',action='WRITE')"%(CHECKPOINT_UNIT_NUMBER) ] - for v in l: - var = variables[v] - if var.is_main: - out_write += [ " if (%s_is_built) then"%(v) ] - for w in [v]+var.others: - d = variables[w].dim - if d == []: - out_write += [ " write(iunit,*) '%s', 0"%(w) ] - else: - out_write += [ " write(iunit, *) '%s', %d"%(w, len(d)), - " write(iunit, *) %s"%(",".join( - [ "size(%s,%d)"%(w,i+1) for i in range(len(d)) ] )) - ] - out_write += [ " write(iunit,*) %s"%(w) ] - out_write += [ " endif" ] - out_write += [ " close(%d)"%(CHECKPOINT_UNIT_NUMBER) ] - out_write += [ "end" ] - - out = '\n'.join(out_write) - if not same_file(FILENAME,out): - file = open(FILENAME,'w') - file.writelines(out) - file.close() - -if __name__ == '__main__': - create() - diff --git a/src/codelet.py b/src/codelet.py index dbdc57e..d5e6f25 100644 --- a/src/codelet.py +++ b/src/codelet.py @@ -63,8 +63,7 @@ end precondition = "" else: precondition = "PROVIDE "+precondition - file = open(filename,'w') - file.write(template%locals()) - file.close() - + + from util import lazy_write_file + lazy_write_file(filename,template%locals()) diff --git a/src/command_line.py b/src/command_line.py index d6dc093..e8e15bc 100644 --- a/src/command_line.py +++ b/src/command_line.py @@ -24,6 +24,11 @@ # 31062 Toulouse Cedex 4 # scemama@irsamc.ups-tlse.fr +try: + import irpy +except: + import lib_irpy as irpy + import getopt, sys from version import version @@ -52,6 +57,7 @@ options['t'] = [ 'touch' , 'Display which entities are touched when touch options['v'] = [ 'version' , 'Prints version of irpf90', 0 ] options['w'] = [ 'warnings' , 'Activate Warnings', 0 ] options['z'] = [ 'openmp' , 'Activate for OpenMP code', 0 ] +options['G'] = [ 'graph' , 'Print the dependecy-graph of the entities (dots format)', 0 ] class CommandLine(object): @@ -61,17 +67,16 @@ class CommandLine(object): self.argv = list(sys.argv) self.executable_name = self.argv[0] + @irpy.lazy_property def defined(self): - if '_defined' not in self.__dict__: - self._defined = [] - for o,a in self.opts: - if o in [ "-D", '--'+options['D'][0] ]: - self._defined.append(a) - return self._defined - defined = property(fget=defined) + return [ a for o,a in self.opts if o in [ "-D", '--'+options['D'][0] ] ] + @irpy.lazy_property + def graph(self): + return next((a.split() for o,a in self.opts if o in ["-G", '--'+options['G'][0] ]),[]) + + @irpy.lazy_property def include_dir(self): - if '_include_dir' not in self.__dict__: self._include_dir = [] for o,a in self.opts: if o in [ "-I", '--'+options['I'][0] ]: @@ -80,41 +85,32 @@ class CommandLine(object): if a[-1] != '/': a = a+'/' self._include_dir.append(a) - return self._include_dir - include_dir = property(fget=include_dir) - + return self._include_dir + + @irpy.lazy_property def inline(self): - if '_inline' not in self.__dict__: - self._inline = "" - for o,a in self.opts: - if o in [ "-n", '--'+options['n'][0] ]: - self._inline = a - break - return self._inline - inline = property(fget=inline) + return next( (a for o,a in self.opts if o in [ "-n", '--'+options['n'][0] ]),'') + @irpy.lazy_property def substituted(self): - if '_substituted' not in self.__dict__: self._substituted = {} for o,a in self.opts: if o in [ "-s", '--'+options['s'][0] ]: k, v = a.split(':') v_re = re.compile(r"(\W)(%s)(\W.*$|$)"%k.strip()) self._substituted[k] = [v, v_re] - return self._substituted - substituted = property(fget=substituted) + return self._substituted + @irpy.lazy_property def codelet(self): - if '_codelet' not in self.__dict__: - self._codelet = [] for o,a in self.opts: if o in [ "-c", '--'+options['c'][0] ]: buffer = a.split(':') filename = 'codelet_'+buffer[0]+'.irp.f' if len(buffer) == 2: - self._codelet = [buffer[0], int(buffer[1]), None, filename] + return [buffer[0], int(buffer[1]), None, filename] elif len(buffer) == 3: - self._codelet = [buffer[0], int(buffer[2]), buffer[1], filename] + return [buffer[0], int(buffer[2]), buffer[1], filename] else: print """ Error in codelet definition. Use: @@ -123,80 +119,38 @@ or --codelet=provider:precondition:NMAX """ sys.exit(1) - return self._codelet - codelet = property(fget=codelet) - def preprocessed(self): - if '_preprocessed' not in self.__dict__: - self._preprocessed = [] - for o,a in self.opts: - if o in [ "-p", '--'+options['p'][0] ]: - self._preprocessed.append(a) - return self._preprocessed - preprocessed = property(fget=preprocessed) + @irpy.lazy_property + def preprocessed(self): + return [a for o,a in self.ops if o in [ "-p", '--'+options['p'][0] ] ] + @irpy.lazy_property def touched(self): - if '_touched' not in self.__dict__: - self._touched = [] - for o,a in self.opts: - if o in [ "-t", '--'+options['t'][0] ]: - self._touched.append(a.lower()) - return self._touched - touched = property(fget=touched) + return [a for o,a in self.ops if o in [ "-t", '--'+options['t'][0] ] ] + @irpy.lazy_property def align(self): - if '_align' not in self.__dict__: - self._align = '1' - for o,a in self.opts: - if o in [ "-l", '--'+options['l'][0] ]: - self._align = a - return self._align - align = property(fget=align) + return next( (a for o,a in self.opts if o in [ "-l", '--'+options['l'][0] ]),'1') + @irpy.lazy_property def coarray(self): - if '_coarray' not in self.__dict__: - self._coarray = False - for o,a in self.opts: - if o in [ "-C", '--'+options['C'][0] ]: - self._coarray = True - return self._coarray - coarray = property(fget=coarray) + return any(o for o,a in self.opts if o in [ "-C", '--'+options['C'][0] ]) + @irpy.lazy_property def warnings(self): - if '_warnings' not in self.__dict__: - self._warnings= False - for o,a in self.opts: - if o in [ "-w", '--'+options['w'][0] ]: - self._warnings= True - return self._warnings - do_warnings = property(fget=warnings) + return any(o for o,a in self.opts if o in [ "-W", '--'+options['W'][0] ]) + @irpy.lazy_property def openmp(self): - if '_openmp' not in self.__dict__: - self._openmp = False - for o,a in self.opts: - if o in [ "-z", '--'+options['z'][0] ]: - self._openmp = True - return self._openmp - do_openmp = property(fget=openmp) + return any(o for o,a in self.opts if o in [ "-z", '--'+options['z'][0] ]) + @irpy.lazy_property def ninja(self): - if '_ninja' not in self.__dict__: - self._ninja = False - for o,a in self.opts: - if o in [ "-j", '--'+options['j'][0] ]: - self._ninja = True - return self._ninja - do_ninja = property(fget=ninja) + return any(o for o,a in self.opts if o in [ "-j", '--'+options['j'][0] ]) + @irpy.lazy_property def directives(self): - if '_directives' not in self.__dict__: - self._directives = True - for o,a in self.opts: - if o in [ "-r", '--'+options['r'][0] ]: - self._directives = False - return self._directives - directives = property(fget=directives) + return not(any(o for o,a in self.opts if o in [ "-r", '--'+options['r'][0] ])) def usage(self): t = """ @@ -251,17 +205,10 @@ do_$LONG = property(fget=do_$LONG) for short in options: long = options[short][0] exec t.replace("$LONG",long).replace("$SHORT",short) #in locals() - + + @irpy.lazy_property def do_run(self): - if '_do_run' not in self.__dict__: - self._do_run = not ( \ - self.do_version or \ - self.do_help or \ - self.do_preprocess or \ - self.do_touch or \ - self.do_init ) - return self._do_run - do_run = property(fget=do_run) + return not(any( (self.do_version, self.do_help, self.do_preprocess, self.do_touch, self.do_init))) command_line = CommandLine() diff --git a/src/create_man.py b/src/create_man.py index 63d6512..5d51efc 100644 --- a/src/create_man.py +++ b/src/create_man.py @@ -24,166 +24,171 @@ # 31062 Toulouse Cedex 4 # scemama@irsamc.ups-tlse.fr +from entity import Entity +from routine import Routine +from irpf90_t import mandir +from util import parmap, build_dim,lazy_write_file +import os -from variable import Variable -from variables import variables -from subroutine import Sub -from subroutines import subroutines -from irpf90_t import * -from util import * +def do_print_short(entity): + assert type(entity) == Entity + str_ = "{0:<35} : {1:<30} :: {2:<25} {3}".format(entity.prototype.filename[0], + entity.type, + entity.name, + build_dim(entity.dim)) # yapf: disable + return [str_] -def do_print_short(file,var): - assert type(var) == Variable - print >>file, "%s : %s :: %s %s"%( \ - var.line.filename[0].ljust(35), - var.type.ljust(30), - var.name.ljust(25), - build_dim(var.dim) ) - ###################################################################### -def process_doc(file,line): - assert type(line) == str - line = line.strip() - if line == "": - line = ".br" - print >>file, line +def process_doc(line): + assert type(line) == str + line = line.strip() + return [line if line else ".br"] + ###################################################################### -def process_deps(file,l): - assert type(l) == list - for v in l: - print >>file, "%s\n.br"%(v,) +def process_deps(l): + assert isinstance(l, (list, set)) + return ['%s\n.br' % v for v in sorted(l)] + ###################################################################### -def process_types(file,var): - assert type(var) == Variable - vars = [var.name] + var.others - for var in vars: - name = var - var = variables[var] - Type = var.type - dim = build_dim(var.dim) - print >>file, "%s\t:: %s\t%s"%(Type,name,dim) +def process_types(entity_input, d_entity): + assert type(entity_input) == Entity + + l_name = [entity_input.name] + entity_input.others_entity_name + l_entity = [d_entity[name] for name in l_name] + + l = [ "{0}\t:: {1}\t{2}".format(entity.type, name, build_dim(entity.dim) ) + for name,entity in zip(l_name,l_entity) ] # yapf: disable + + return l + ###################################################################### -def do_print(var): - assert type(var) == Variable - filename = var.line.filename[0] - name = var.name - file = open("%s%s.l"%(mandir,var.name), "w") - print >>file, '.TH "IRPF90 entities" l %s "IRPF90 entities" %s'%(name,name) - if var.same_as != var.name: - var = variables[var.same_as] - print >>file, ".SH Declaration" - print >>file, ".nf" - process_types(file,var) - print >>file, ".ni" - if var.doc != []: - print >>file, ".SH Description" - for l in var.doc: - process_doc(file,l) - print >>file, ".SH File\n.P" - print >>file, filename - if var.needs != []: - var.needs.sort() - print >>file, ".SH Needs" - process_deps(file,var.needs) - if var.needed_by != []: - var.needed_by.sort() - print >>file, ".SH Needed by" - process_deps(file,var.needed_by) - print >>file, ".SH Instability factor" - fo = len(var.children) - fi = len(var.parents) - print >>file, "%5.1f %%"%(100.* (fi / (fi+fo+.000001) )) - print >>file, ".br" - file.close() +def do_print(entity, d_entity): + assert type(entity) == Entity + filename = entity.prototype.filename[0] + name = entity.name + + l_data = [] + + l_data.append('.TH "IRPF90 entities" l {0} "IRPF90 entities" {0}'.format(name)) + + if entity.same_as != entity.name: + entity = d_entity[entity.same_as] + l_data.extend([".SH Declaration", ".nf"]) + l_data += process_types(entity, d_entity) + + l_data.append(".ni") + + if entity.doc: + l_data.append(".SH Description") + for l in entity.doc: + l_data += process_doc(l) + + l_data.append(".SH File\n.P") + l_data.append(filename) + + if entity.needs: + l_data.append(".SH Needs") + l_data += process_deps(entity.needs) + + if entity.needed_by: + l_data.append(".SH Needed by") + l_data += process_deps(entity.needed_by) + + l_data.append(".SH Instability factor") + fo = len(entity.children) + fi = len(entity.parents) + l_data.append("%5.1f %%" % (100. * (fi / (fi + fo + .000001)))) + l_data.append(".br") + str_ = '\n'.join(l_data) + lazy_write_file("%s%s.l" % (mandir, name), '%s\n' % str_) + -###################################################################### -def process_declaration_subroutine(file, sub): - print >>file, sub.line.text.split('!')[0].strip() -# for line in sub.text: ###################################################################### def do_print_subroutines(sub): - assert type(sub) == Sub - filename = sub.line.filename - name = sub.name - file = open("%s%s.l"%(mandir,sub.name), "w") - print >>file, '.TH "IRPF90 entities" l %s "IRPF90 entities" %s'%(name,name) - print >>file, ".SH Declaration" - print >>file, ".nf" - process_declaration_subroutine(file,sub) - print >>file, ".ni" - if sub.doc != []: - print >>file, ".SH Description" - for l in sub.doc: - process_doc(file,l) - print >>file, ".SH File\n.P" - print >>file, filename - if sub.needs != []: - sub.needs.sort() - print >>file, ".SH Needs" - process_deps(file,sub.needs) - if sub.called_by != []: - sub.called_by.sort() - print >>file, ".SH Called by" - process_deps(file,sub.called_by) - if sub.calls != []: - sub.calls.sort() - print >>file, ".SH Calls" - process_deps(file,sub.calls) - if sub.touches != []: - sub.touches.sort() - print >>file, ".SH Touches" - process_deps(file,sub.touches) - print >>file, ".SH Instability factor" - fo = len(sub.needs)+len(sub.calls)+len(sub.touches) - fi = len(sub.called_by) - print >>file, "%5.1f %%"%(100.* (fi / (fi+fo+.000001) )) - print >>file, ".br" - file.close() + assert type(sub) == Routine + filename = sub.prototype.filename + name = sub.name + l_data = [] + + l_data.append('.TH "IRPF90 entities" l {0} "IRPF90 entities" {0}'.format(name)) + l_data.append(".SH Declaration") + l_data.append(".nf") + l_data += [sub.prototype.text] + l_data.append(".ni") + if sub.doc: + l_data.append(".SH Description") + for l in sub.doc: + l_data += process_doc(l) + l_data.append(".SH File\n.P") + + l_data.append(filename) + if sub.needs: + l_data.append(".SH Needs") + l_data += process_deps(sub.needs) + + if sub.called_by: + l_data.append(".SH Called by") + l_data += process_deps(sub.called_by) + + if sub.calls: + l_data.append(".SH Calls") + l_data += process_deps(sub.calls) + + if sub.touches: + l_data.append(".SH Touches") + l_data += process_deps(sub.touches) + + l_data.append(".SH Instability factor") + fo = len(sub.needs) + len(sub.calls) + len(sub.touches) + fi = len(sub.called_by) + l_data.append("%5.1f %%" % (100. * (fi / (fi + fo + .000001)))) + l_data.append(".br") + + str_ = '\n'.join(l_data) + + return '%s\n' % str_ + + #lazy_write_file(filename="%s.l" % os.path.join(mandir, name), text='%s\n' % str_) + ###################################################################### -def run(): - import parsed_text - import os,sys - pid1 = os.fork() - if pid1 == 0: - for v in variables.values(): - do_print(v) - for s in subroutines.values(): - do_print_subroutines(s) - sys.exit(0) +def run(d_entity, d_routine): + + for v in d_entity.values(): + do_print(v, d_entity) + + l_subs = d_routine.values() + + l_data_to_write = [("%s.l" % os.path.join(mandir, s.name), do_print_subroutines(s)) for s in l_subs] + + + def worker(l): + filename, text = l + lazy_write_file(filename, text) + + parmap(worker, l_data_to_write) - pid2 = os.fork() - if pid2 == 0: tags = [] - l = variables.keys() - file = open("irpf90_entities","w") - l.sort() - for v in l: - do_print_short(file,variables[v]) - line = variables[v].line -# tags.append( '%s\t%s\t/%s/;"\n'%(v,line.filename[0],line.text.split('!')[0].strip()) ) - tags.append( '%s\t%s\t%d\n'%(v,line.filename[0],line.i) ) - file.close() - l = subroutines.keys() - for v in l: - line = subroutines[v].line -# tags.append('%s\t%s\t/%s/;"\n'%(v,line.filename,line.text.split('!')[0].strip())) - tags.append('%s\t%s\t%d\n'%(v,line.filename,line.i)) - tags.sort() - file = open("tags","w") - for line in tags: - file.write(line) - file.close() - sys.exit(0) - os.waitpid(pid1,0) - os.waitpid(pid2,0) + for v in d_entity.keys(): + line = d_entity[v].prototype + tags.append('%s\t%s\t%d\n' % (v, line.filename[0], line.i)) + + for v in d_routine.keys(): + line = d_routine[v].prototype + tags.append('%s\t%s\t%d\n' % (v, line.filename, line.i)) + + lazy_write_file("tags", ''.join(sorted(tags))) + + l_data = [e for k, v in sorted(d_entity.items()) for e in do_print_short(v)] + str_ = '\n'.join(l_data) + lazy_write_file(filename="irpf90_entities", text='%s\n' % str_) ###################################################################### if __name__ == '__main__': - run() + run() diff --git a/src/entity.py b/src/entity.py new file mode 100644 index 0000000..2fc1f66 --- /dev/null +++ b/src/entity.py @@ -0,0 +1,726 @@ +#!/usr/bin/env python +# IRPF90 is a Fortran90 preprocessor written in Python for programming using +# the Implicit Reference to Parameters (IRP) method. +# Copyright (C) 2009 Anthony SCEMAMA +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Anthony Scemama +# LCPQ - IRSAMC - CNRS +# Universite Paul Sabatier +# 118, route de Narbonne +# 31062 Toulouse Cedex 4 +# scemama@irsamc.ups-tlse.fr + +from irpf90_t import * +from util import * +from command_line import command_line +import sys +try: + import irpy +except: + import lib_irpy as irpy + + +class Entity(object): + '''All lines between BEGIN_PROVIDER and END_PROVIDER included + + Note: Those lines can define multiple Provider, one need to pick one. + ''' + + ############################################################ + def __init__(self, text, label, name=None, comm_world=None): + # (list[str], str, int, Irpy_comm_world) + '''Instantiate the object. + + Args: + text: List of lines between BEGIN_PROVIDER and END_PROVIDER included + int: An unique int id (usefull when profilling) + name: The name of the provider defined after the chosen BEGIN_PROVIDER statement + comm_world: A object to communicate we the external world. + ''' + + assert type(text) == list + assert len(text) > 0 + assert type(text[0]) == Begin_provider + + self.label = label + self.text = text + + self.same_as = text[0].filename[1] + self.name = name if name else self.same_as + + self.comm_world = comm_world + + + # ~ # ~ # ~ + # G l o b a l P r o p e r t y + # ~ # ~ # ~ + @irpy.lazy_property + def d_entity(self): + # () -> Dict[str,Entity] + '''Create an alias to the global dictionary of Entity. + + Note: Be aware of the possiblity of Cyclic Dependency. + ''' + return self.comm_world.d_entity + + @irpy.lazy_property + def cm_t_filename_parsed_text(self): + # () -> Tuple[str, Parsed_text] + '''Create an alias to the global tuple for parsed text + + Note: self.comm_world.t_filename_parsed_text need d_entity. + Be aware of the possibility of Cyclic Dependency + ''' + return self.comm_world.t_filename_parsed_text + + @irpy.lazy_property + def d_type_lines(self): + # () -> Dict[Line, Tuple[int,Line] ] + '''Contruct a mapping table between the type of the line and the possition''' + from collections import defaultdict + d = defaultdict(list) + for i, line in enumerate(self.text): + d[type(line)] += [(i, line)] + return d + + + # ~ # ~ # ~ + # M u l t i p l e P r o v i d e r H a n d l e r + # ~ # ~ # ~ + @irpy.lazy_property + def is_main(self): + # () -> bool + '''Check if this Entity is the main one + + Exemple: + BEGIN_PROVIDER [pi, double precision] & + BEGIN_PROVIDER [e, double preision] + + return True for 'pi' and False for 'e' + ''' + return self.name == self.same_as + + + @irpy.lazy_property + def prototype(self): + # () -> Line + '''Find the declaration statement associated with the name of the provider + + Exemple: + BEGIN_PROVIDER [pi, double precision] & + BEGIN_PROVIDER [e, double preision] + + if self.name == e, will return BEGIN_PROVIDER [e, double preision] + ''' + + d = self.d_type_lines + return next(line for _,line in d[Begin_provider]+d[Cont_provider] if line.filename[1] == self.name) + + + @irpy.lazy_property + def others_entity_name(self): + # () -> List[str] + '''Extract the other entity-name defined''' + d = self.d_type_lines + return [line.filename[1] for _,line in d[Begin_provider]+d[Cont_provider] if not line.filename[1] == self.name] + + + @irpy.lazy_property + def doc(self): + # () -> List[str] + doc = [line.text.lstrip()[1:] for _,line in self.d_type_lines[Doc]] + if not doc: + logger.warning("Entity '%s' is not documented" % (self.name)) + return doc + + @irpy.lazy_property + def documented(self): + #() -> bool + return bool(self.doc) + + # ~ # ~ # ~ + # T o u c h / R E A D / W R O T E + # ~ # ~ # ~ + + @irpy.lazy_property_mutable + def is_written(self): + #() -> bool + '''Check if it will be written on disk''' + return any(self.d_entity[i].is_written for i in self.parents) + + @irpy.lazy_property + def writer(self): + if not self.is_main: + result = [] + else: + name = self.name + result = [ \ + "subroutine writer_%s(irp_num)"%(name), + " use %s"%(self.fmodule), + " implicit none", + " character*(*), intent(in) :: irp_num", + " logical :: irp_is_open", + " integer :: irp_iunit" ] + if command_line.do_debug: + length = len("writer_%s" % (self.name)) + result += [\ + " character*(%d) :: irp_here = 'writer_%s'"%(length,name), + " call irp_enter(irp_here)" ] + result += [ \ + " if (.not.%s_is_built) then"%(self.same_as), + " call provide_%s"%(self.same_as), + " endif" ] + result += map(lambda x: " call writer_%s(irp_num)" % (x), self.needs) + result += [ \ + " irp_is_open = .True.", + " irp_iunit = 9", + " do while (irp_is_open)", + " irp_iunit = irp_iunit+1", + " inquire(unit=irp_iunit,opened=irp_is_open)", + " enddo" ] + for n in [name] + self.others_entity_name: + result += [\ + " open(unit=irp_iunit,file='irpf90_%s_'//trim(irp_num),form='FORMATTED',status='UNKNOWN',action='WRITE')"%(n), + " write(irp_iunit,*) %s%s"%(n,build_dim(self.d_entity[n].dim,colons=True)), + " close(irp_iunit)" ] + if command_line.do_debug: + result.append(" call irp_leave(irp_here)") + result.append("end subroutine writer_%s" % (name)) + result.append("") + return result + + @irpy.lazy_property_mutable + def is_read(self): + '''Check if it will be read from disk''' + return any(self.d_entity[i].is_read for i in self.parents) + + @irpy.lazy_property + def reader(self): + if not self.is_main: + result = [] + else: + name = self.name + result = [ \ + "subroutine reader_%s(irp_num)"%(name), + " use %s"%(self.fmodule), + " implicit none", + " character*(*), intent(in) :: irp_num", + " logical :: irp_is_open", + " integer :: irp_iunit" ] + if command_line.do_debug: + length = len("reader_%s" % (self.name)) + result += [\ + " character*(%d) :: irp_here = 'reader_%s'"%(length,name), + " call irp_enter(irp_here)" ] + result += map(lambda x: " call reader_%s(irp_num)" % (x), self.needs) + result += [ \ + " irp_is_open = .True.", + " irp_iunit = 9", + " do while (irp_is_open)", + " inquire(unit=irp_iunit,opened=irp_is_open)", + " enddo"] + for n in [name] + self.others: + result += [\ + " open(unit=irp_iunit,file='irpf90_%s_'//trim(irp_num),form='FORMATTED',status='OLD',action='READ')"%(n), + " read(irp_iunit,*) %s%s"%(n,build_dim(self.cm_d_variable[n].dim,colons=True)), + " close(irp_iunit)" ] + result += [ \ + " call touch_%s"%(name), + " %s_is_built = .True."%(name) ] + if command_line.do_debug: + result.append(" call irp_leave(irp_here)") + result.append("end subroutine reader_%s" % (name)) + result.append("") + return result + + @irpy.lazy_property_mutable + def is_self_touched(self): + '''Cehck if it will be modified (touch)''' + return False + + @irpy.lazy_property + def is_touched(self): + '''If any of the children is touched, the entity is touched''' + if self.is_self_touched or any(self.d_entity[i].is_touched for i in self.children): + return True + + return False + + # ~ # ~ # ~ + # INCLUDE, USE, CALL + # ~ # ~ # ~ + + @irpy.lazy_property + def includes(self): + # () -> str + '''Extract the name of include who need be to be include in this Entity''' + return [line.filename for _,line in self.d_type_lines[Include]] + + @irpy.lazy_property + def uses(self): + '''Extract the name of module who are used in this Entity''' + return [line.filename for _,line in self.d_type_lines[Use]] + + @irpy.lazy_property + def calls(self): + '''Extract the name ofthe function called by the entity''' + + def extract_name(line): + return line.text.split('(', 1)[0].split()[1].lower() + + return [extract_name(line) for _,line in self.d_type_lines[Call] ] + + # ~ # ~ # ~ + # Array Dimension + # ~ # ~ # ~ + + @irpy.lazy_property + def dim(self): + # () -> List[str] + '''Extract the dimension of the needed array in a form of list of variable name + + Exemple: + BEGIN_PROVIDER [real, ao_num ] + -> [] + + BEGIN_PROVIDER [ real, ao_oneD_p, (ao_num) ] + -> ['ao_num'] + + BEGIN_PROVIDER [ real, ao_oneD_prim_p, (ao_num,ao_prim_num_max) ] + -> ['ao_num', 'ao_prim_num_max'] + ''' + + line = self.prototype.text.split('!')[0] + buffer = line.replace(']', '').split(',', 2) + + try: + x = buffer[2].strip() + except IndexError: + return [] + else: + return map(str.strip, x[1:-1].split(',')) + + + @irpy.lazy_property + def allocate(self): + # () -> List[Str] + '''Return a list of name of entity who are array and main''' + if not self.is_main: + return [] + else: + # We never go here + return [var for var in self.others_entity_name + [self.name] if self.d_entity[var].dim] + + # ~ # ~ # ~ + # D e c l a r a t i o n + # ~ # ~ # ~ + + @irpy.lazy_property + def type(self): + # () -> str + '''Compute the fortran type code of the entity''' + + type_ = self.prototype.text.split(',')[0].split('[')[1].strip() + + if not type_: + logger.error( "Error in definition of %s." % (self.name)) + sys.exit(1) + + if self.dim: + return "%s, allocatable" % (type_) + else: + return type_ + + @irpy.lazy_property + def header(self): + # () -> List[str] + '''Compute all the code needed to inistanticant the entity''' + + + name = self.name + str_ = " {type_} :: {name} {dim}".format(type_=self.type, name=name, dim=build_dim(self.dim, colons=True)) + + if command_line.coarray: + if not self.dim: + str_ += " [*]" + else: + str_ += " [:]" + + l = [str_] + if self.dim and command_line.align != '1': + l += [" !DIR$ ATTRIBUTES ALIGN: %s :: %s" % (command_line.align, name)] + + if self.is_main: + l += [" logical :: %s_is_built = .False." % (name)] + + return l + + + ############################################################ + @irpy.lazy_property + def fmodule(self): + # () -> str + '''Contruct the name of the module who will contain the entity''' + name = self.prototype.filename[0].replace('/', '__').split('.irp.f')[0] + return '%s_mod' % name + + ############################################################ + @irpy.lazy_property + def regexp(self): + # () -> Regex + '''Compile a regex targeted to 'search' the name of this entity''' + import re + return re.compile(r"([^a-z0-9'\"_]|^)%s([^a-z0-9_]|$)" % (self.name), re.I).search + + # ~ # ~ # ~ + # F o r t r a n 9 0 G e n e r a t i o n + # ~ # ~ # ~ + + @irpy.lazy_property + def toucher(self): + # () -> List[str] + '''Fabric the f90 routine who handle the cache invalidation''' + + # Only one by EntityColleciton + if not self.is_main: + return [] + + parents = self.parents + name = self.name + + result = ["subroutine touch_%s" % (name)] + + result += build_use(parents+[name],self.d_entity) + result.append(" implicit none") + + if command_line.do_debug: + length = str(len("touch_%s" % (name))) + result += [" character*(%s) :: irp_here = 'touch_%s'" % (length, name)] + result += [" call irp_enter(irp_here)"] + + result += map(lambda x: " %s_is_built = .False." % (x), parents) + result.append(" %s_is_built = .True." % (name)) + + if command_line.do_debug: + result.append(" call irp_leave(irp_here)") + + result.append("end subroutine touch_%s" % (name)) + result.append("") + + return result + + ########################################################## + @irpy.lazy_property + def locker(self): + if not command_line.do_openmp: + return [] + + name = self.name + result = ["subroutine irp_lock_%s(set)" % (name)] + result += [ + " use omp_lib", + " implicit none", + " logical, intent(in) :: set", + " integer(kind=omp_nest_lock_kind),save :: %s_lock" % (name), + " integer,save :: ifirst", + ] + if command_line.do_debug: + length = str(len("irp_lock_%s" % (name))) + result += [ + " character*(%s) :: irp_here = 'irp_lock_%s'" % (length, name), + " call irp_enter(irp_here)" + ] + + result += [ + " if (ifirst == 0) then", + " ifirst = 1", + " call omp_init_nest_lock(%s_lock)" % (name), + " endif", + " if (set) then", + " call omp_set_nest_lock(%s_lock)" % (name), + " else", + " call omp_unset_nest_lock(%s_lock)" % (name), + " endif", + ] + if command_line.do_debug: + result.append(" call irp_leave(irp_here)") + result.append("end subroutine irp_lock_%s" % (name)) + result.append("") + return result + + ########################################################## + @irpy.lazy_property + def free(self): + # () -> List[ str ] + '''Compute an part of a subroutine used to free a variable''' + + name = self.name + result = ["!", + "! >>> FREE %s" % (name), + " %s_is_built = .False." % (self.same_as)] + + if self.dim: + result += [ + " if (allocated(%s)) then"%(name), + " deallocate (%s)"%(name)] + if command_line.do_memory: + result += " print *, 'Deallocating %s'"%(name) + + result += [" endif"] + + result.append("! <<< END FREE") + return result + + ########################################################## + @irpy.lazy_property + def provider(self): + # () -> List[str] + '''Create the fortran90 code for the EntityCollection''' + + if not self.is_main: + return [] + + name = self.name + same_as = self.same_as + + def dimsize(x): + # (str) -> str + '''Compute the number of element in the array''' + try: + b0, b1 = x.split(':') + except ValueError: + return x + + b0_is_digit = b0.replace('-', '').isdigit() + b1_is_digit = b1.replace('-', '').isdigit() + + + if b0_is_digit and b1_is_digit: + size = str(int(b1) - int(b0) + 1) + elif b0_is_digit: + size = "(%s) - (%d)" % (b1, int(b0) - 1) + elif b1_is_digit: + size = "(%d) - (%s)" % (int(b1) + 1, b0) + else: + size = "(%s) - (%s) + 1" % (b1, b0) + + return size + + def build_alloc(name): + + var = self.d_entity[name] + if var.dim == []: + return [] + + from util import build_dim + + def print_size(): + return " " * 5 + "print *, ' size: {0}'".format(build_dim(var.dim)) + + def check_dimensions(): + l = ["(%s>0)" % dimsize(x) for x in var.dim] + str_ = ".and.".join(l) + return " if (%s) then" % (str_) + + def dimensions_OK(): + result = [" irp_dimensions_OK = .True."] + for i, k in enumerate(var.dim): + result.append(" irp_dimensions_OK = irp_dimensions_OK.AND.(SIZE(%s,%d)==(%s))" + % (name, i + 1, dimsize(k))) + return result + + def do_allocate(): + if command_line.coarray: + result = " allocate(%s(%s)[*],stat=irp_err)" + else: + result = " allocate(%s(%s),stat=irp_err)" + result = result % (name, ','.join(var.dim)) + if command_line.do_memory: + tmp = "\n print *, %s, 'Allocating %s(%s)'" + d = ','.join(self.dim) + result += tmp % ('size(' + name + ')', name, d) + return result + + result = [" if (allocated (%s) ) then" % (name)] + result += dimensions_OK() + result += [ + " if (.not.irp_dimensions_OK) then", " deallocate(%s,stat=irp_err)" % (name), + " if (irp_err /= 0) then", " print *, irp_here//': Deallocation failed: %s'" % + (name), print_size(), " endif" + ] + + if command_line.do_memory: + result += [" print *, 'Deallocating %s'" % (name)] + result.append(check_dimensions()) + result.append(do_allocate()) + result += [\ + " if (irp_err /= 0) then", + " print *, irp_here//': Allocation failed: %s'"%(name), + print_size(), + " endif", + " endif", + " endif", + " else" ] + result.append(check_dimensions()) + result.append(do_allocate()) + result += [ + " if (irp_err /= 0) then", " print *, irp_here//': Allocation failed: %s'" % + (name), print_size(), " endif", " endif", " endif" + ] + return result + + result = [] + if command_line.directives and command_line.inline in ["all", "providers"]: + result += ["!DEC$ ATTRIBUTES FORCEINLINE :: provide_%s" % (name)] + result += ["subroutine provide_%s" % (name)] + result += build_use([same_as] + self.to_provide, self.d_entity) + if command_line.do_openmp: + result += [" use omp_lib"] + result.append(" implicit none") + length = len("provide_%s" % (name)) + result += [ + " character*(%d) :: irp_here = 'provide_%s'" % (length, name), + " integer :: irp_err ", + " logical :: irp_dimensions_OK", + "!$ integer :: nthreads" + ] + if command_line.do_openmp: + result.append(" call irp_lock_%s(.True.)" % (same_as)) + if command_line.do_assert or command_line.do_debug: + result.append(" call irp_enter(irp_here)") + result += build_call_provide(self.to_provide, self.d_entity) + result += flatten(map(build_alloc, [self.same_as] + self.others_entity_name)) + result += [ + " if (.not.%s_is_built) then" % (same_as), " call bld_%s" % (same_as), + " %s_is_built = .True." % (same_as), "" + ] + result += [" endif"] + if command_line.do_assert or command_line.do_debug: + result.append(" call irp_leave(irp_here)") + if command_line.do_openmp: + result.append(" call irp_lock_%s(.False.)" % (same_as)) + result.append("end subroutine provide_%s" % (name)) + result.append("") + return result + + ########################################################## + @irpy.lazy_property + def builder(self): + if not self.is_main: + return [] + + # ~#~#~#~#~# + # Get the raw text for the builder + # ~#~#~#~#~# + + #Next return the first element of the iterator + ps_text = next(text for filename, text in self.cm_t_filename_parsed_text + if self.prototype.filename[0].startswith(filename)) + begin = next(i for i, (_, line) in enumerate(ps_text) + if isinstance(line, Begin_provider) if line.filename[1] == self.same_as) + end = next(begin + i for i, (_, line) in enumerate(ps_text[begin:]) + if isinstance(line, End_provider)) + + # Now we now that the text is betern ps_text[begin:end] + _, line_prototype = ps_text[begin] + + # ~#~#~#~#~# + # Aded the call to the provider + # ~#~#~#~#~# + + text = [] + if command_line.do_profile: + text.append(([], Declaration(line_prototype.i, + " double precision :: irp_rdtsc, irp_rdtsc1, irp_rdtsc2", + line_prototype.filename))) + text.append(([], Simple_line(line_prototype.i, " irp_rdtsc1 = irp_rdtsc()", + line_prototype.filename))) + + for vars, line in ps_text[begin + 1:end]: + text.append((vars, line)) + text += map(lambda x: ([], Simple_line(line.i, x, line.filename)), + build_call_provide(vars, self.d_entity)) + + # ~#~#~#~#~# + # Create the subroutine. + # ~#~#~#~#~# + + result = [] + if command_line.directives and command_line.inline in ["all", "builders"]: + result += ["!DEC$ ATTRIBUTES INLINE :: bld_%s" % (same_as)] + + # Add the use statement + result += ["subroutine bld_%s" % (self.name)] + result += build_use([self.name] + self.needs, self.d_entity) + + import parsed_text + # Move the variable to top, and add the text + parsed_text.move_to_top_list(text, [Declaration, Implicit, Use]) + + result.extend( line.text for _,line in text if not isinstance(line, (Begin_doc, End_doc, Doc, Cont_provider))) + + if command_line.do_profile: + result += [ + " irp_rdtsc2 = irp_rdtsc()", + " call irp_set_timer(%d,(irp_rdtsc2-irp_rdtsc1))" % self.label + ] + #Close + result.append("end subroutine bld_%s" % (self.name)) + + return result + + ########################################################## + @irpy.lazy_property_mutable + def needs(self): + #Set by parsed_text.build_needs(...) + raise AttributeError + + @irpy.lazy_property + def children(self): + + result = [] + for x in self.needs: + result.append(x) + try: + result += self.d_entity[x].children + except RuntimeError: + pass # Exception will be checked after + + result = OrderedUniqueList(result) + if self.name in result: + error.fail(self.prototype, "Cyclic dependencies:\n%s" % (str(result))) + return result + + ########################################################## + @irpy.lazy_property + def parents(self): + if not self.is_main: + return [] + + result = [] + for x in self.needed_by: + result.append(x) + try: + result += self.d_entity[x].parents + except RuntimeError: + pass # Exception will be checked after + + result = OrderedUniqueList(result) + if self.name in result: + error.fail(self.prototype, "Cyclic dependencies:\n%s" % (str(self._parents))) + + return result diff --git a/src/init.py b/src/init.py deleted file mode 100644 index cf46025..0000000 --- a/src/init.py +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/env python -# IRPF90 is a Fortran90 preprocessor written in Python for programming using -# the Implicit Reference to Parameters (IRP) method. -# Copyright (C) 2009 Anthony SCEMAMA -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Anthony Scemama -# LCPQ - IRSAMC - CNRS -# Universite Paul Sabatier -# 118, route de Narbonne -# 31062 Toulouse Cedex 4 -# scemama@irsamc.ups-tlse.fr - - -import os - -import util -import makefile -import irpf90_t -from command_line import command_line - -initialized = False - - -def init(): - - global initialized - if initialized: - return - - # Create directories - for dir in [ irpf90_t.irpdir, irpf90_t.mandir ]: - try: - wd = os.getcwd() - os.chdir(dir) - os.chdir(wd) - except OSError: - os.mkdir(dir) - - for dir in command_line.include_dir: - dir = irpf90_t.irpdir+dir - try: - wd = os.getcwd() - os.chdir(dir) - os.chdir(wd) - except OSError: - os.mkdir(dir) - - # Create makefile - makefile.create() - - # Copy current files in the irpdir - for dir in ['./']+command_line.include_dir: - try: - os.stat(dir) - except: - print dir,'not in dir' - continue - for filename in os.listdir(dir): - filename = dir+filename - if not filename.startswith(".") and not os.path.isdir(filename): - try: - file = open(filename,"r") - except IOError: - if command_line.do_warnings: - print "Warning : Unable to read file %s."%(filename) - else: - buffer = file.read() - file.close() - if not util.same_file(irpf90_t.irpdir+filename,buffer): - file = open(irpf90_t.irpdir+filename,"w") - file.write(buffer) - file.close() - - initialized = True - diff --git a/src/irp_stack.py b/src/irp_stack.py index d60710b..fe321bc 100644 --- a/src/irp_stack.py +++ b/src/irp_stack.py @@ -85,9 +85,9 @@ subroutine irp_enter(irp_where) nthread = 1 """ txt += """ - print *, 'Allocating irp_stack(',STACKMAX,',',nthread,')' - print *, 'Allocating irp_cpu(',STACKMAX,',',nthread,')' - print *, 'Allocating stack_index(',nthread,')' + print *, 'Allocating irp_stack(',STACKMAX,',',0:nthread,')' + print *, 'Allocating irp_cpu(',STACKMAX,',',0:nthread,')' + print *, 'Allocating stack_index(',0:nthread,')' endif""" txt +=""" $2 @@ -128,9 +128,9 @@ $1 nthread = 1 """ txt +=""" - print *, 'Allocating irp_stack(',STACKMAX,',',nthread,')' - print *, 'Allocating irp_cpu(',STACKMAX,',',nthread,')' - print *, 'Allocating stack_index(',nthread,')' + print *, 'Allocating irp_stack(',STACKMAX,',',0:nthread,')' + print *, 'Allocating irp_cpu(',STACKMAX,',',0:nthread,')' + print *, 'Allocating stack_index(',0:nthread,')' endif """ txt += """ @@ -172,16 +172,16 @@ end subroutine !$OMP END PARALLEL !$OMP CRITICAL if (.not.alloc) then - allocate(irp_stack(0:STACKMAX,nthread)) - allocate(irp_cpu(0:STACKMAX,nthread)) - allocate(stack_index(nthread)) + allocate(irp_stack(0:STACKMAX,0:nthread)) + allocate(irp_cpu(0:STACKMAX,0:nthread)) + allocate(stack_index(0:nthread)) stack_index = 0 alloc = .True. endif !$OMP END CRITICAL endif - stack_index(ithread+1) = mod(stack_index(ithread+1)+1,STACKMAX) - irp_stack(stack_index(ithread+1),ithread+1) = irp_where""" + stack_index(ithread) = min(stack_index(ithread)+1,STACKMAX) + irp_stack(stack_index(ithread),ithread) = irp_where""" else: s += """ nthread = 1 @@ -193,13 +193,13 @@ end subroutine alloc = .True. endif endif - stack_index(1) = mod(stack_index(1)+1,STACKMAX) + stack_index(1) = min(stack_index(1)+1,STACKMAX) irp_stack(stack_index(1),1) = irp_where""" if do_memory: txt+=""" - print *, 'Allocating irp_stack(',STACKMAX,','nthread,')' - print *, 'Allocating irp_cpu(',STACKMAX,','nthread,')' - print *, 'Allocating stack_index(',nthread,')'""" + print *, 'Allocating irp_stack(',STACKMAX,','0:nthread,')' + print *, 'Allocating irp_cpu(',STACKMAX,','0:nthread,')' + print *, 'Allocating stack_index(',0:nthread,')'""" else: s = "" txt = txt.replace("$1",s) @@ -207,8 +207,8 @@ end subroutine # $2 if do_debug: txt = txt.replace("$2",""" - print *, ithread, ':', white(1:stack_index(ithread+1))//'-> ', trim(irp_where) - call cpu_time(irp_cpu(stack_index(ithread+1),ithread+1))""") + print *, ithread, ':', white(1:stack_index(ithread))//'-> ', trim(irp_where) + call cpu_time(irp_cpu(stack_index(ithread),ithread))""") else: txt = txt.replace("$2","") @@ -216,16 +216,16 @@ end subroutine if do_debug: txt = txt.replace("$3",""" call cpu_time(cpu) - print *, ithread, ':', white(1:stack_index(ithread+1))//'<- ', & - trim(irp_stack(stack_index(ithread+1),ithread+1)), & - cpu-irp_cpu(stack_index(ithread+1),ithread+1)""") + print *, ithread, ':', white(1:stack_index(ithread))//'<- ', & + trim(irp_stack(stack_index(ithread),ithread)), & + cpu-irp_cpu(stack_index(ithread),ithread)""") else: txt = txt.replace("$3","") # $4 if do_debug or do_assert: txt = txt.replace("$4",""" - stack_index(ithread+1) = stack_index(ithread+1)-1""") + stack_index(ithread) = max(0,stack_index(ithread)-1)""") else: txt = txt.replace("$4","") @@ -248,18 +248,13 @@ subroutine irp_trace if (.not.alloc) return print *, 'Stack trace: ', ithread print *, '-------------------------' - do i=1,stack_index(ithread+1) - print *, trim(irp_stack(i,ithread+1)) + do i=1,stack_index(ithread) + print *, trim(irp_stack(i,ithread)) enddo print *, '-------------------------' end subroutine + """ - txt = txt.split('\n') - txt = map(lambda x: x+"\n",txt) - if not util.same_file(FILENAME, txt): - file = open(FILENAME,'w') - file.writelines(txt) - file.close() - + util.lazy_write_file(FILENAME,txt) diff --git a/src/irpf90.py b/src/irpf90.py index a332860..4942baa 100644 --- a/src/irpf90.py +++ b/src/irpf90.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -#cscs /usr/bin/env python # IRPF90 is a Fortran90 preprocessor written in Python for programming using # the Implicit Reference to Parameters (IRP) method. # Copyright (C) 2009 Anthony SCEMAMA @@ -25,95 +24,85 @@ # 31062 Toulouse Cedex 4 # scemama@irsamc.ups-tlse.fr - - import vim -import os,sys +import os, sys try: - wd = os.path.abspath(os.path.dirname(__file__)) - sys.path.insert(0,(wd+"/../src/")) + wd = os.path.abspath(os.path.dirname(__file__)) + sys.path.insert(0, (wd + "/../src/")) except: - pass -sys.setcheckinterval(1000) + pass from command_line import command_line +from irpy_files import Irpy_comm_world def main(): - vim.install() + vim.install() - if command_line.do_help: - command_line.usage() + if command_line.do_help: + command_line.usage() + return + if command_line.do_version: + from version import version + print version + return - if command_line.do_version: - from version import version - print version + if command_line.do_init: + from build_file import create_generalmakefile + create_generalmakefile(command_line.do_ninja) + return - from init import init - if command_line.do_init: - init() + comm_world = Irpy_comm_world() - if command_line.do_preprocess: - init() - from preprocessed_text import preprocessed_text - for filename,text in preprocessed_text: - if filename in command_line.preprocessed: - for line in text: - print line.text + if command_line.do_graph: + comm_world.t_filename_parsed_text # Initialize entity need. Dirty I know. + + print 'graph { ' + for name,entity in comm_world.d_entity.items(): + if entity.needs: + print ' {0} -> {1}'.format(name, ' '.join(entity.needs)) + print '}' + return - if command_line.do_touch: - from variables import variables - for var in command_line.touched: - if var not in variables: - print "%s is not an IRP entity"%(var,) - else: - print "Touching %s invalidates the following entities:"%(var,) - parents = variables[var].parents - parents.sort() - for x in parents: - print "- %s"%(x,) + if command_line.do_preprocess: + for filename, text in comm_world.preprocessed_text: + if filename in command_line.preprocessed: + for line in text: + print line.text + return - if command_line.do_codelet: - import profile - profile.build_rdtsc() - import codelet - codelet.run() + if command_line.do_touch: + for var in command_line.touched: + if var not in comm_world.d_entity: + print "%s is not an IRP entity" % var + else: + print "Touching %s invalidates the following entities:" % var + for x in sorted(d_entity[var].parents): + print "- %s" % (x, ) + return - if not command_line.do_run: - return + if command_line.do_codelet: + import profile + profile.build_rdtsc() + import codelet + codelet.run() - init() + if not command_line.do_run: + return - import irp_stack - irp_stack.create() + comm_world.create_buildfile(command_line.do_ninja) + comm_world.write_modules() + + comm_world.create_touches() + comm_world.create_man() - import makefile - makefile.create() + if command_line.do_profile: + import profile + profile.run(comm_world.d_entity) - from modules import modules, write_module - for m in modules.keys(): - write_module(modules[m]) - - makefile.run() - - import touches - touches.create() - -# import checkpoint -# checkpoint.create() - - import create_man - create_man.run() - - if command_line.do_profile: - import profile - profile.run() - - if command_line.do_openmp: - import locks - locks.create() + if command_line.do_openmp: + comm_world.create_lock() if __name__ == '__main__': - main() - + main() diff --git a/vim/irpf90.vim b/src/irpf90.vim similarity index 79% rename from vim/irpf90.vim rename to src/irpf90.vim index c7774f2..d5515b4 100644 --- a/vim/irpf90.vim +++ b/src/irpf90.vim @@ -373,4 +373,120 @@ map K :call ReadMan() set equalprg=irpf90_indent +if exists('g:no_irpf90_conceal') || !has('conceal') || &enc != 'utf-8' + finish +endif + +syntax match irpf90NiceOperator "<-" conceal cchar=← +iab ← <- +syntax match irpf90NiceOperator "->" conceal cchar=→ +iab → -> +syntax match irpf90NiceOperator "==" conceal cchar=≡ +iab ≡ == +syntax match irpf90NiceOperator "\.eq\." conceal cchar=≡ +syntax match irpf90NiceOperator "/=" conceal cchar=≠ +iab ≠ /= +syntax match irpf90NiceOperator "\.ne\." conceal cchar=≠ +syntax match irpf90NiceOperator "\.or\." conceal cchar=∨ +iab ∨ .or. +syntax match irpf90NiceOperator "\.and\." conceal cchar=∧ +iab ∧ .and. +syntax match irpf90NiceOperator "*" conceal cchar=× +iab × * + +let s:extraConceal = 1 +" Some windows font don't support some of the characters, +" so if they are the main font, we don't load them :) +if has("win32") + let s:incompleteFont = [ 'Consolas' + \ , 'Lucida Console' + \ , 'Courier New' + \ ] + let s:mainfont = substitute( &guifont, '^\([^:,]\+\).*', '\1', '') + for s:fontName in s:incompleteFont + if s:mainfont ==? s:fontName + let s:extraConceal = 0 + break + endif + endfor +endif + +if s:extraConceal + syntax match irpf90NiceOperator "<=" conceal cchar=≤ + syntax match irpf90NiceOperator "\.le\." conceal cchar=≤ + iab ≤ <= + syntax match irpf90NiceOperator ">=" conceal cchar=≥ + syntax match irpf90NiceOperator "\.ge\." conceal cchar=≥ + iab ≥ >= + syntax match irpf90NiceOperator "\.lt\." conceal cchar=< + syntax match irpf90NiceOperator "\.gt\." conceal cchar=> + syntax match irpf90NiceOperator "=>" conceal cchar=⇒ + iab ⇒ => + syntax match irpf90NiceOperator "\:\:" conceal cchar=∷ + iab ∷ :: + syntax match irpf90NiceOperator "++" conceal cchar=⧺ + iab ⧺ ++ + syntax match irpf90NiceOperator "\" conceal cchar=Δ + iab Δ Delta + syntax match irpf90NiceOperator "\C\" conceal cchar=Λ + iab Λ Lambda + syntax match irpf90NiceOperator "\C\" conceal cchar=Π + iab Π Pi + syntax match irpf90NiceOperator "\C\" conceal cchar=Σ + iab Σ Sigma + syntax match irpf90NiceOperator "\C\" conceal cchar=Ψ + iab Ψ Psi + syntax match irpf90NiceOperator "\C\" conceal cchar=Ω + iab Ω Omega + syntax match irpf90NiceOperator "\C\" conceal cchar=α + iab α alpha + syntax match irpf90NiceOperator "\C\" conceal cchar=β + iab β beta + syntax match irpf90NiceOperator "\C\" conceal cchar=γ + iab γ gamma + syntax match irpf90NiceOperator "\C\" conceal cchar=δ + iab δ delta + syntax match irpf90NiceOperator "\C\" conceal cchar=ε + iab ε epsilon + syntax match irpf90NiceOperator "\C\" conceal cchar=ζ + iab ζ zeta + syntax match irpf90NiceOperator "\C\" conceal cchar=θ + iab θ theta + syntax match irpf90NiceOperator "\C\" conceal cchar=η + iab η eta + syntax match irpf90NiceOperator "\C\" conceal cchar=λ + iab λ lambda + syntax match irpf90NiceOperator "\C\" conceal cchar=μ + iab μ mu + syntax match irpf90NiceOperator "\C\" conceal cchar=ν + iab ν nu + syntax match irpf90NiceOperator "\C\" conceal cchar=π + iab π pi + syntax match irpf90NiceOperator "\C\" conceal cchar=ρ + iab ρ rho + syntax match irpf90NiceOperator "\C\" conceal cchar=σ + iab σ sigma + syntax match irpf90NiceOperator "\C\" conceal cchar=τ + iab τ tau + syntax match irpf90NiceOperator "\C\" conceal cchar=φ + iab φ phi + syntax match irpf90NiceOperator "\C\" conceal cchar=∇ + iab ∇ nabla + syntax match irpf90NiceOperator "\C\" conceal cchar=χ + iab χ chi + syntax match irpf90NiceOperator "\C\" conceal cchar=ψ + iab ψ psi + syntax match irpf90NiceOperator "\C\" conceal cchar=ω + iab ω omega +endif + +hi link irpf90NiceOperator Operator +hi! link Conceal Operator +setlocal conceallevel=2 + +" vim: set fenc=utf-8: " vim: ts=8 tw=132 + diff --git a/src/irpf90_t.py b/src/irpf90_t.py index 68ffca9..4e6f793 100644 --- a/src/irpf90_t.py +++ b/src/irpf90_t.py @@ -24,385 +24,63 @@ # 31062 Toulouse Cedex 4 # scemama@irsamc.ups-tlse.fr -import os -from zlib import crc32 irpdir = "IRPF90_temp/" mandir = "IRPF90_man/" + +from zlib import crc32 +import os irp_id = abs(crc32(os.getcwd())) +try: + import irpy +except: + import lib_irpy as irpy + class Line(object): - def __init__(self,i,text,filename): - self.i = i - self._text = None - self.filename = filename - self._lower = None - self.set_text(text) + def __init__(self, i, text, filename): + self.i = i + self.text = text + self.filename = filename - def get_text(self): - return self._text - - def set_text(self,value): - self._text = value - self._lower = value.lower() + @irpy.lazy_property + def lower(self): + return self.text.lower() - def get_lower(self): - return self._lower + def __repr__(self): + return "%20s:%5d : %s (%s)" % (type(self).__name__, self.i, self.text, self.filename) - text = property(fget=get_text, fset=set_text) - lower = property(fget=get_lower) +class LineWithName(Line): -class Empty_line(Line): - str="Empty_line" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Empty_line",self.i,self.text) + @irpy.lazy_property + def subname(self): + buf = self.lower + if not buf.endswith(')'): + buf += "()" -class Simple_line(Line): - str="Simple_line" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Simple_line",self.i,self.text) + l_buf = buf.split('(') + l_name = l_buf[0].split() -class Declaration(Line): - str="Declaration" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Declaration",self.i,self.text) - -class Continue(Line): - str="Continue" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Continue",self.i,self.text) - -class Begin_provider(Line): - str="Begin_provider" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Begin_provider",self.i,self.text) - -class Cont_provider(Line): - str="Cont_provider" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Cont_provider",self.i,self.text) - -class End_provider(Line): - str="End_provider" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("End_provider",self.i,self.text) - -class Begin_doc(Line): - str="Begin_doc" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Begin_doc",self.i,self.text) - -class Doc(Line): - str="Doc" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Doc",self.i,self.text) - -class End_doc(Line): - str="End_doc" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("End_doc",self.i,self.text) - -class Begin_shell(Line): - str="Begin_shell" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Begin_shell",self.i,self.text) - -class End_shell(Line): - str="End_shell" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("End_shell",self.i,self.text) - -class Begin_template(Line): - str="Begin_template" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Begin_template",self.i,self.text) - -class End_template(Line): - str="End_template" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("End_template",self.i,self.text) - -class Subst(Line): - str="Subst" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Subst",self.i,self.text) - -class Assert(Line): - str="Assert" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Assert",self.i,self.text) - -class Touch(Line): - str="Touch" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Touch",self.i,self.text) - -class SoftTouch(Touch): - str="SoftTouch" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("SoftTouch",self.i,self.text) - -class Irp_read(Line): - str="Irp_read" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Irp_read",self.i,self.text) - -class Irp_write(Line): - str="Irp_write" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Irp_write",self.i,self.text) - -class Irp_If(Line): - str="Irp_If" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Irp_If",self.i,self.text) - -class Irp_Else(Line): - str="Irp_Else" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Irp_Else",self.i,self.text) - -class Irp_Endif(Line): - str="Irp_Endif" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Irp_Endif",self.i,self.text) - -class Openmp(Line): - str="Openmp" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Openmp",self.i,self.text) - -class Directive(Line): - str="Directive" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Directive",self.i,self.text) - -class Use(Line): - str="Use" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Use",self.i,self.text) - -class Do(Line): - str="Do" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Do",self.i,self.text) - -class Enddo (Line): - str="Enddo" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Enddo",self.i,self.text) - -class If(Line): - str="If" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("If",self.i,self.text) - -class Elseif(Line): - str="Elseif" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Elseif",self.i,self.text) - -class Else(Line): - str="Else" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Else",self.i,self.text) - -class Endif(Line): - str="Endif" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Endif",self.i,self.text) - -class Select(Line): - str="Select" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Select",self.i,self.text) - -class Case(Line): - str="Case" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Case",self.i,self.text) - -class End_select(Line): - str="End_select" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("End_select",self.i,self.text) - -class Program(Line): - str="Program" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Program",self.i,self.text) - -class Subroutine(Line): - str="Subroutine" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Subroutine",self.i,self.text) - -class Function(Line): - str="Function" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Function",self.i,self.text) - -class Call(Line): - str="Call" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Call",self.i,self.text) - -class Provide(Line): - str="Provide" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Provide",self.i,self.text) - -class NoDep(Line): - str="NoDep" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("NoDep",self.i,self.text) - -class Return (Line): - str="Return" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Return",self.i,self.text) - -class Include(Line): - str="Include" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Include",self.i,self.text) - -class Implicit (Line): - str="Implicit" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Implicit",self.i,self.text) - -class Free(Line): - str="Free" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Free",self.i,self.text) - -class End(Line): - str="End" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("End",self.i,self.text) - -class Provide_all (Line): - str="Provide_all" - def __init__(self,i,text,filename): - Line.__init__(self,i,text,filename) - def __repr__(self): - return "%20s:%5d : %s"%("Provide_all",self.i,self.text) - - -###################################################################### - -def create_irpf90_files(): - result = [] - from command_line import command_line - import os - def is_irpf90_file(filename): - return filename.endswith(".irp.f") and not filename.startswith('.') - result = filter ( is_irpf90_file, os.listdir(os.getcwd()) ) - for dir in command_line.include_dir: - try: - os.stat(dir) - result += map(lambda x: dir+x, filter ( is_irpf90_file, os.listdir(dir) ) ) - except: - continue - if command_line.do_codelet: - result += [command_line.codelet[3]] - return result -irpf90_files = create_irpf90_files() + if len(l_name) < 2: + import loger + logger.error("Syntax Error: %s" % line) + sys.exit(1) + return l_name.pop() +l_type = [ + 'Empty_line', 'Simple_line', "Declaration", "Continue", "Begin_provider", + "Cont_provider", "End_provider", "Begin_doc", "Doc", "End_doc", + "Begin_shell", "End_shell", "Begin_template", "End_template", "Subst", + "Assert", "Touch", "SoftTouch", "Irp_read", "Irp_write", "Irp_If", + "Irp_Else", "Irp_Endif", "Openmp", "Directive", "Use", "Do", "Enddo", "If", + "Elseif", "Else", "Endif", "Select", "Case", "End_select", "Provide", "NoDep", "Return", "Include", + "Implicit", "Free", "End", "Provide_all","Contains",'Type','End_module','Interface','End_interface', + 'Where','Elsewhere','Endwhere'] +for t in l_type: + globals()[t] = type(t, (Line, ), {}) +for t in ['Subroutine', 'Function', 'Program', 'Call','Module']: + globals()[t] = type(t, (LineWithName, ), {}) diff --git a/src/irpman.py b/src/irpman.py index 4e15b54..b22ad62 100755 --- a/src/irpman.py +++ b/src/irpman.py @@ -28,12 +28,13 @@ import os import sys -wd = os.path.abspath(os.path.dirname(__file__)) -from irpf90_t import mandir -filename = sys.argv[1].lower()+".l" -if filename not in os.listdir(mandir): - print "%s does not exist"%(sys.argv[1]) - sys.exit(-1) - -os.system("man ./"+mandir+sys.argv[1].lower()+".l") +if __name__ == "__main__": + from irpf90_t import mandir + entity = sys.argv[1].lower() + + filename = '%s.l'% entity + if filename not in os.listdir(mandir): + print "Error: `%s` does not exist"% entity + sys.exit(-1) + os.system("man %s" % os.path.join(mandir,filename)) diff --git a/src/irpy_files.py b/src/irpy_files.py new file mode 100644 index 0000000..19438ed --- /dev/null +++ b/src/irpy_files.py @@ -0,0 +1,322 @@ +from util import parmap,lazy_write_file +from util import flatten, listdir + +try: + import irpy +except: + import lib_irpy as irpy + +import os +import irpf90_t +import sys + +from command_line import command_line + +from util import logger + +class Irpy_comm_world(object): + '''Maestro.''' + + def __init__(self,l_dir=None, l_file=None): + # (Iter, Iter) -> None + + # Create directories + from itertools import ifilterfalse + i_folder = ifilterfalse(os.path.exists, (irpf90_t.irpdir, irpf90_t.mandir)) + map(os.mkdir,i_folder) + + # List file + + l_dir =l_dir if l_dir else (command_line.include_dir+['.']) + l_not_dir = [d for d in l_dir if not (os.path.exists(d) and os.path.isdir(d))] + if l_not_dir: + logger.error('Try to include no existing directory: [%s]' % ','.join(l_not_dir)) + sys.exit(1) + + # Create folder in IRPDIR + i_folder = ifilterfalse(os.path.exists, (os.path.join(irpf90_t.irpdir,d) for d in l_dir)) + map(os.mkdir, i_folder) + + s_folder_abs = set(os.path.abspath(path) for path in l_dir) + + s_file_folder_all = set(flatten(listdir(path,abspath=True) for path in s_folder_abs)) + + # Take everything! + s_file_folder = filter(lambda f: os.path.isfile(f) and not f.startswith("."), s_file_folder_all) + + + + + s_file_tot = set(l_file) if l_file else set() + s_file_tot.update(s_file_folder) + + s_file_rel = set(os.path.relpath(f,self.cwd) for f in s_file_tot) + + # Lazy Copy file + for f in s_file_rel: + src = os.path.join(self.cwd,f) + text_ref = open(src, 'rb').read() + + dest = os.path.join(self.cwd,irpf90_t.irpdir, f) + lazy_write_file(dest, text_ref) + + if command_line.do_codelet: + s_file_tot.update(command_line.codelet[3]) + + # No filter the irpf90 file + self.irpf90_files_ordered=sorted(filter(lambda f: f.endswith(".irp.f") ,s_file_rel)) + + @irpy.lazy_property + def cwd(self): + return os.getcwd() + + @irpy.lazy_property + def t_filename_preprocessed_text(self): + '''Tuple (filename, preprocessed_text)''' + + from preprocessed_text import Preprocess_text + def worker_preprocess(filename): + return (filename, Preprocess_text(filename).preprocessed_text) + + return parmap(worker_preprocess, self.irpf90_files_ordered) + + @irpy.lazy_property + def l_preprocessed_text(self): + # (None) -> List[Line] + '''List preprocessed_text''' + + return [line for _, text in self.t_filename_preprocessed_text for line in text] + + @irpy.lazy_property + def d_type_lines(self): + + from collections import defaultdict + d = defaultdict(list) + for i, line in enumerate(self.l_preprocessed_text): + d[type(line)] += [(i, line)] + return d + + @irpy.lazy_property + def d_entity(self): + # None -> Dict[Str,Entity] + '''And entity is a collection of line between BEGIN_PROVIDER and END_PROVIDER ''' + from irpf90_t import Begin_provider, End_provider + from entity import Entity + + l_begin = [i for i, line in self.d_type_lines[Begin_provider]] + l_end = [i for i, line in self.d_type_lines[End_provider]] + l_provider = [ self.l_preprocessed_text[begin:end] for begin, end in zip(l_begin, l_end)] + + + l_ent = [] + for icount, buf in enumerate(l_provider): + from functools import partial + Ent_part = partial(Entity,buf,icount,comm_world=self) + + ent = Ent_part() + l_ent += [ent] + [Ent_part(other) for other in ent.others_entity_name] + + # O(2) but who care + l_duplicate = [x for x in l_ent if l_ent.count(x) > 1] + if l_duplicate: + from util import logger + logger.error('You have duplicate PROVIDER: %s' % ' '.join([e.name for e in l_duplicate])) + import sys + sys.exit(1) + + # Python 2.6 Don't allow list comprehesion + d_ent = dict() + for e in l_ent: + d_ent[e.name] = e + + # + # Second pass + # + # Modify parameter of variables + + # Touch Softouch + def find_variable(line): + l_var = line.lower.split()[1:] + if len(l_var) < 1: + error.fail(line, "Syntax error") + + if any(v for v in l_var if v not in d_ent): + error.fail(line, "Variable %s unknown" % (v, )) + return l_var + + + d_modif = dict() + from irpf90_t import Touch, SoftTouch, Free + from util import flatten + for cmd, l_type in [('is_self_touched', [Touch, SoftTouch]), + ('is_free', [Free])]: + + l_line = flatten( [self.d_type_lines[type_] for type_ in l_type]) + l_name = flatten( [find_variable(line) for _, line in l_line]) + d_modif[cmd] = l_name + + # Read and Write + from irpf90_t import Irp_read, Irp_write + for cmd, type_ in [('is_read', Irp_read), ('is_written', Irp_write)]: + l_name = [line.filename for _, line in self.d_type_lines[type_]] + d_modif[cmd] = l_name + + #Do the modifcation + for cmd, l_name in d_modif.items(): + for name in l_name: + setattr(d_ent[name], cmd, True) + + return d_ent + + @irpy.lazy_property_mutable + def d_routine(self): + ''' + Dictionnary name -> Routine object. + Routine is a collection of line between Subroutine / Function + ''' + + + # ~#~#~#~#~# + # Create the dict + # ~#~#~#~#~# + + from irpf90_t import Subroutine, Function, Program, End + d_type = self.d_type_lines + l_begin = sorted(i for type_ in (Subroutine, Function, Program) for i, _ in d_type[type_]) + l_end = [i for i, _ in d_type[End]] + + from routine import Routine + text = self.l_preprocessed_text + l_rou = [ Routine(text[b:e]) for b, e in zip(l_begin, l_end) if not isinstance(text[b], Program)] + + # Now we can create a dict and at it + d_rou = dict() + for s in l_rou: + d_rou[s.name] = s + + # ~#~#~#~#~# + # Finish the initialization of the routine + # ~#~#~#~#~# + + from collections import defaultdict + d_called_by = defaultdict(set) + + for entity in self.d_entity.values(): + name = entity.name + if entity.same_as == name: + for x in entity.calls: + d_called_by[x].add(name) + + from util import uniquify + for routine in d_rou.values(): + for x in routine.calls: + d_called_by[x].add(routine.name) + + for routine in d_rou.values(): + routine.called_by = sorted(d_called_by[routine.name]) + + l_set = [d_rou[name].touches_my_self for name in routine.calls if name in d_rou] + routine.touches_ancestor = set().union(*l_set) + + return d_rou + + @irpy.lazy_property + def t_filename_parsed_text(self): + '''(filename,parsed_text)''' + d_entity = self.d_entity + d_routine = self.d_routine + + import parsed_text + vtuple = [(v, s.same_as, s.regexp) for v, s in d_entity.iteritems()] + def worker_parsed(filename_text): + filename, text = filename_text + return parsed_text.get_parsed_text(filename, text, d_entity, d_routine, vtuple) + + parsed_text_0 = parmap(worker_parsed, self.t_filename_preprocessed_text) + + + from irpf90_t import NoDep,Declaration,Implicit,Use,Cont_provider + def moved_to_top_l(ptext): + l = [NoDep, Declaration, Implicit, Use, Cont_provider] + for _, text in ptext: + parsed_text.move_to_top_list(text, l) + + #Touch routine + parsed_text.build_sub_needs(parsed_text_0, d_routine) + moved_to_top_l(parsed_text_0) + + parsed_text_1 = parsed_text.add_subroutine_needs(parsed_text_0, d_routine) + parsed_text_1 = parsed_text.move_variables(parsed_text_1) + + moved_to_top_l(parsed_text_1) + + parsed_text.check_opt(parsed_text_1) + parsed_text_1 = parsed_text.perform_loop_substitutions(parsed_text_1) + + #touch entity + stuple = [(s, v.regexp) for s, v in d_routine.iteritems() if v.is_function] + parsed_text.build_needs(parsed_text_1, d_routine, stuple,d_entity) + + return parsed_text_1 + + @irpy.lazy_property + def d_module(self): + from module import Fmodule + result = dict() + for filename, text in self.t_filename_parsed_text: + result[filename] = Fmodule(text, filename,self.d_entity) + + return result + + def write_modules(self): + from irpf90_t import irpdir + from util import lazy_write_file + import os + + for m in self.d_module.values(): + # Module data + if m.has_irp_module: + filename = os.path.join(irpdir, '%s.irp.module.F90' % m.filename) + text = '\n'.join(m.header + m.head) + lazy_write_file(filename, '%s\n' % text) + + # Subroutines + filename = os.path.join(irpdir, '%s.irp.F90' % m.filename) + text = '\n'.join(m.header + m.generated_text + m.residual_text) + lazy_write_file(filename, '%s\n' % text) + + def create_stack(self): + import irp_stack + irp_stack.create() + + def create_buildfile(self,ninja): + import build_file + build_file.run(self.d_module,ninja) + + def create_touches(self): + import touches + touches.create(self.d_module, self.d_entity) + + def create_man(self): + import create_man as c_man + c_man.run(self.d_entity, self.d_routine) + + + def create_lock(self): + from util import lazy_write_file + l = sorted(self.d_entity.keys()) + + out = [] + for v in l: + out += self.d_entity[v].locker + + out += [ "subroutine irp_init_locks_%s()"%(irpf90_t.irp_id), + " implicit none" ] + for v in l: + out += [ " call irp_lock_%s(.True.)"%v ] + out += [ " call irp_lock_%s(.False.)"%v ] + out += [ "end subroutine", "" ] + + filename = os.path.join(irpf90_t.irpdir,'irp_locks.irp.F90') + lazy_write_file(filename, '\n'.join(out)) + diff --git a/src/lib_irpy.py b/src/lib_irpy.py new file mode 100755 index 0000000..574ca3c --- /dev/null +++ b/src/lib_irpy.py @@ -0,0 +1,160 @@ +#Handle the execution stack +from collections import defaultdict +d_path = defaultdict(list) +d_last_caller = defaultdict(lambda: None) + +def genealogy(obj, _node, direction,degree_max=100): + """Return the genealogy of a _node. + Direction is $parents or $children, recurse accordingly""" + + def sap(_node, direction, visited=set(), degree=0): + + visited.add(_node) + try: + s = getattr(obj, "{0}_{1}".format(_node, direction)) + except AttributeError: + s = set() + + for next_ in s - visited: + + if degree < degree_max: + sap(next_, direction, visited, degree+1) + + return visited + + s = sap(_node, direction) - set([_node]) + + return s + + +def addattr(obj, name, value): + try: + s = getattr(obj, name) + except AttributeError: + setattr(obj, name, set([value])) + else: + setattr(obj, name, s | set([value])) + +def removeattr(obj, name, value): + try: + s = getattr(obj, name) + except AttributeError: + pass + else: + setattr(obj, name, s - set([value])) + + +# _ +# | \ _ _ _ ._ _. _|_ _ ._ +# |_/ (/_ (_ (_) | (_| |_ (_) | +# +class lazy_property(object): + """ + My little Property + My little Property + My little Property... friend + """ + + def __init__(self, provider, init_node=False, immutable=True): + """Provider: If a function who will be used to compute the node + init_node: If the name of the node + immutable: If immutable is set you cannot set the node""" + + self.provider = provider + self.init_node = init_node + self.immutable = immutable + + if not self.init_node: + name = provider.__name__ + else: + name = self.init_node + + #Kind of human readable identifier + self._node = "_%s_%s" % (name, id(provider)) + + def __get__(self, obj, objtype): + "Get the value of the node and handle the genealogy" + + _node = self._node + + if d_path[obj]: + _caller = d_path[obj][-1] + if _caller != d_last_caller[obj]: + addattr(obj, "%s_parents" % _node, _caller) + addattr(obj, "%s_children" % _caller, _node) + d_last_caller[obj] = _caller + + #Wanted: value. Cached or Computed + try: + value = getattr(obj, _node) + except AttributeError: + + d_path[obj].append(_node) + + value = self.provider(obj) + setattr(obj, _node, value) + + d_path[obj].pop() + + return value + + def __set__(self, obj, value): + """Set the value of the node + But wait, init_node are "gradual typed" variable! Youpi! + Idea borrowed from the-worst-programming-language-ever (http://bit.ly/13tc6XW) + """ + + _node = self._node + + if not self.init_node: + + if self.immutable: + raise AttributeError("Immutable Node {0}".format(self._node)) + + #Set the new value + setattr(obj, _node, value) + + #Node ancestor need to be recompute is asked + for _parent in genealogy(obj, _node, "parents"): + if hasattr(obj, _parent): delattr(obj, _parent) + + #Node abandoned her children, + for _child in genealogy(obj, _node, "children",degree_max=1): + removeattr(obj, "%s_parents" % _child, _node) + + #Indeed node is now a leaf + setattr(obj, "%s_children" % _node, set()) + + else: + setattr(obj, _node, value) + self.init_node = False + + +def lazy_property_mutable(provider): + "Return a lazy_property mutable" + return lazy_property(provider=provider, immutable=False) + + +def lazy_property_leaves(mutables=(), immutables=()): + "Set to properties for the __init__ method" + + def leaf_decorator(func): + def func_wrapper(self, *args, **kwargs): + + for node in set(immutables) | set(mutables): + + def provider(self): + return getattr(self, "_%s" % node) + + p = lazy_property(provider=provider, + init_node=node, + immutable=node in immutables) + + #If this ugly? Yeah... Is this an issue? I don't really know + setattr(self.__class__, node, p) + + return func(self, *args, **kwargs) + + return func_wrapper + + return leaf_decorator diff --git a/src/makefile.py b/src/makefile.py deleted file mode 100644 index 5f4339b..0000000 --- a/src/makefile.py +++ /dev/null @@ -1,204 +0,0 @@ -#!/usr/bin/env python -# IRPF90 is a Fortran90 preprocessor written in Python for programming using -# the Implicit Reference to Parameters (IRP) method. -# Copyright (C) 2009 Anthony SCEMAMA -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Anthony Scemama -# LCPQ - IRSAMC - CNRS -# Universite Paul Sabatier -# 118, route de Narbonne -# 31062 Toulouse Cedex 4 -# scemama@irsamc.ups-tlse.fr - - -import os,sys -import irpf90_t -from command_line import command_line -irpdir = irpf90_t.irpdir -mandir = irpf90_t.mandir - -FILENAME = "Makefile" -FILENAME_GITIGNORE = ".gitignore" -IRPF90_MAKE = "irpf90.make" - -###################################################################### -def create(): - has_makefile = True - try: - file = open(FILENAME,"r") - except IOError: - has_makefile = False - if has_makefile: - return - file = open(FILENAME,"w") - t = """IRPF90 = irpf90 #-a -d -FC = gfortran -FCFLAGS= -O2 -ffree-line-length-none -I . -NINJA = ninja -AR = ar -RANLIB = ranlib - -SRC= -OBJ= -LIB= - -include %s -export - -%s: $(filter-out %s%%, $(wildcard */*.irp.f)) $(wildcard *.irp.f) $(wildcard *.inc.f) Makefile -\t$(IRPF90) -"""%(IRPF90_MAKE,IRPF90_MAKE,irpdir) - file.write(t) - file.close() - create_gitignore() - -###################################################################### -def create_gitignore(): - has_makefile = True - try: - file = open(FILENAME_GITIGNORE,"r") - except IOError: - has_makefile = False - if has_makefile: - return - file = open(FILENAME_GITIGNORE,"w") - t = "\n".join([ irpdir, mandir, IRPF90_MAKE, 'irpf90_entities', 'tags' ]) - file.write(t) - file.close() - -###################################################################### -def run_ninja(): - import ninja - ninja.run() - -###################################################################### -def run_make(): - from modules import modules - mod = [] - for m in modules.values(): - mod.append(m) - - file = open(IRPF90_MAKE,'w') - result = "" - result += "FC+=-I %s "%(irpdir) - for i in command_line.include_dir: - result += "-I %s%s "%(irpdir,i) - result += "\n" - result += "SRC += %sirp_stack.irp.F90"%(irpdir) - result += " %sirp_touches.irp.F90"%(irpdir) -# result += " %sirp_checkpoint.irp.F90"%(irpdir) - if command_line.do_openmp: - result += " %sirp_locks.irp.F90"%(irpdir) - if command_line.do_profile: - result += " %sirp_profile.irp.F90"%(irpdir) - for m in mod: - result += " %s%s.irp.F90"%(irpdir,m.filename) - result += " %s%s.irp.module.F90"%(irpdir,m.filename) - print >>file, result - - result = "OBJ_IRP = %sirp_stack.irp.o "%(irpdir) - for m in mod: - if not m.is_main: - result += " %s%s.irp.o"%(irpdir,m.filename) - result += " %s%s.irp.module.o"%(irpdir,m.filename) - print >>file, result - - print >>file, "OBJ1 = $(OBJ_IRP) $(OBJ) %sirp_touches.irp.o "%(irpdir), -# print >>file, " %sirp_checkpoint.irp.o"%(irpdir), - if command_line.do_profile: - print >>file, " %sirp_profile.irp.o"%(irpdir), " irp_rdtsc.o", - if command_line.do_codelet: - print >>file, " irp_rdtsc.o", - if command_line.do_openmp: - print >>file, " %sirp_locks.irp.o"%(irpdir) - else: - print >>file, "" - - all = filter(lambda x: modules[x].is_main, modules) - all = map(lambda x: x[:-6], all) - all_o = map(lambda x: "%s.irp.module.o %s.irp.o"%(x,x), all) - print >>file, "ALL = %s"%(" ".join(all)) - print >>file, "ALL_OBJ = %s"%(" ".join(all_o)) - print >>file, "ALL_OBJ1 = $(patsubst %%, %s%%,$(notdir $(ALL_OBJ)))"%(irpdir) - print >>file, "all:$(ALL)" - print >>file, "\t@$(MAKE) -s move" -# print >>file, "ifdef USE_IRPF90_A" - for m in mod: - if m.is_main: - exe = m.filename - print >>file, "%s: %s%s.irp.o %s%s.irp.module.o IRPF90_temp/irpf90.a"%(exe,irpdir,exe,irpdir,exe) - print >>file, "\t$(FC) -o $@ %s$@.irp.o %s$@.irp.module.o IRPF90_temp/irpf90.a $(LIB)"%(irpdir,irpdir) - print >>file, "\t@$(MAKE) -s move" -# print >>file, "else" -# for m in mod: -# if m.is_main: -# exe = m.filename -# print >>file, "%s: %s%s.irp.o %s%s.irp.module.o $(OBJ1)"%(exe,irpdir,exe,irpdir,exe) -# print >>file, "\t$(FC) -o $@ %s$@.irp.o %s$@.irp.module.o $(OBJ1) $(LIB)"%(irpdir,irpdir) -# print >>file, "\t@$(MAKE) -s move" -# print >>file, "endif" - - buffer = "" - for m in mod: - filename = "%s%s.irp.o: $(OBJ) %s%s.irp.module.o"%(irpdir,m.filename,irpdir,m.filename) - needed_modules = filter( lambda x: modules[x].name in m.needed_modules, modules ) - needed_files = map(lambda x: modules[x].filename, needed_modules) - mds = map (lambda x: " %s%s.irp.module.o"%(irpdir,x),needed_files) - print >>file, filename," ".join(mds)," ".join(m.includes) - if not m.is_main: - buffer += "\t - @echo '"+filename+" ".join(mds)+"' >> %sdist_Makefile\n"%(irpdir) -# print >>file, "%sirp_touches.irp.o %sirp_checkpoint.irp.o: $(OBJ) "%(irpdir,irpdir), - print >>file, "%sirp_touches.irp.o: $(OBJ) "%(irpdir), - mds = filter(lambda x: not x.is_main,mod) - mds = map(lambda x: " %s%s.irp.o %s%s.irp.o"%(irpdir,x.filename,irpdir,x.filename),mds) - print >>file," ".join(mds) - if command_line.do_profile: - print >>file, "%sirp_profile.irp.o:"%(irpdir), - print >>file," ".join(mds) - if command_line.do_openmp: - print >>file, "%sirp_locks.irp.o:"%(irpdir), - print >>file," ".join(mds) - - - for dir in [ irpdir ] + map(lambda x: irpdir+x, command_line.include_dir): - print >>file, dir+"%.irp.module.o: $(OBJ) "+dir+"%.irp.module.F90" - print >>file, "\t$(FC) $(FCFLAGS) -c "+dir+"$*.irp.module.F90 -o "+dir+"$*.irp.module.o" - print >>file, dir+"%.irp.o: $(OBJ) "+dir+"%.irp.module.o "+dir+"%.irp.F90" - print >>file, "\t$(FC) $(FCFLAGS) -c "+dir+"$*.irp.F90 -o "+dir+"$*.irp.o" - print >>file, dir+"%.irp.o: $(OBJ) "+dir+"%.irp.F90" - print >>file, "\t$(FC) $(FCFLAGS) -c "+dir+"$*.irp.F90 -o "+dir+"$*.irp.o" - print >>file, dir+"%.o: %.F90" - print >>file, "\t$(FC) $(FCFLAGS) -c $*.F90 -o "+dir+"$*.o" - print >>file, dir+"%.o: %.f90\n\t$(FC) $(FCFLAGS) -c $*.f90 -o "+dir+"$*.o" - print >>file, dir+"%.o: %.f\n\t$(FC) $(FCFLAGS) -c $*.f -o "+dir+"$*.o" - print >>file, dir+"%.o: %.F\n\t$(FC) $(FCFLAGS) -c $*.F -o "+dir+"$*.o" - print >>file, dir+"%.irp.F90: "+IRPF90_MAKE+"\n" - print >>file, "move:\n\t@mv -f *.mod IRPF90_temp/ 2> /dev/null | DO_NOTHING=\n" - print >>file, "IRPF90_temp/irpf90.a: $(OBJ) $(OBJ1)\n\t$(AR) crf IRPF90_temp/irpf90.a $(OBJ1)\n" - print >>file, "clean:\n\trm -rf $(EXE) $(OBJ1) IRPF90_temp/irpf90.a $(ALL_OBJ1) $(ALL)\n" - print >>file, "veryclean:\n\t- $(MAKE) clean\n" - print >>file, "\t- rm -rf "+irpdir+" "+mandir+" "+IRPF90_MAKE+" irpf90_entities dist tags\n" - - file.close() - -###################################################################### -def run(): - if command_line.do_ninja: - run_ninja() - else: - run_make() - diff --git a/src/module.py b/src/module.py index 5f761ed..75fa1aa 100644 --- a/src/module.py +++ b/src/module.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/unr/bin/env python # IRPF90 is a Fortran90 preprocessor written in Python for programming using # the Implicit Reference to Parameters (IRP) method. # Copyright (C) 2009 Anthony SCEMAMA @@ -24,204 +24,246 @@ # 31062 Toulouse Cedex 4 # scemama@irsamc.ups-tlse.fr - from irpf90_t import * -from variable import * -from variables import variables from command_line import command_line import preprocessed_text from util import * +from entity import Entity + +def put_info(text, filename): + + lenmax = 80 - len(filename) + format_ = "%" + str(lenmax) + "s ! %s:%4s" + + str_ = '{text:{width}} ! {filename}:{i:4}' + for _, line in text: + line.text = str_.format(text=line.text,filename=line.filename,i=line.i,width=lenmax) + return text + class Fmodule(object): - header = \ - [ "! -*- F90 -*-", - "!", - "!-----------------------------------------------!", - "! This file was generated with the irpf90 tool. !", - "! !", - "! DO NOT MODIFY IT BY HAND !", - "!-----------------------------------------------!", - "" ] + header = [ "! -*- F90 -*-", + "!", + "!-----------------------------------------------!", + "! This file was generated with the irpf90 tool. !", + "! !", + "! DO NOT MODIFY IT BY HAND !", + "!-----------------------------------------------!", + ""] - def __init__(self,text,filename): - self.text = put_info(text,filename) - self.filename = filename[:-6] - self.name = "%s_mod"%(self.filename).replace('/','__').replace('.','Dot') + def __init__(self, text, filename, d_variable): + self.text = put_info(text, filename) + self.filename = filename[:-6] + self.name = "%s_mod" % (self.filename).replace('/', '__').replace('.', 'Dot') + self.d_all_variable = d_variable - def is_main(self): - if '_is_main' not in self.__dict__: - self._is_main = self.prog_name is not None - return self._is_main - is_main = property(is_main) + @irpy.lazy_property + def prog_name(self): + l = [line.filename for _, line in self.text if isinstance(line, Program)] + return l.pop() if l else None - def prog_name(self): - if '_prog_name' not in self.__dict__: - buffer = filter(lambda x: type(x[1]) == Program,self.text) - if buffer == []: - self._prog_name = None - else: - self._prog_name = buffer[0][1].filename - return self._prog_name - prog_name = property(prog_name) + @irpy.lazy_property + def is_main(self): + return self.prog_name is not None - def variables(self): - if '_variables' not in self.__dict__: - from variables import variables - name = self.name - self._variables = filter(lambda x: variables[x].fmodule == name, variables) - return self._variables - variables = property(variables) + @irpy.lazy_property + def l_entity(self): + return [value for value in self.d_all_variable.values() if value.fmodule == self.name] + + @irpy.lazy_property + def head(self): + '''The module who containt the declaration of the entity''' + body = list(self.use) + body += list(self.dec) + body += [header for var in self.l_entity for header in var.header] - def head(self): - if '_head' not in self.__dict__: - result = [ "module %s"%(self.name) ] - result += self.use - result += self.dec - result += flatten( map(lambda x: variables[x].header,self.variables) ) - result.append( "end module %s"%(self.name) ) - self._head = result - return self._head - head = property(head) + if body: + result = ["module %s" % (self.name)] + result += body + result += ["end module %s" % (self.name)] + else: + result = [] - def needed_vars(self): - if '_needed_vars' not in self.__dict__: - result = map(lambda x: variables[x].needs,self.variables) - result = make_single ( flatten(result) ) - self._needed_vars = result - return self._needed_vars - needed_vars = property(needed_vars) + return result - def includes(self): - if '_includes' not in self.__dict__: - buffer = [] - for v in self.needed_vars: - buffer += variables[v].includes - self._includes = make_single(buffer) - return self._includes - includes = property(includes) + @irpy.lazy_property + def has_irp_module(self): + return bool(self.head) - def generated_text(self): - if '_generated_text' not in self.__dict__: - result = [] - for var in self.variables: - var = variables[var] - result += var.provider - result += var.builder - if var.is_read: - result += var.reader - if var.is_written: - result += var.writer - self._generated_text = result - return self._generated_text - generated_text = property(generated_text) + @irpy.lazy_property + def needed_vars(self): + return set(n for var in self.l_entity for n in var.needs) - def residual_text(self): - if '_residual_text' not in self.__dict__: - from variables import build_use, call_provides - from parsed_text import move_to_top - def remove_providers(text): + @irpy.lazy_property + def includes(self): + return set(i for var in self.needed_vars for i in self.d_all_variable[var].includes) + + @irpy.lazy_property + def generated_text(self): + 'Routine genereraed by the IRPF90. provide, build, ...' result = [] - inside = False - for vars,line in text: - if type(line) == Begin_provider: - inside = True - if not inside: - result.append( (vars,line) ) - if type(line) == End_provider: + for var in self.l_entity: + result += var.provider + result += var.builder + if var.is_read: + result += var.reader + if var.is_written: + result += var.writer + + return result + + @irpy.lazy_property + def residual_text_use_dec(self): + + def remove_providers(text): + result = [] inside = False - return result - def modify_functions(text): + for vars, line in text: + if type(line) == Begin_provider: + inside = True + if not inside: + result.append((vars, line)) + if type(line) == End_provider: + inside = False + return result + + def modify_functions(text): + + result = [] + variable_list = [] + skip_interface = False + for vars, line in text: + if type(line) in [Interface, End_interface]: + skip_interface = not skip_interface + + if skip_interface: + result.append((vars, line)) + continue + + + if type(line) in [Subroutine, Function, Program]: + #Deep copy... + variable_list = list(vars) + elif type(line) == End: + result += [([], Use(line.i, x, line.filename)) for x in build_use(variable_list, self.d_all_variable)] + else: + variable_list += vars + + result.append((vars, line)) + return result + + def extract_use_dec_text(text): + # (List[ Tuple(Entity,Line) ]) -> (List[ Tuple(Entity,Line),List[ Tuple(Entity,Line),List[ Tuple(Entity,Line)) + '''Extract the global declaration statement and module use form the declaration of function. ''' + + inside = 0 + result,dec,use,module = [],[],[],[] + + for vars, line in text: + + if isinstance(line, (Subroutine, Function, Program,Interface,Module)): + inside += 1 + + if type(line) == Module: + module.append((vars,line)) + + if inside: + result.append((vars, line)) + else: + if type(line) == Use: + use.append((vars, line)) + elif type(line) == Declaration: + dec.append((vars, line)) + + + if isinstance(line,(End,End_interface,End_module)): + inside += -1 + + if inside: + print 'Something wrong append' + sys.exit(1) + + return use, module, dec, result + + result = remove_providers(self.text) + result = modify_functions(result) + + from collections import namedtuple + Residual_text_use_dec = namedtuple('Residual_text_use_dec', ['use', 'module', 'dec', 'result']) + + return Residual_text_use_dec(*extract_use_dec_text(result)) + + @irpy.lazy_property + def use(self): + return set(" %s" % line.text for _, line in self.residual_text_use_dec.use) + + @irpy.lazy_property + def gen_mod(self): + '''List of module generated by the user in this module...''' + return set("%s" % line.subname for _, line in self.residual_text_use_dec.module) + + @irpy.lazy_property + def dec(self): + '''The declaration of this module + + Note: + Because user can define F90 Type, we need to keep the correct order. + + Warning: + If we uniquify that can cause a problem with the type in guess. + ```type toto + integer :: n + end type toto + integer :: n + ``` + Fix: + We need to support Type keyword. + + ''' + + l = [" %s" % line.text for _, line in self.residual_text_use_dec.dec] + from util import uniquify + if len(l) != len(uniquify(l)): + raise NotImplementedError + + return l + + @irpy.lazy_property + def residual_text(self): + '''Not the generated function (build, provide, touch, etc.)''' + result = [] - variable_list = [] - for vars,line in text: - if type(line) in [ Subroutine, Function ]: - variable_list = list(vars) - elif type(line) == End: - result += map(lambda x: ([],Use(line.i,x,line.filename)), build_use(variable_list)) - else: - variable_list += vars - result.append( (vars,line) ) - return result - - def extract_use_dec_text(text): - inside = False - result = [] - dec = [] - use = [] - for vars,line in text: - if type(line) in [ Subroutine, Function, Program]: - inside = True - if inside: - result.append( (vars,line) ) - else: - if type(line) == Use: - use.append( (vars,line) ) - elif type(line) == Declaration: - dec.append( (vars,line) ) - if type(line) == End: - inside = False - return use, dec, result - - def provide_variables(text): - result = [] - for vars,line in text: - result.append( ([],line) ) - result += map(lambda x: ([],Simple_line(line.i,x,line.filename)), call_provides(vars)) - return result - - result = remove_providers(self.text) - result = modify_functions(result) - use,dec,result = extract_use_dec_text(result) - self._use = make_single(map(lambda x: " "+x[1].text, use)) - self._dec = map(lambda x: " "+x[1].text, dec) -# self._dec = make_single(map(lambda x: " "+x[1].text, dec)) - result = provide_variables(result) - result = move_to_top(result,Declaration) - result = move_to_top(result,Implicit) - result = move_to_top(result,Use) - result = map(lambda x: x[1], result) - result = map(lambda x: x.text, result) - self._residual_text = result - return self._residual_text - residual_text = property(residual_text) - - def use(self): - if '_use' not in self.__dict__: - self.residual_text - return self._use - use = property(use) - - def dec(self): - if '_dec' not in self.__dict__: - self.residual_text - return self._dec - dec = property(dec) + for vars, line in self.residual_text_use_dec.result: + result.append(([], line)) + result += map(lambda x: ([], Simple_line(line.i, x, line.filename)), + build_call_provide(vars, self.d_all_variable)) - def needed_modules(self): - if '_needed_modules' not in self.__dict__: - buffer = filter(lambda x: x.lstrip().startswith("use "), \ - self.generated_text+self.head+self.residual_text) - buffer = map(lambda x: x.split()[1], buffer) - buffer = filter(lambda x: x.endswith("_mod"),buffer ) - self._needed_modules = make_single(buffer) - if self.name in self._needed_modules: - self._needed_modules.remove(self.name) - return self._needed_modules - needed_modules = property(needed_modules) + from parsed_text import move_to_top_list, move_interface + move_to_top_list(result, [Declaration, Implicit, Use]) + move_interface(result) -###################################################################### + return [line.text for _, line in result] + + @irpy.lazy_property + def needed_modules(self): + l = set(x.split(',only').pop(0).split()[1] for x in self.generated_text + self.head + self.residual_text if x.lstrip().startswith("use ")) + + if self.name in l: + l.remove(self.name) + + return l + + + @irpy.lazy_property + def needed_modules_irp(self): + return [i for i in self.needed_modules if i.endswith("_mod")] + + @irpy.lazy_property + def needed_modules_usr(self): + return [i for i in self.needed_modules if not i.endswith("_mod")] -if __name__ == '__main__': - from parsed_text import parsed_text - for filename, text in parsed_text: - if filename == 'vmc_step.irp.f': - x = Fmodule(text,filename) - break - for line in x.head: - print line - print x.includes diff --git a/src/modules.py b/src/modules.py deleted file mode 100644 index 9a18051..0000000 --- a/src/modules.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python -# IRPF90 is a Fortran90 preprocessor written in Python for programming using -# the Implicit Reference to Parameters (IRP) method. -# Copyright (C) 2009 Anthony SCEMAMA -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Anthony Scemama -# LCPQ - IRSAMC - CNRS -# Universite Paul Sabatier -# 118, route de Narbonne -# 31062 Toulouse Cedex 4 -# scemama@irsamc.ups-tlse.fr - - -from irpf90_t import * -from parsed_text import parsed_text -from module import Fmodule -from util import * - -###################################################################### -def create_modules(): - result = {} - for filename,text in parsed_text: - result[filename] = Fmodule(text,filename) - return result - -modules = create_modules() - -###################################################################### -def write_module(m): - # Module data - filename = irpdir+m.filename+".irp.module.F90" - text = m.header + m.head - text = map(lambda x: "%s\n"%(x),text) - if not same_file(filename,text): -# print filename - file = open(filename,"w") - file.writelines(text) - file.close() - - # Subroutines - filename = irpdir+m.filename+".irp.F90" - text = m.header + m.generated_text + m.residual_text - text = map(lambda x: "%s\n"%(x),text) - if not same_file(filename,text): -# print filename - file = open(filename,"w") - file.writelines(text) - file.close() - -###################################################################### -if __name__ == '__main__': - write_module(modules['psi.irp.f']) - - diff --git a/src/ninja.py b/src/ninja.py deleted file mode 100644 index f8c44e0..0000000 --- a/src/ninja.py +++ /dev/null @@ -1,408 +0,0 @@ -#!/usr/bin/env python -# IRPF90 is a Fortran90 preprocessor written in Python for programming using -# the Implicit Reference to Parameters (IRP) method. -# Copyright (C) 2009 Anthony SCEMAMA -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Anthony Scemama -# LCPQ - IRSAMC - CNRS -# Universite Paul Sabatier -# 118, route de Narbonne -# 31062 Toulouse Cedex 4 -# scemama@irsamc.ups-tlse.fr - - -import os,sys -import irpf90_t -from command_line import command_line -from modules import modules -irpdir = irpf90_t.irpdir -mandir = irpf90_t.mandir -irp_id = irpf90_t.irp_id - -FILENAME = os.path.join(irpdir,"build.ninja") - -cwd = os.getcwd() - -PRINT_WIDTH=50 - -def dress(f,in_root=False): - """ - Transfoms the filename f into $PWD/IRPF90_temp/f - """ - if in_root: - result = os.path.join(cwd,f) - else: - result = os.path.join(cwd,irpdir,f) - return os.path.normpath(result) - - -def create_build_touches(list_of_other_o): - """ - Create the build command for the irp_touches.o file and the irpf90.a library. - """ - name = "irp_touches" - short_lib = "irpf90.a" - short_target_o = "%s.irp.o"%name - short_target_F90 = "%s.irp.F90"%name - lib = dress(short_lib) - target_o = dress(short_target_o) - target_F90 = dress(short_target_F90) - - needed_modules = [ "%s.irp.module.o"%(modules[x].filename) for x in modules ] - - list_of_modules = map(dress, needed_modules) + list_of_other_o - list_of_modules = ' '.join(list_of_modules) - - result = '\n'.join( - [ - "build {target_o}: compile_touches_{id} {target_F90} | {list_of_modules}", - " short_in = {short_target_F90}", - " short_out = {short_target_o}", - "", - "build {lib}: link_lib_{id} {target_o} {list_of_modules}", - " short_out = {short_lib}", - "", - ] ) - - result = result.format( - id = irp_id , - lib = lib , - list_of_modules = list_of_modules , - short_lib = short_lib , - short_target_F90 = os.path.split(target_F90)[1] , - short_target_o = os.path.split(target_o)[1] , - target_F90 = target_F90 , - target_o = target_o - ) - return result - -def create_build_target(t,list_of_other_o): - """ - Create the build command for the target module t. t is a Fmodule object. - """ - name = t.filename - - irp_lib = dress("irpf90.a") - target = dress(name,in_root=True) - short_target_o = "%s.irp.o"%name - short_target_F90 = "%s.irp.F90"%name - short_target_module_F90 = "%s.irp.module.F90"%name - short_target_module_o = "%s.irp.module.o"%name - target_o = dress(short_target_o) - target_F90 = dress(short_target_F90) - target_module_o = dress(short_target_module_o) - target_module_F90 = dress(short_target_module_F90) - - needed_modules = [ "%s.irp.module.o"%(modules[x].filename) for x in modules \ - if modules[x].name in t.needed_modules ] + [ target_module_o ] - - list_of_o = [ target_o, target_module_o, irp_lib ] - list_of_o = ' '.join(list_of_o) - - list_of_modules = map(dress, needed_modules) + list_of_other_o - list_of_modules = ' '.join(list_of_modules) - - list_of_includes = ' '.join(map(lambda x: dress(x,in_root=True), t.includes)) - - result = '\n'.join( - [ "build {target}: link_{id} {list_of_o}", - " short_out = {short_target}", - "", - "build {target_o}: compile_fortran_{id} {target_F90} | {list_of_modules} {list_of_includes}", - " short_in = {short_target_F90}", - " short_out = {short_target_o}", - "", - "build {target_module_o}: compile_fortran_{id} {target_module_F90}", - " short_in = {short_target_module_F90}", - " short_out = {short_target_module_o}", - "", - ] ) - - result = result.format( - id = irp_id , - list_of_includes = list_of_includes , - list_of_modules = list_of_modules , - list_of_o = list_of_o , - short_target_F90 = os.path.split(target_F90)[1] , - short_target_module_F90 = os.path.split(target_module_F90)[1] , - short_target_module_o = os.path.split(target_module_o)[1] , - short_target = name , - short_target_o = os.path.split(target_o)[1] , - target_F90 = target_F90 , - target_module_F90 = target_module_F90 , - target_module_o = target_module_o , - target_o = target_o , - target = target - ) - return result - - -def create_build_non_target(t,list_of_other_o): - """ - Create the build command for the non-target module t. t is a Fmodule object. - """ - name = t.filename - - target = dress(name,in_root=True) - short_target_o = "%s.irp.o"%name - short_target_F90 = "%s.irp.F90"%name - short_target_module_F90 = "%s.irp.module.F90"%name - short_target_module_o = "%s.irp.module.o"%name - target_o = dress(short_target_o) - target_F90 = dress(short_target_F90) - target_module_o = dress(short_target_module_o) - target_module_F90 = dress(short_target_module_F90) - - needed_modules = [ "%s.irp.module.o"%(modules[x].filename) for x in modules \ - if modules[x].name in t.needed_modules ] + [ target_module_o ] - - list_of_modules = map(dress, needed_modules) - list_of_modules = ' '.join(list_of_modules) - list_of_externals = ' '.join([ dress(x,in_root=True) for x in list_of_other_o ]) - list_of_includes = ' '.join(map(lambda x: dress(x,in_root=True), t.includes)) - - result = '\n'.join( - [ - "build {target_o}: compile_fortran_{id} {target_F90} | {list_of_modules} {list_of_externals}", - " short_in = {short_target_F90}", - " short_out = {short_target}", - "", - "build {target_module_o}: compile_fortran_{id} {target_module_F90} | {list_of_externals} {list_of_includes}", - " short_in = {short_target_F90}", - " short_out = {short_target_o}", - "", - ] ) - - result = result.format( - id = irp_id , - list_of_externals = list_of_externals , - list_of_includes = list_of_includes , - list_of_modules = list_of_modules , - short_target_F90 = os.path.split(target_F90)[1] , - short_target = name , - short_target_o = os.path.split(target_o)[1] , - target_F90 = target_F90 , - target_module_F90 = target_module_F90 , - target_module_o = target_module_o , - target_o = target_o - ) - return result - - -def create_build_remaining(f): - """ - Create the build command for the remaining file f. f is a file name (str). - """ - t, extension = f.rsplit('.',1) - t1 = dress(t,in_root=True) - t2 = dress(t,in_root=False) - target_i = f - target_o = "%s.o"%t - if not target_o.startswith(os.path.join(cwd,irpdir)): - target_o = target_o.replace(cwd,os.path.join(cwd,irpdir)) - - if extension.lower() in [ 'f', 'f90' ]: - result = [ "build {target_o}: compile_fortran_{id} {target_i}" ] - elif extension.lower() in [ 'c' ]: - result = [ "build {target_o}: compile_c_{id} {target_i}" ] - elif extension.lower() in [ 'cxx', 'cpp' ]: - result = [ "build {target_o}: compile_cxx_{id} {target_i}" ] - - result += [ " short_in = {short_target_i}", - " short_out = {short_target_o}", "" ] - result = '\n'.join(result).format( - target_o = target_o, - target_i = target_i, - short_target_o = os.path.split(target_o)[1], - short_target_i = os.path.split(target_i)[1], - id = irp_id - ) - return result - - - -def create_irpf90_make(targets): - targets = ' '.join(targets) - result = """NINJA += -C {0} - -TARGETS={1} - -.PHONY: all clean veryclean - -all: - $(NINJA) - -$(TARGETS): - $(NINJA) $(PWD)/$@ - -clean: - $(NINJA) -t clean - -veryclean: clean - rm -rf IRPF90_temp/ IRPF90_man/ irpf90.make irpf90_entities dist tags - -""".format(irpdir, targets) - - import makefile - with open(makefile.IRPF90_MAKE,'w') as file: - file.write(result) - - -def run(): - - output = [ "builddir = %s"%os.path.join(cwd,irpdir) ] - - # Environment variables - - try: FC = os.environ["FC"] - except KeyError: FC="gfortran -ffree-line-length-none" - - try: AR = os.environ["AR"] - except KeyError: AR="ar" - - try: CC = os.environ["CC"] - except KeyError: CC="gcc" - - try: CXX = os.environ["CXX"] - except KeyError: CXX="g++" - - includes = [ "-I %s"%(i) for i in command_line.include_dir ] - - FC += " "+' '.join(includes) - CC += " "+' '.join(includes) - CXX += " "+' '.join(includes) - - try: SRC = os.environ["SRC"].split() - except KeyError: SRC=[] - - try: OBJ = os.environ["OBJ"].split() - except KeyError: OBJ=[] - - try: LIB = os.environ["LIB"].split() - except KeyError: LIB=[] - - try: FCFLAGS = os.environ["FCFLAGS"].split() - except KeyError: FCFLAGS = [ "-O2" ] - - try: CFLAGS = os.environ["CFLAGS"].split() - except KeyError: CFLAGS = [ "-O2" ] - - try: CXXFLAGS = os.environ["CXXFLAGS"].split() - except KeyError: CXXFLAGS = [ "-O2" ] - - FCFLAGS = ' '.join(FCFLAGS) - CFLAGS = ' '.join(CFLAGS) - CXXFLAGS = ' '.join(CXXFLAGS) - LIB = ' '.join(LIB) - - # Rules - - t = [ "rule compile_fortran_{id}", - " command = {FC} {FCFLAGS} -c $in -o $out", - " description = F : $short_in -> $short_out", - "", - "rule compile_touches_{id}", - " command = {FC} -c $in -o $out", - " description = F : $short_in -> $short_out", - "", - "", - "rule compile_c_{id}" , - " command = {CC} {CFLAGS} -c $in -o $out", - " description = C : $short_in -> $short_out", - "", - "rule compile_cxx_{id}", - " command = {CXX} {CXXFLAGS} -c $in -o $out", - " description = C++ : $short_in -> $short_out", - "", - "rule link_lib_{id}", - " command = {AR} crf $out $in" , - " description = Link: $short_out", - "", - "rule link_{id}", - " command = {FC} $in {LIB} -o $out" , - " description = Link: $short_out"] - - output += [ '\n'.join(t).format(id=irp_id, FC=FC, FCFLAGS=FCFLAGS, LIB=LIB, CXX=CXX, CXXFLAGS=CXXFLAGS, CC=CC, CFLAGS=CFLAGS, AR=AR) ] - - - # All modules : list of Fmodule objects - - l_mod = list( modules.values() ) - - - # Modules that are not targets - - l_non_targets = [ x for x in l_mod if not x.is_main ] - - - - - # Common object/source files - - l_common_o = [ "irp_touches.irp.o" ] + \ - [ "{0}.irp.o".format(x.filename) for x in l_non_targets ] + \ - [ "{0}.irp.module.o".format(x.filename) for x in l_non_targets ] - - - l_common_s = [] - - if command_line.do_assert: - l_common_o += [ "irp_stack.irp.o" ] - l_common_s += [ "irp_stack.irp.F90" ] - - if command_line.do_openmp: - l_common_o += [ "irp_locks.irp.o" ] - l_common_s += [ "irp_locks.irp.F90" ] - - if command_line.do_profile: - l_common_o += [ "irp_profile.irp.o", "rdtsc.o" ] - l_common_s += [ "irp_profile.irp.F90", "rdtsc.c" ] - - l_common_o = map(dress,l_common_o) + map(lambda x: dress(x,in_root=True), OBJ) - l_common_s = map(dress,l_common_s) + map(lambda x: dress(x,in_root=True), SRC) - - - # IRP_touches - output.append(create_build_touches(l_common_o[1:])) - - # All targets : list of Fmodule objects - - l_targets = [ x for x in l_mod if x.is_main ] - - - # Create lines - - for i in l_non_targets: - output.append (create_build_non_target(i,OBJ)) - - for i in l_targets: - output.append(create_build_target(i, l_common_o)) - - # Remaining files - for i in l_common_s: - output.append(create_build_remaining(i)) - - - with open(FILENAME,'w') as f: - f.write('\n\n'.join(output)) - f.write('\n') - - create_irpf90_make([ x.filename for x in l_targets ] + [ os.path.join(irpdir,'irpf90.a') ] ) - - return - - diff --git a/src/parsed_text.py b/src/parsed_text.py index d2cbbdb..bed0a2d 100644 --- a/src/parsed_text.py +++ b/src/parsed_text.py @@ -24,526 +24,529 @@ # 31062 Toulouse Cedex 4 # scemama@irsamc.ups-tlse.fr - from util import * from irpf90_t import * -from variables import variables -from preprocessed_text import preprocessed_text -from subroutines import subroutines import regexps, re -import error -vtuple = map(lambda v: (v, variables[v].same_as, variables[v].regexp), variables.keys()) -stuple = map(lambda s: (s, subroutines[s].regexp), subroutines.keys()) -stuple = filter(lambda s: subroutines[s[0]].is_function, stuple) re_string_sub = regexps.re_string.sub - regexps_re_string_sub = regexps.re_string.sub -def find_variables_in_line(line): - assert isinstance(line,Line) - result = [] - sub_done = False - buffer = line.lower - ap = result.append - for v,same_as,regexp in vtuple: - if v in buffer: - if not sub_done: - buffer = regexps_re_string_sub('',buffer) - sub_done = True - if regexp.search(buffer) is not None: - ap(same_as) - return result -def find_funcs_in_line(line): - assert isinstance(line,Line) - result = [] - append = result.append - sub_done = False - buffer = line.lower - for s,regexp in stuple: - if s in buffer: - if regexp.search(buffer) is not None: - append(s) - return result + +def find_variables_in_line(line, vtuple): + line_lower = regexps_re_string_sub('', line.lower) + return [same_as for v, same_as, regexp in vtuple if v in line_lower and regexp(line_lower)] + + +def find_funcs_in_line(line, stuple): + assert isinstance(line, Line) + line_lower = line.lower + result = [s for s, regexp in stuple if s in line_lower and regexp.search(line_lower)] + return result def find_subroutine_in_line(line): - assert type(line) == Call - buffer = line.text.split('(')[0] - buffer = buffer.split()[1].lower() - return buffer + assert type(line) == Call + buffer = line.text.split('(')[0] + buffer = buffer.split()[1].lower() + return buffer + + +def check_touch(variables, line, vars, main_vars): + def fun(main_var): + if main_var not in variables: + error.fail(line, "Variable %s unknown" % (main_var, )) + x = variables[main_var] + return [main_var] + x.others_entity_name + + all_others = uniquify(flatten(map(fun, main_vars))) + all_others.sort() + vars.sort() + for x, y in zip(vars, all_others): + if x != y: + message = "The following entities should be touched:\n" + message = "\n".join([message] + map(lambda x: "- %s" % (x, ), all_others)) + error.fail(line, message) + + +from collections import namedtuple +Parsed_text = namedtuple('Parsed_text', ['varlist', 'line']) -def check_touch(line,vars,main_vars): - def fun(main_var): - if main_var not in variables: - error.fail(line,"Variable %s unknown"%(main_var,)) - x = variables[main_var] - return [main_var]+x.others - all_others = make_single(flatten( map(fun,main_vars) )) - all_others.sort() - vars.sort() - for x,y in zip(vars,all_others): - if x != y: - message = "The following entities should be touched:\n" - message = "\n".join([message]+map(lambda x: "- %s"%(x,),all_others)) - error.fail(line,message) ################################################################################ -def update_variables(): - for filename,text in preprocessed_text: - - for line in filter(lambda x: type(x) in [ Touch, SoftTouch ], text): - vars = line.lower.split() - if len(vars) < 2: - error.fail(line,"Syntax error") - for v in vars[1:]: - if v not in variables: - error.fail(line,"Variable %s unknown"%(v,)) - variables[v]._is_touched = True - - for line in filter(lambda x: type(x) == Free,text): - vars = line.lower.split() - if len(vars) < 2: - error.fail(line,"Syntax error") - for v in vars[1:]: - if v not in variables: - error.fail(line,"Variable %s unknown"%(v,)) - variables[v].is_freed = True - - for line in filter(lambda x: type(x) == Irp_read,text): - variables[line.filename]._is_read = True - - for line in filter(lambda x: type (x) == Irp_write,text): - variables[line.filename]._is_written = True - -################################################################################ - -def get_parsed_text(): - def func(filename, text): +def get_parsed_text(filename, text, variables, subroutines, vtuple): varlist = [] result = [] append = result.append - for line in text: #filter( -# lambda x: type(x) not in [ Doc, Begin_doc, End_doc ], -# text): - if type(line) in [ \ - Empty_line, - Continue, - Return, - Begin_shell, - End_shell, - Openmp, - Directive, - Use, - Enddo, - End_select, - Endif, - Implicit, - Program, - Subroutine, - Function, - End, - ]: - append( ([],line) ) - elif type(line) in [ Begin_provider, Cont_provider ]: - if type(line) == Begin_provider: - varlist = [] - buffer = map(strip,line.lower.replace(']','').split(',')) - assert len(buffer) > 1 - v = buffer[1] - varlist.append(v) - variable_list = find_variables_in_line(line) - try: - variable_list.remove(variables[v].same_as) - except ValueError: - print v, variables[v].same_as - raise - append( (variable_list,line) ) - elif type(line) == End_provider: - varlist = [] - append( ([],line) ) - elif type(line) == Provide: - l = line.lower.split()[1:] - l = filter(lambda x: x not in varlist, l) - for v in l: - if v not in variables: - error.fail(line,"Variable %s is unknown"%(v)) - append( (l,Provide(line.i,"",line.filename)) ) - append( (l,Simple_line(line.i,"!%s"%(line.text),line.filename)) ) - elif type(line) == NoDep: - l = line.lower.split()[1:] - for v in l: - if v not in variables: - error.fail(line,"Variable %s is unknown"%(v)) - l = map(lambda x: "-%s"%(x), l) - append( (l,Simple_line(line.i,"!%s"%(line.text),line.filename)) ) - elif type(line) in [ Touch, SoftTouch ]: - vars = line.lower.split() - if len(vars) < 2: - error.fail(line,"Syntax error") - vars = vars[1:] - def fun(x): - main = variables[x].same_as - return main - main_vars = make_single( map(fun, vars) ) - check_touch(line,vars,main_vars) - txt = " ".join(vars) - append ( (vars,Simple_line(line.i,"!",line.filename)) ) - append ( ([],Simple_line(line.i,"! >>> TOUCH %s"%(txt,),line.filename)) ) - def fun(x): - if x not in variables: - error.fail(line,"Variable %s unknown"%(x,)) - return [ ([],Simple_line(line.i," call touch_%s"%(x,),line.filename)), - ([],Use(line.i," use %s"%(variables[x].fmodule), line.filename)) ] - result += flatten(map( fun, main_vars )) - def fun(x): - if x not in variables: - error.fail(line,"Variable %s unknown"%(x,)) - return ([],Simple_line(line.i," %s_is_built = .True."%(x,),line.filename)) - result += map( fun, main_vars[:-1] ) - if type(line) == SoftTouch: - append ( ([],Simple_line(line.i,"! <<< END TOUCH (Soft)",line.filename)) ) + + for i, line in enumerate(text): + + tmp_result = [] + if isinstance(line, + (Empty_line, Continue, Return, Begin_shell, End_shell, Openmp, Directive, Use, + Enddo, End_select, Endif, End, Implicit, Program, Subroutine, Function)): + + append(Parsed_text([], line)) + + elif isinstance(line, (Begin_provider, Cont_provider)): + + if isinstance(line, (Begin_provider)): + varlist = [] + + v = line.lower.replace(']', '').split(',')[1].strip() + varlist.append(v) + + variable_list = find_variables_in_line(line, vtuple) + variable_list.remove(variables[v].same_as) + + append(Parsed_text(variable_list, line)) + + elif type(line) == End_provider: + varlist = [] + append(Parsed_text([], line)) + + elif type(line) == Provide: + l = line.lower.split()[1:] + l = filter(lambda x: x not in varlist, l) + for v in l: + if v not in variables: + error.fail(line, "Variable %s is unknown" % (v)) + + append(Parsed_text(l, Provide(line.i, "", line.filename))) + append(Parsed_text(l, Simple_line(line.i, "!%s" % (line.text), line.filename))) + + elif type(line) == NoDep: + l = line.lower.split()[1:] + for v in l: + if v not in variables: + error.fail(line, "Variable %s is unknown" % (v)) + l = map(lambda x: "-%s" % (x), l) + append(Parsed_text(l, Simple_line(line.i, "!%s" % (line.text), line.filename))) + elif type(line) in [Touch, SoftTouch]: + + vars = line.lower.split() + if len(vars) < 2: + error.fail(line, "Syntax error") + vars = vars[1:] + + main_vars = uniquify([variables[x].same_as for x in vars]) + + check_touch(variables, line, vars, main_vars) + + txt = " ".join(vars) + append(Parsed_text(vars, Simple_line(line.i, "!", line.filename))) + append(Parsed_text([], Simple_line(line.i, "! >>> TOUCH %s" % (txt, ), line.filename))) + + def fun(x): + if x not in variables: + error.fail(line, "Variable %s unknown" % (x, )) + return [ + Parsed_text([], Simple_line(line.i, " call touch_%s" % (x, ), line.filename)), + Parsed_text([], Use(line.i, " use %s" % (variables[x].fmodule), line.filename)) + ] + + result += flatten(map(fun, main_vars)) + + def fun(x): + if x not in variables: + error.fail(line, "Variable %s unknown" % (x, )) + return Parsed_text( + [], Simple_line(line.i, " %s_is_built = .True." % (x, ), line.filename)) + + result += map(fun, main_vars[:-1]) + if type(line) == SoftTouch: + append( + Parsed_text([], Simple_line(line.i, "! <<< END TOUCH (Soft)", line.filename))) + else: + append(Parsed_text([], Provide_all(line.i, "! <<< END TOUCH", line.filename))) + + elif type(line) == Call: + l = find_variables_in_line(line, vtuple) + l = filter(lambda x: x not in varlist, l) + sub = find_subroutine_in_line(line) + + if sub not in subroutines: + t = Simple_line + append(Parsed_text(l, Simple_line(line.i, line.text, line.filename))) + else: + append((l, line)) + if subroutines[sub].touches != []: + append(Parsed_text([], Provide_all(line.i, "", line.filename))) + + elif type(line) == Free: + vars = line.lower.split() + vars = vars[1:] + append(Parsed_text([], Simple_line(line.i, "!%s" % (line.text), line.filename))) + use = map(lambda x: " use %s" % (variables[x].fmodule), vars) + for var in vars: + result += map(lambda x: Parsed_text([], Use(line.i, x, line.filename)), + uniquify(use)) + result += map(lambda x: Parsed_text([], Simple_line(line.i, x, line.filename)), + variables[var].free) + + elif type(line) == Irp_read: + append(Parsed_text([], Simple_line(line.i, "!%s" % (line.text), line.filename))) + + elif type(line) == Irp_write: + append(Parsed_text([], Simple_line(line.i, "!%s" % (line.text), line.filename))) + + elif type(line) in [Begin_doc, End_doc, Doc]: + pass else: - append ( ([],Provide_all(line.i,"! <<< END TOUCH",line.filename)) ) - elif type(line) == Call: - l = find_variables_in_line(line) - l = filter(lambda x: x not in varlist, l) - sub = find_subroutine_in_line(line) - if sub not in subroutines: - t = Simple_line - append( (l,Simple_line(line.i,line.text,line.filename)) ) - else: - append( (l,line) ) - if subroutines[sub].touches != []: - append( ([],Provide_all(line.i,"",line.filename)) ) - elif type(line) == Free: - vars = line.lower.split() - vars = vars[1:] - append( ([],Simple_line(line.i,"!%s"%(line.text),line.filename)) ) - use = map(lambda x: " use %s"%(variables[x].fmodule),vars) - for var in vars: - result += map(lambda x: ([],Use(line.i,x,line.filename)), - make_single(use)) - result += map(lambda x: ([],Simple_line(line.i,x,line.filename)), - variables[var].free) - elif type(line) == Irp_read: - append( ([],Simple_line(line.i,"!%s"%(line.text),line.filename)) ) - elif type(line) == Irp_write: - append( ([],Simple_line(line.i,"!%s"%(line.text),line.filename)) ) - elif type(line) in [ Begin_doc, End_doc, Doc ]: - pass - else: - l = find_variables_in_line(line) - l = filter(lambda x: x not in varlist, l) - append( (l,line) ) - return result - - #main_result = [] - #for filename,text in preprocessed_text: - # main_result.append( (filename, func(filename,text)) ) - #return main_result - return parallel_loop(func,preprocessed_text) - -update_variables() -parsed_text = get_parsed_text() + l = find_variables_in_line(line, vtuple) + l = filter(lambda x: x not in varlist, l) + append(Parsed_text(l, line)) + return (filename, result) ###################################################################### +def move_to_top_list(text, it): + # ( List[ List[Entity], Line], Iterator) + '''Move the all the element of List[ List[Entity], Line] of Line's Type containt in IT are the top of text. -def move_to_top(text,t): - assert type(text) == list - assert t in [ NoDep, Declaration, Implicit, Use, Cont_provider ] + Note: + - The permutation neeed to be done following `it` order + - We can have `nested` subroutine / Function. (Because of interface) + - This function is called way to much. Is need to be efficient + - This function is Unpure + - One pass over `text` - inside = False - for i in range(len(text)): - vars, line = text[i] - if type(line) in [ Begin_provider, Program, Subroutine, Function ]: - begin = i - inside = True - elif type(line) in [ End_provider, End ]: - inside = False - elif type(line) == t: - if inside: - text.pop(i) - begin += 1 - text.insert(begin,(vars,line)) - return text + NB: + - I am not really proud of the Sentinel value for the deleted, + but I waste already so much time on more cleaver but not working solution... + ''' -result = [] -for filename,text in parsed_text: - text = move_to_top(text,NoDep) - text = move_to_top(text,Declaration) - text = move_to_top(text,Implicit) - text = move_to_top(text,Use) - text = move_to_top(text,Cont_provider) - result.append ( (filename,text) ) -parsed_text = result + assert set(it).issubset([NoDep, Declaration, Implicit, Use, Cont_provider]) + # ~ # ~ # ~ + # G e t P e r m u t a t i o n + # ~ # ~ # ~ + + from collections import defaultdict + d_permutation = defaultdict(list) + # Type:List(begin, Line) + # We will insert the Line at begin position later on + + l_begin = [] + + for i, (l_var, line) in enumerate(text): + t = type(line) + + if t in [Begin_provider, Module,Program, Subroutine, Function]: + l_begin.append(i) + elif t in [End_provider, End]: + l_begin.pop() + + elif l_begin and t in it: + d_permutation[t].append( (l_begin[-1], [l_var, line]) ) + # Put the sentinel, will be deleted after the insertion + text[i] = None + + # ~ # ~ # ~ + # O r d e r t h e m + # ~ # ~ # ~ + # We need to do the permutation in the correct order + d_insert = defaultdict(list) + for t in reversed(it): + for begin, tline in d_permutation[t]: + d_insert[begin].append(tline) + + # ~ # ~ # ~ + # D o t h e m + # ~ # ~ # ~ + # Because idx are sorted, it's easy to do the insert part of the move + # Just pad each insert by the number of precedent insert + padding = 0 + for idx in sorted(d_insert.keys()): + for tline in d_insert[idx]: + text.insert(idx + padding + 1, tline) + padding += 1 + + # Now do the Delete part of the move. Fortunatly we put a sentinel to know the line to delete + for i in reversed(xrange(len(text))): + if text[i] is None: + del text[i] + + +def move_interface(parsed_text,s_type=(Use,Implicit,Declaration,Subroutine,Function,Module)): + # ( List[ List[Entity], Line], Iterator) + '''Move everything containt into 'interface' below the first instance of s_type who preced it + + Note: + = This function is unpur + ''' + + # Get the born of the interface + i_begin = [ i for i, (_, line) in enumerate(parsed_text) if isinstance(line,Interface) ] + i_end = [ i+1 for i, (_, line) in enumerate(parsed_text) if isinstance(line,End_interface) ] + + # Get the begin of the insert + i_insert = [] + for begin in i_begin: + i_insert.append(next(i+1 for i in range(begin,-1,-1) if isinstance(parsed_text[i][1], s_type))) + + # Do the insert and the delete in one passe + for insert, begin, end in zip(i_insert,i_begin,i_end): + parsed_text[insert:insert] = parsed_text[begin:end] + + padding = end-begin + parsed_text[begin+padding:end+padding] = [] ###################################################################### -def build_sub_needs(): - # Needs - for filename, text in parsed_text: - sub = None - in_program = False - for vars,line in text: - if type(line) in [ Subroutine, Function ]: - subname = find_subname(line) - sub = subroutines[subname] - sub._needs = [] - sub._to_provide = [] - elif type(line) == End: - if not in_program: - sub._needs = make_single(sub._needs) - sub._to_provide = make_single(sub._to_provide) - sub = None - elif type(line) == Program: - in_program = True - if sub is not None: - if type(line) == Declaration: - sub._to_provide += vars - sub._needs += vars +def build_sub_needs(parsed_text, d_subroutine): + #(List[ Tuple[List[Entity], Tuple[int,List[Line]] ]], Dict[str:Sub]) -> None + '''Set the needs, and provides arguements of Routine present in parsed_text + + Note: + This function is unpure + ''' -build_sub_needs() + l_buffer = [] + for _, text in parsed_text: + l_begin = [ i for i, (_, line) in enumerate(text) if isinstance(line, (Subroutine, Function, Program))] + l_end = [i for i, (_, line) in enumerate(text) if isinstance(line, End)] + + l_buffer += [(d_subroutine[text[b].line.subname], text[b + 1:e]) for b, e in zip(l_begin, l_end) if not isinstance(text[b].line, Program)] + + for sub, text in l_buffer: + sub.needs = set(v for vs, _ in text for v in vs) + sub.to_provide = set(v for vs, line in text for v in vs if isinstance(line, Declaration)) ##################################################################### -def add_subroutine_needs(): - main_result = [] - for filename, text in parsed_text: - result = [] - append = result.append - for vars,line in text: - if type(line) == Call: - subname = find_subname(line) - vars += subroutines[subname].to_provide - append( (vars,line) ) - main_result.append( (filename, result) ) - return main_result -parsed_text = add_subroutine_needs() +def add_subroutine_needs(parsed_text, subroutines): + main_result = [] + for filename, text in parsed_text: + result = [] + append = result.append + for vars, line in text: + if type(line) == Call: + vars += subroutines[line.subname].to_provide + append((vars, line)) + main_result.append((filename, result)) + return main_result + ###################################################################### -def move_variables(): +def move_variables(parsed_text): + #(List[ Tuple[List[Entity], Tuple[int,List[Line]] ]] + '''Move variables into the top of the declaraiton''' - def func(filename, text): - result = [] - append = result.append - # 1st pass - varlist = [] - ifvars = [] - elsevars = [] - old_varlist = [] - old_ifvars = [] - old_elsevars = [] - revtext = list(text) - revtext.reverse() - try: - for vars,line in revtext: - if type(line) in [ End_provider,End ]: - varlist = [] - append( ([],line) ) - elif type(line) in [ Endif, End_select ]: - old_ifvars.append( list(ifvars) ) - old_elsevars.append( list(elsevars) ) - old_varlist.append( list(varlist) ) - varlist = [] - append( ([],line) ) - elif type(line) == Else: - elsevars += list(varlist) - append( (varlist,line) ) - varlist = [] - elif type(line) in [ Elseif, Case ]: - ifvars += list(varlist) - append( (varlist,line) ) - if vars != []: - varlist = old_varlist.pop() - varlist += vars - old_varlist.append( list(varlist) ) - varlist = [] - elif type(line) in [ If, Select ]: - ifvars += list(varlist) - append( (varlist,line) ) - vars += filter(lambda x: x in elsevars, ifvars) - ifvars = old_ifvars.pop() - elsevars = old_elsevars.pop() - varlist = old_varlist.pop() + vars - elif type(line) in [ Begin_provider, Program, Subroutine, Function ]: - varlist += vars - append( (varlist,line) ) - if old_varlist != [] \ - or old_ifvars != [] \ - or old_elsevars != []: - error.fail(line,"End if missing") - varlist = [] - elif type(line) in (Provide,Provide_all): - append( (vars,line) ) - else: - varlist += vars - append( ([],line) ) - except: - error.fail(line,"Unable to parse file") + + def func(filename, text): + result = [] + append = result.append + # 1st pass + varlist = [] + ifvars = [] + elsevars = [] + old_varlist = [] + old_ifvars = [] + old_elsevars = [] + revtext = list(text) + revtext.reverse() + + skip_interface = False + try: + for vars, line in revtext: + if type(line) in [Interface, End_interface]: + skip_interface = not skip_interface + + if skip_interface: + append(([], line)) + continue - result.reverse() + if type(line) in [End_provider, End]: + varlist = [] + append(([], line)) + elif type(line) in [Endif, End_select]: + old_ifvars.append(list(ifvars)) + old_elsevars.append(list(elsevars)) + old_varlist.append(list(varlist)) + varlist = [] + append(([], line)) + elif type(line) == Else: + elsevars += list(varlist) + append((varlist, line)) + varlist = [] + elif type(line) in [Elseif, Case]: + ifvars += list(varlist) + append((varlist, line)) + if vars != []: + varlist = old_varlist.pop() + varlist += vars + old_varlist.append(list(varlist)) + varlist = [] + elif type(line) in [If, Select]: + ifvars += list(varlist) + append((varlist, line)) + vars += filter(lambda x: x in elsevars, ifvars) + ifvars = old_ifvars.pop() + elsevars = old_elsevars.pop() + varlist = old_varlist.pop() + vars + elif type(line) in [Begin_provider, Program, Subroutine, Function]: + varlist += vars + append((varlist, line)) + if old_varlist != [] \ + or old_ifvars != [] \ + or old_elsevars != []: + error.fail(line, "End if missing") + varlist = [] + elif type(line) in (Provide, Provide_all): + append((vars, line)) + else: + varlist += vars + append(([], line)) + except: + from util import logger + logger.error("Unable to parse file %s", line) + import sys + sys.exit(1) - # 2nd pass - text = result - result = [] - append = result.append - old_varlist = [] - varlist = [] - try: - for vars,line in text: - if vars != []: - vars = make_single(vars) - if type(line) in [ Begin_provider, Program, Subroutine, Function ]: - varlist = list(vars) - elif type(line) in [ If, Select ]: - old_varlist.append(varlist) - vars = filter(lambda x: x not in varlist,vars) - varlist = make_single(varlist + vars) - assert old_varlist is not varlist - elif type(line) in [ Elseif, Else, Case ]: - varlist = old_varlist.pop() - old_varlist.append(varlist) - vars = filter(lambda x: x not in varlist,vars) - varlist = make_single(varlist + vars) - assert old_varlist is not varlist - elif type(line) in [ Endif, End_select ]: - varlist = old_varlist.pop() - elif type(line) == Provide_all: - vars += varlist - elif type(line) in [ End_provider, End ]: - assert old_varlist == [] - varlist = [] - for v in vars[:]: - if v[0] == '-': - vars.remove(v) - vars.remove(v[1:]) - result.append( (vars,line) ) - except: - error.fail(line,"Unable to parse file") - return result + result.reverse() - main_result = [] - for filename,text in parsed_text: - main_result.append( (filename, func(filename,text)) ) - return main_result - #return parallel_loop(func,parsed_text) + # 2nd pass + text = result + result = [] + append = result.append + old_varlist = [] + varlist = [] + try: + for vars, line in text: + if vars: + vars = uniquify(vars) + if type(line) in [Begin_provider, Program, Subroutine, Function]: + varlist = list(vars) + elif type(line) in [If, Select]: + old_varlist.append(varlist) + vars = filter(lambda x: x not in varlist, vars) + varlist = uniquify(varlist + vars) + assert old_varlist is not varlist + elif type(line) in [Elseif, Else, Case]: + varlist = old_varlist.pop() + old_varlist.append(varlist) + vars = filter(lambda x: x not in varlist, vars) + varlist = uniquify(varlist + vars) + assert old_varlist is not varlist + elif type(line) in [Endif, End_select]: + varlist = old_varlist.pop() + elif type(line) == Provide_all: + vars += varlist + elif type(line) in [End_provider, End]: + assert old_varlist == [] + varlist = [] + for v in vars[:]: + if v[0] == '-': + vars.remove(v) + vars.remove(v[1:]) + result.append((vars, line)) + except: + error.fail(line, "Unable to parse file") + return result + + main_result = [] + for filename, text in parsed_text: + main_result.append((filename, func(filename, text))) + return main_result -parsed_text = move_variables() ###################################################################### -def build_needs(): - # Needs - for filename, text in parsed_text: - var = None - for vars,line in text: - if type(line) == Begin_provider: - buffer = map(strip,line.lower.replace(']',',').split(',')) - var = variables[buffer[1]] - var.needs = [] - var.to_provide = vars - elif type(line) == End_provider: - var.needs = make_single(var.needs) - var.to_provide = make_single(var.to_provide) - var = None - if var is not None: - var.needs += vars - if type(line) == Call: - subname = find_subname(line) - var.needs += subroutines[subname].needs - elif type(line) in [ \ - Simple_line, Assert, - Do , If, - Elseif , Select, - ]: - funcs = find_funcs_in_line(line) - for f in funcs: - var.needs += subroutines[f].needs - for v in variables: - main = variables[v].same_as - if main != v: - variables[v].needs = variables[main].needs - variables[v].to_provide = variables[main].to_provide +def build_needs(parsed_text, subroutines, stuple, variables): + 'out: variable' - # Needed_by - for v in variables: - variables[v].needed_by = [] - for v in variables: - main = variables[v].same_as - if main != v: - variables[v].needed_by = variables[main].needed_by - for v in variables: - var = variables[v] - if var.is_main: - for x in var.needs: - variables[x].needed_by.append(var.same_as) - for v in variables: - var = variables[v] - var.needed_by = make_single(var.needed_by) + # ~#~#~#~#~# + # Needs and to_provide + # ~#~#~#~#~# + for filename, text in parsed_text: -build_needs() + l_begin = [i for i, (_, line) in enumerate(text) if isinstance(line, Begin_provider)] + l_end = [i for i, (_, line) in enumerate(text) if isinstance(line, End_provider)] -result = [] -for filename,text in parsed_text: - text = move_to_top(text,NoDep) - text = move_to_top(text,Declaration) - text = move_to_top(text,Implicit) - text = move_to_top(text,Use) - text = move_to_top(text,Cont_provider) - result.append ( (filename,text) ) -parsed_text = result + for start, end in zip(l_begin, l_end): + l_vars_start, line_start = text[start] + name = map(str.strip, line_start.lower.replace(']', ',').split(','))[1] + entity = variables[name] + + entity.to_provide = uniquify(l_vars_start) + + l_needs = [] + for vars, line in text[start:end]: + l_needs += vars + + if type(line) == Call: + l_needs += subroutines[line.subname].needs + elif type(line) in [Simple_line, Assert, Do, If, Elseif, Select]: + funcs = find_funcs_in_line(line, stuple) + for f in funcs: + l_needs += subroutines[f].needs + + entity.needs = uniquify(l_needs) + + for v in variables: + main = variables[v].same_as + if main != v: + variables[v].needs = variables[main].needs + variables[v].to_provide = variables[main].to_provide + + # ~#~#~#~#~# + # Needs and to_provide + # ~#~#~#~#~# + + for v in variables: + variables[v].needed_by = [] + for v in variables: + main = variables[v].same_as + if main != v: + variables[v].needed_by = variables[main].needed_by + + for v in variables: + var = variables[v] + if var.is_main: + for x in var.needs: + variables[x].needed_by.append(var.same_as) + + for v in variables: + var = variables[v] + var.needed_by = uniquify(var.needed_by) ###################################################################### from command_line import command_line -def check_opt(): - if not command_line.do_checkopt: - return - for filename, text in parsed_text: - do_level = 0 - for vars,line in text: - if not type(line) == Provide_all: - if do_level > 0 and vars != []: - print "Optimization: %s line %d"%(line.filename,line.i) - for v in vars: - print " PROVIDE ",v - if type(line) == Do: - do_level += 1 - elif type(line) == Enddo: - do_level -= 1 -check_opt() +def check_opt(parsed_text): + if not command_line.do_checkopt: + return + + for filename, text in parsed_text: + do_level = 0 + for vars, line in text: + if not type(line) == Provide_all: + if do_level > 0 and vars != []: + print "Optimization: %s line %d" % (line.filename, line.i) + for v in vars: + print " PROVIDE ", v + if type(line) == Do: + do_level += 1 + elif type(line) == Enddo: + do_level -= 1 + ###################################################################### -def perform_loop_substitutions(): - main_result = [] - for filename, text in parsed_text: - result = [] - append = result.append - for vars,line in text: - if type(line) in [ Do, If, Elseif ] : - for k,v in command_line.substituted.items(): - reg = v[1] - while reg.search(line.text) is not None: - line.text = re.sub(reg,r'\1%s\3', line.text,count=1)%v[0] - append( (vars,line) ) - main_result.append( (filename, result) ) - return main_result +def perform_loop_substitutions(parsed_text): + main_result = [] + for filename, text in parsed_text: + result = [] + append = result.append + for vars, line in text: + if type(line) in [Do, If, Elseif]: + for k, v in command_line.substituted.items(): + reg = v[1] + while reg.search(line.text) is not None: + line.text = re.sub(reg, r'\1%s\3', line.text, count=1) % v[0] + append((vars, line)) + main_result.append((filename, result)) + return main_result -parsed_text = perform_loop_substitutions() - -###################################################################### -if __name__ == '__main__': - for i in range(len(parsed_text)): - if parsed_text[i][0] == sys.argv[1]: - print '!-------- %s -----------'%(parsed_text[i][0]) - for line in parsed_text[i][1]: - print line[1] - print line[0], line[1].filename -#for i in subroutines: -# print i, subroutines[i].needs, subroutines[i].to_provide diff --git a/src/preprocessed_text.py b/src/preprocessed_text.py index ec7575a..69c24b5 100644 --- a/src/preprocessed_text.py +++ b/src/preprocessed_text.py @@ -26,18 +26,20 @@ from irpf90_t import * from regexps import * -import error from command_line import command_line from util import * +import sys # Local regular expressions -re_endif = re.compile("end\s+if") -re_elseif = re.compile("else\s+if") -re_enddo = re.compile("end\s+do") -re_endtype= re.compile("end\s+type") -re_endmodule = re.compile("end\s+module") -re_endselect = re.compile("end\s+select") -re_endinterface = re.compile("end\s+interface") +re_endif = re.compile("end +if") +re_elseif = re.compile("else +if") +re_enddo = re.compile("end +do") +re_endwhere = re.compile("end +where") + +re_endtype = re.compile("end +type.*") +re_endmodule = re.compile("end +module",re.I) +re_endselect = re.compile("end +select") +re_endinterface = re.compile("end +interface") # Local variables Free_form = 0 @@ -46,865 +48,936 @@ Fixed_form = 1 ###################################################################### # Dictionary of simple statements simple_dict = { - "program": Program , - "subroutine": Subroutine , - "begin_shell": Begin_shell , - "end_shell": End_shell , - "begin_template": Begin_template , - "end_template": End_template , - "subst": Subst , - "end_doc": End_doc , - "begin_provider": Begin_provider , - "&begin_provider": Cont_provider , - "end_provider": End_provider , - "assert": Assert , - "touch": Touch , - "soft_touch": SoftTouch , - "provide": Provide , - "no_dep": NoDep , - "free": Free , - "irp_if": Irp_If , - "irp_else": Irp_Else , - "irp_endif": Irp_Endif , - "irp_read": Irp_read , - "irp_write": Irp_write , - "use": Use , - "do": Do , - "if": If , - "case": Case , - "elseif": Elseif , - "else": Else , - "enddo": Enddo , - "endif": Endif , - "endselect": End_select , - "end": End , - "include": Include , - "call": Call , - "continue": Continue , - "return": Return , - "implicit": Implicit , - "save": Declaration , - "function": Function , - "recursive": Function , + "program": Program, + "subroutine": Subroutine, + "begin_shell": Begin_shell, + "end_shell": End_shell, + "begin_template": Begin_template, + "end_template": End_template, + "subst": Subst, + "end_doc": End_doc, + "begin_provider": Begin_provider, + "&begin_provider": Cont_provider, + "end_provider": End_provider, + "assert": Assert, + "touch": Touch, + "soft_touch": SoftTouch, + "provide": Provide, + "no_dep": NoDep, + "free": Free, + "irp_if": Irp_If, + "irp_else": Irp_Else, + "irp_endif": Irp_Endif, + "irp_read": Irp_read, + "irp_write": Irp_write, + "use": Use, + "do": Do, + "if": If, + "case": Case, + "elseif": Elseif, + "else": Else, + "enddo": Enddo, + "endif": Endif, + "endselect": End_select, + "end": End, + "include": Include, + "call": Call, + "continue": Continue, + "return": Return, + "implicit": Implicit, + "save": Declaration, + "function": Function, + "recursive": Function, + "select": Select, + "selectcase": Select, + "module": Module, + "endmodule": End_module, + "interface": Interface, + "endinterface": End_interface, + "where": Where, + "elsewhere": Elsewhere, + "endwhere": Endwhere, } -def get_type (i, filename, line, is_doc): - '''Find the type of a text line''' - assert type(i) == int - assert type(filename) == str - assert type(line) == str - assert type(is_doc) == bool +def get_canonized_text(text_lower): - # add support for interface block - has_interface = False + text_canonized = text_lower + text_canonized = re_elseif.sub("elseif", text_canonized) + text_canonized = re_enddo.sub("enddo", text_canonized) + text_canonized = re_endtype.sub("endtype", text_canonized) + text_canonized = re_endmodule.sub("endmodule", text_canonized) + text_canonized = re_endif.sub("endif", text_canonized) + text_canonized = re_endselect.sub("endselect", text_canonized) + text_canonized = re_endinterface.sub("endinterface", text_canonized) + text_canonized = re_endwhere.sub('endwhere',text_canonized) - line = line.rstrip() - line = line.replace("$IRP_ALIGN",command_line.align) - lower_line0 = line.lstrip().lower() - lower_line = lower_line0.replace("!"," ! ") + for c in """()'"[]""": + text_canonized = text_canonized.replace(c, " %s " % c) + return text_canonized - # Replacements - lower_line = re_elseif.sub("elseif",lower_line) - lower_line = re_enddo.sub("enddo",lower_line) - lower_line = re_endtype.sub("endtype",lower_line) - lower_line = re_endmodule.sub("endmodule",lower_line) - lower_line = re_endif.sub("endif",lower_line) - lower_line = re_endselect.sub("endselect",lower_line) - lower_line = re_endinterface.sub("endinterface",lower_line) - for c in """()'"[]""": - lower_line = lower_line.replace(c," "+c+" ") +def get_type(i, filename, line, line_lower, line_lower_canonized, is_doc): + # ( int,str,str,str,str,bool) -> Irpf90_t + '''Find the type of a text line''' + + line = line.rstrip() + l_word = line_lower_canonized.split() - buffer = lower_line.split() - if len(buffer) == 0: - return [ Empty_line(i,line,filename) ], is_doc + if not l_word: + return [Empty_line(i, line, filename)], is_doc - firstword = buffer[0] - if firstword.isdigit(): - assert len(buffer) > 1 - buffer = buffer[1:] - firstword = buffer[0] + # Handle archaic do loop of f77 + firstword = l_word[0] + if firstword.isdigit(): + l_word = l_word[1:] + firstword = l_word[0] - # Identify line - if firstword == "endinterface": - has_interface = False - return [ Simple_line (i,line,filename) ], False + if firstword == "contains": + return [Contains(i, line, filename)], False + if firstword == "end_doc": + return [End_doc(i, line, filename)], False - if firstword == "interface" or has_interface: - has_interface = True - return [ Simple_line (i,line,filename) ], False + if firstword == "begin_doc": + return [Begin_doc(i, line, filename)], True - if firstword == "end_doc": - return [ End_doc (i,line,filename) ], False + if is_doc: + return [Doc(i, line, filename)], is_doc - if firstword == "begin_doc": - return [ Begin_doc (i,line,filename) ], True + if firstword in simple_dict: + type_ = simple_dict[firstword] + return [type_(i, line, filename)], is_doc - if is_doc: - return [ Doc (i,line,filename) ], is_doc - if firstword in simple_dict: - return [ simple_dict[firstword](i,line,filename) ], is_doc + #label do-loop (outer: do i=1,sze) + reg_do_lab = ur":\s+do\s+" + if re.search(reg_do_lab,line_lower): + return [Do(i,line,filename)], is_doc + - if firstword in [ "select", "selectcase" ]: - return [ Select(i,line,filename) ] , is_doc + lower_line = line_lower.strip()[1:] - if len(lower_line0) > 4: + if len(lower_line) <= 3: + return [Simple_line(i, line, filename)], is_doc - if firstword[0] == '#': - result = [ Simple_line(i,line,filename) ] - error.warn ( result[0] , -"""irpf90 may not work with preprocessor directives. You can use - Irp_if ... Irp_else ... Irp_endif -instead of - #ifdef ... #else ... #endif""" ) - return result, is_doc + #WARNING: The regex shloud match endtype. Don't know why it's not the case + if re_decl.match(line_lower_canonized) or line_lower_canonized == 'endtype': + if "function" in l_word[1:3]: + return [Function(i, line, filename)], is_doc + else: + return [Declaration(i, line, filename)], is_doc + + if firstword.startswith('#'): + result = [Simple_line(i, line, filename)] + + logger.info("%s:" + "irpf90 may not work with preprocessor directives. You can use" + "Irp_if ... Irp_else ... Irp_endif" + "instead of" + "#ifdef ... #else ... #endif"%line) + return result, is_doc if firstword.startswith("case("): - return [ Case(i,line,filename) ], is_doc + return [Case(i, line, filename)], is_doc - if lower_line0[1:5] == "$omp": - return [ Openmp(i,line,filename) ], is_doc - elif lower_line0[1:5] in ["dec$", "dir$"] and command_line.directives: - return [ Directive(i,line,filename) ], is_doc - elif lower_line0[1:3] == "$ ": - return [ Openmp(i,line,filename) ], is_doc - - if re_decl.match(lower_line) is not None: - if "function" in buffer[1:3]: - return [ Function (i,line,filename) ], is_doc - else: - return [ Declaration (i,line,filename) ], is_doc + if lower_line.startswith("$omp"): + return [Openmp(i, line, filename)], is_doc + if lower_line.startswith(("dec$", "dir$")) and command_line.directives: + return [Directive(i, line, filename)], is_doc + if lower_line.startswith("$ "): + return [Openmp(i, line, filename)], is_doc # Detect errors if firstword == "dowhile": - error.fail( Do(i,line,filename) , "'do while' should be in 2 words." ) - - return [ Simple_line(i,line,filename) ], is_doc + logger.error("%s 'do while' should be in 2 words." % Do(i, line, filename)) + sys.exit(1) + return [Simple_line(i, line, filename)], is_doc ###################################################################### -def get_text(lines,filename): - '''Read the input file and transform it to labeled lines''' - assert type(filename) == str - assert type(lines) == list +import os.path - result = [] - is_doc = False - for i,line in enumerate(lines): - line, is_doc = get_type(i+1,filename,line,is_doc) - result += line - return result -###################################################################### +def save_and_execute(irpdir, scriptname, code, interpreter): + # (str, str, List, str) -> List[Line] + ''' Save the script in irpdir/scriptname and Execute it + + Note: + The script are executed in the orginal directory of the .irp.f (aka '..') + and this directory is added to PYTHONPATH. + ''' + + irpdir_scriptname = os.path.abspath(os.path.join(irpdir, scriptname)) + with open(irpdir_scriptname, 'w') as f: + f.writelines(code) + + # Execute shell + import util + try: + text = util.check_output('PYTHONPATH=$PYTHONPATH:. %s %s' % (interpreter, irpdir_scriptname), shell=True, bufsize=-1, cwd=os.path.join(irpdir,'..')) + except: + util.logger.error("Something wrong append with embeded '%s' script: %s"% (interpreter, irpdir_scriptname)) + import sys + sys.exit(1) + + # Create the Line + p = Preprocess_text(scriptname) + p.text = text + return p.lines_overloaded + + +####################################################################### def execute_shell(text): - '''Execute the embedded shell scripts''' - def fail(l,a,b): error.fail(l,"In Begin_Shell, %s '%s'"%(a,b)) - inside = False - result = [] - for line in text: - if inside: - if type(line) == Begin_shell: - error.fail(line,"Nested Begin_shell") - elif type(line) == End_shell: - inside = False - # Write script file - scriptname = "%s%s_shell_%d"%(irpdir,line.filename,line.i) - file = open(scriptname,'w') - file.writelines(script) - file.close() - scriptname = "%s_shell_%d"%(line.filename,line.i) - file = open(scriptname,'w') - file.writelines(script) - file.close() - # Execute shell - import os - pipe = os.popen("%s < %s"%(shell,scriptname),'r') - lines = pipe.readlines() - pipe.close() - result += get_text(lines,scriptname) - os.remove(scriptname) - else: - script.append(line.text+'\n') - else: - if type(line) == Begin_shell: - inside = True - begin = line.i - script = [] - # Find shell executable - buffer = line.text.split('[') - if len(buffer) > 2: - fail(line,"Too many",'[') - elif len(buffer) < 2: - fail(line,"Missing",'[') - buffer = buffer[1] - buffer = buffer.split(']') - if len(buffer) > 2: - fail(line,"Too many",']') - elif len(buffer) < 2: - fail(line,"Missing",']') - shell = buffer[0].strip() - elif type(line) == End_shell: - error.fail(line,"Begin_shell missing") - else: - result.append(line) - return result + # (List[Line]) -> List[Line] + '''Execute the embedded shell scripts''' + + + l_begin = [i for i,line in enumerate(text) if isinstance(line,Begin_shell)] + l_end = [i for i,line in enumerate(text) if isinstance(line,End_shell)] + l_output= [] + + # ~=~=~=~ + # E x e c u t e S h e l l + # ~=~=~=~ + from util import logger + import sys + def fail(l, a, b): + logger.error("%s In Begin_Shell, %s '%s'" % (l,a, b)) + sys.exit(1) + + for begin,end in zip(l_begin,l_end): + + header = text[begin] + header_text = header.text + + for bracket in ['[', ']']: + n = header_text.count(bracket) + assert n <= 1, fail(header_text, "Too many", bracket) + assert n >= 1, fail(header_text, "Missing", bracket) + else: + interpreter = header_text[header_text.find('[')+1: header_text.find(']')].strip() + script = ['%s\n' % l.text for l in text[begin+1:end] ] + scriptname="%s_shell_%d" % (header.filename, header.i) + + l_output.append(save_and_execute(irpdir, scriptname, script,interpreter)) + + # ~=~=~=~ + # R e p l a c e + # ~=~=~=~ + + #Deep copy for pure function + text_new = text[:] + + # Because we use slicing and we want to include the end line + l_end_include = [i+1 for i in l_end] + padding = 0 + for begin,end, out in zip(l_begin,l_end_include,l_output): + text_new[begin+padding:end+padding] = out + padding += len(out) - (end-begin) + + return text_new + ###################################################################### def execute_templates(text): - '''Execute the templates''' - def fail(l,a,b): error.fail(l,"In %s, %s"%(a,b)) + '''Execute the templates''' - def get_variables(line): - buffer = line.text.split('[',1) - if len(buffer)<2: - fail(line,"Subst","Syntax error") - buffer = buffer[1].replace(']','') - buffer = buffer.split(',') - return map(lambda x: '$%s'%(x.strip()), buffer) + def fail(l, a, b): + error.fail(l, "In %s, %s" % (a, b)) - TEMPLATE = 1 - SUBST = 2 - inside = 0 - result = [] - for line in text: - if inside == 0: - if type(line) == Begin_template: - script = [] - inside = TEMPLATE - script = "template = \"\"\"\n" - else: - result.append(line) - elif inside == TEMPLATE: - if type(line) == Begin_template: - fail(line,"template", "Nested Begin_Template") - elif type(line) == End_template: - fail(line,"template","Missing Subst") - elif type(line) == Subst: - inside = SUBST - script += "\"\"\"\n" - variables = get_variables(line) - script += "v = []\n" - subst = "" - else: - script += line.text+"\n" - else: # inside == SUBST - if type(line) == Begin_template: - fail(line,"subst","Nested Begin_template") - elif type(line) == Subst: - fail(line,"subst","Subst already defined") - elif type(line) == End_template: - inside = 0 - subst = subst.rstrip() - if subst[-2:] == ';;': - subst = subst[:-2] - for s in subst.split(';;'): - buffer = map(lambda x: x.strip(), s.split(';')) - if len(buffer) != len(variables): - fail(line,"subst","%d variables defined, and %d substitutions"%(len(variables),len(buffer))) - script += "v.append( { \\\n" - for t,v in zip(variables,buffer): - script += ' "%s": """%s""" ,\n'%(t,v) - script += "} )\n" - script += "for d in v:\n t0 = str(template)\n" - for v in variables: - script += " t0 = t0.replace('%s',d['%s'])\n"%(v,v) - script += " print t0\n" - # Write script file - scriptname = "%s%s_template_%d"%(irpdir,line.filename,line.i) - file = open(scriptname,'w') - file.writelines(script) - file.close() - scriptname = "%s_template_%d"%(line.filename,line.i) - file = open(scriptname,'w') - file.writelines(script) - file.close() - # Execute shell - import os - pipe = os.popen("python < %s"%(scriptname),'r') - lines = pipe.readlines() - pipe.close() - result += get_text(lines,scriptname) - os.remove(scriptname) - else: - subst += line.text+'\n' + def get_variables(line): + buffer = line.text.split('[', 1) + if len(buffer) < 2: + fail(line, "Subst", "Syntax error") + buffer = buffer[1].replace(']', '') + buffer = buffer.split(',') + return map(lambda x: '$%s' % (x.strip()), buffer) + + TEMPLATE = 1 + SUBST = 2 + inside = 0 + result = [] + for line in text: + if inside == 0: + if type(line) == Begin_template: + script = [] + inside = TEMPLATE + script = "template = \"\"\"\n" + else: + result.append(line) + elif inside == TEMPLATE: + if type(line) == Begin_template: + fail(line, "template", "Nested Begin_Template") + elif type(line) == End_template: + fail(line, "template", "Missing Subst") + elif type(line) == Subst: + inside = SUBST + script += "\"\"\"\n" + variables = get_variables(line) + script += "v = []\n" + subst = "" + else: + script += line.text + "\n" + else: # inside == SUBST + if type(line) == Begin_template: + fail(line, "subst", "Nested Begin_template") + elif type(line) == Subst: + fail(line, "subst", "Subst already defined") + elif type(line) == End_template: + inside = 0 + subst = subst.rstrip() + if subst[-2:] == ';;': + subst = subst[:-2] + for s in subst.split(';;'): + buffer = map(lambda x: x.strip(), s.split(';')) + if len(buffer) != len(variables): + fail(line, "subst", "%d variables defined, and %d substitutions" % + (len(variables), len(buffer))) + script += "v.append( { \\\n" + for t, v in zip(variables, buffer): + script += ' "%s": """%s""" ,\n' % (t, v) + script += "} )\n" + script += "for d in v:\n t0 = str(template)\n" + for v in variables: + script += " t0 = t0.replace('%s',d['%s'])\n" % (v, v) + script += " print t0\n" + result += save_and_execute(irpdir, scriptname="%s_template_%d" % (line.filename, line.i), code=script,interpreter="python") + else: + subst += line.text + '\n' + + return result - return result ###################################################################### def form(text): - '''Find if the text is in fixed form or in free form''' - assert type(text) == list - if len(text) == 0: - return Free_form - assert isinstance(text[0],Line) + '''Find if the text is in fixed form or in free form''' + assert type(text) == list + if len(text) == 0: + return Free_form + assert isinstance(text[0], Line) - re2 = re.compile(r"^\s*[!#]") - re3 = re.compile(r"^\s*[^ 0-9]+") - for line in text: - if type(line) in [ Empty_line, Doc, Openmp, Directive ]: - pass - else: - if len(line.text) > 5: - test = line.text[0:5] - if test[0] in "Cc#!*": - pass + re2 = re.compile(r"^\s*[!#]") + re3 = re.compile(r"^\s*[^ 0-9]+") + for line in text: + if type(line) in [Empty_line, Doc, Openmp, Directive]: + pass else: - if re2.match(test) is None and \ - re3.match(test) is not None: - return Free_form - if line.text.rstrip()[-1] == '&': - return Free_form - return Fixed_form + if len(line.text) > 5: + test = line.text[0:5] + if test[0] in "Cc#!*": + pass + else: + if re2.match(test) is None and re3.match(test) is not None: + return Free_form + if line.text.rstrip()[-1] == '&': + return Free_form + return Fixed_form + ###################################################################### def add_operators(text): - re_incr = re.compile(r"(\s*)(.*)(\+=)(.*$)",re.S) - re_decr = re.compile(r"(\s*)(.*)(-=)(.*$)",re.S) - re_mult = re.compile(r"(\s*)(.*)(\*=)(.*$)",re.S) - '''Change additional operators''' - result = [] - for line in text: - buffer = line.text - if "+=" in buffer: - if buffer.lstrip().startswith("if "): - re_incr = re.compile(r"(.*)(\))(\s*)(.*)(\+=)(.*$)",re.S) - line.text = re.sub(re_incr,r'\1\2\4=\4+(\6)', buffer) - else: - line.text = re.sub(re_incr,r'\1\2=\2+(\4)', buffer) - elif "-=" in buffer: - line.text = re.sub(re_decr,r'\1\2=\2-(\4)', buffer) - elif "*=" in buffer: - line.text = re.sub(re_mult,r'\1\2=\2*(\4)', buffer) - result.append(line) - return result - -###################################################################### -def remove_comments(text,form): - '''Remove all comments''' - result = [] - - def remove_after_bang(line): - match = re_comment.match(line) - if match is None: - return line - else: - return re_comment.split(line)[1].rstrip() - - if form == Free_form: + re_incr = re.compile(r"(\s*)(.*)(\+=)(.*$)", re.S) + re_decr = re.compile(r"(\s*)(.*)(-=)(.*$)", re.S) + re_mult = re.compile(r"(\s*)(.*)(\*=)(.*$)", re.S) + '''Change additional operators''' + result = [] for line in text: - if type(line) in [ Openmp, Doc, Directive] : - result.append(line) - elif type(line) == Empty_line: - pass - else: - newline = line.text.lstrip() - if newline == "" or newline[0] == "!": - pass - else: - line.text = remove_after_bang(line.text) - result.append(line) - return result - else: - for line in text: - if type(line) in [ Openmp, Doc, Directive ]: - result.append(line) - elif type(line) == Empty_line: - pass - else: - newline = line.text.lstrip() - if newline == "" or newline[0] == "!": - pass - else: - line.text = remove_after_bang(line.text) - if line.text[0] in "#123456789 ": - result.append(line) - return result - -###################################################################### -def remove_continuation(text,form): - '''Removes continuation lines''' - result = [] - buffer = "" - number = 0 - t = None - if form == Free_form: - for line in text: - if line.text[-1] == '&': - buffer = "%s%s\n"%(buffer,line.text) - if number == 0: - t = type(line) - number = line.i - else: - if number != 0: - newline = t(number, \ - "%s%s"%(buffer,line.text), \ - line.filename) - line = newline - number = 0 - buffer = "" + buffer = line.text + ls = buffer.strip() + if ls.startswith('print ') or \ + ls.startswith('print*') or \ + ls.startswith('write('): + pass + elif "+=" in buffer: + if buffer.lstrip().startswith("if "): + re_incr = re.compile(r"(.*)(\))(\s*)(.*)(\+=)(.*$)", re.S) + line.text = re.sub(re_incr, r'\1\2\4=\4+(\6)', buffer) + else: + line.text = re.sub(re_incr, r'\1\2=\2+(\4)', buffer) + elif "-=" in buffer: + line.text = re.sub(re_decr, r'\1\2=\2-(\4)', buffer) + elif "*=" in buffer: + line.text = re.sub(re_mult, r'\1\2=\2*(\4)', buffer) result.append(line) - else: - rev_text = list(text) - rev_text.reverse() - for line in rev_text: - is_continuation = False - if type(line) == Simple_line: - if len(line.text) >= 6: - if line.text[5] != ' ': - is_continuation = True - if is_continuation: - buffer = "&\n%s %s %s"%(line.text[:5],line.text[6:],buffer) - else: - line.text = line.text+buffer - result.insert(0,line) - buffer = "" - return result + return result + + +###################################################################### +def remove_comments(text, form): + # (List[Line], int) -> List[Line] + '''Remove all comments + + Note: + This function is unpur + ''' + result = [] + + def remove_after_bang(str_): + # str -> str + i_bang = str_.find('!') + + if i_bang == -1: + return str_ + else: + sentinel, inside = None, False + for i,c in enumerate(str_): + if c == '"' or c == "'": + if not inside: + inside = True + sentinel = c + elif sentinel == c: + inside = False + + elif c == '!' and not inside: + return str_[:i].strip() + + return str_ + + + if form == Free_form: + for line in text: + if type(line) in [Openmp, Doc, Directive]: + result.append(line) + elif type(line) == Empty_line: + pass + else: + newline = line.text.lstrip() + if (newline != "" and newline[0] != "!#"): + text = remove_after_bang(line.text) + if text: + line.text = text + result.append(line) + + return result + else: + for line in text: + if type(line) in [Openmp, Doc, Directive]: + result.append(line) + elif type(line) == Empty_line: + pass + else: + newline = line.text.lstrip() + if newline == "" or newline[0] == "!": + pass + else: + line.text = remove_after_bang(line.text) + if line.text[0] in "#123456789 ": + result.append(line) + return result + + +###################################################################### +def remove_continuation(text, form): + '''Removes continuation lines''' + result = [] + buffer = "" + number = 0 + t = None + if form == Free_form: + for line in text: + if line.text[-1] == '&': + buffer = "%s%s\n" % (buffer, line.text) + if number == 0: + t = type(line) + number = line.i + else: + if number != 0: + newline = t(number, \ + "%s%s"%(buffer,line.text), \ + line.filename) + line = newline + number = 0 + buffer = "" + result.append(line) + else: + rev_text = list(text) + rev_text.reverse() + for line in rev_text: + is_continuation = False + if type(line) == Simple_line: + if len(line.text) >= 6: + if line.text[5] != ' ': + is_continuation = True + if is_continuation: + buffer = "&\n%s %s %s" % (line.text[:5], line.text[6:], buffer) + else: + line.text = line.text + buffer + result.insert(0, line) + buffer = "" + return result ###################################################################### def irp_simple_statements(text): - '''Processes simple statements''' + '''Processes simple statements''' - def process_irp_rw(line,rw,t): - assert type(line) == t - buffer = line.text.split() - if len(buffer) == 2: - dummy, variable = buffer - num = "0" - elif len(buffer) == 3: - dummy, variable, num = buffer - else: - error.fail(line,"Error in IRP_%s statement"%(rw,)) - variable = variable.lower() - i = line.i - f = line.filename - txt = line.text.lstrip() - result = [ - Empty_line(i,"!",f), - t(i,"! >>> %s"%(txt,),variable ), - Provide_all(i," call %ser_%s('%s')"%(rw,variable,num),f), - Empty_line(i,"! >>> END %s "%(txt,),f ), - Empty_line(line.i,"!",f), - ] - return result - - def process_irp_read (line): - assert type(line) == Irp_read - return process_irp_rw(line,'read' ,Irp_read ) - - def process_irp_write(line): - assert type(line) == Irp_write - return process_irp_rw(line,'writ' ,Irp_write) - - def process_return(line): - assert type(line) == Return - if command_line.do_assert or command_line.do_debug: - newline = Simple_line(line.i," call irp_leave(irp_here)",line.filename) - result = [newline, line] - else: - result = [ line ] - return result - - def debug_conditions(line): - '''Find condition in assert statement for debug''' - assert type(line) == Assert - match = re_test.search(line.text) - result = [] - if match is not None: - matches = [ match.group(1).strip(), match.group(3).strip() ] - for m in matches: - if not(m.isdigit() or ("'" in m) or (m == "")): - result.append ( Simple_line (line.i, " print *, '%s = ', %s"%(m,m), line.filename) ) - result.append ( Simple_line (line.i, " print *, ''", line.filename) ) - return result - - def process_assert(line): - assert type(line) == Assert - if command_line.do_assert: - if '(' not in line.text or ')' not in line.text: - error.fail(line,"Syntax error in ASSERT statement (parentheses)") - condition = "(%s"%(line.text.split('(',1)[1]) - if condition == "": - error.fail(line,"Error in Assert statement") - condition_str = condition.replace("'","''") - i = line.i - f = line.filename - txt = line.text.strip() - result = [ - Empty_line(i, "!", f), - Empty_line(i, "! >>> %s"%(txt,), f), - If (i, " if (.not.%s) then"%(condition,), f), - Simple_line(i, " call irp_trace", f), - Simple_line(i, " print *, irp_here//': Assert failed:'", f), - Simple_line(i, " print *, ' file: %s, line: %d'"%(f,i), f), - Simple_line(i, " print *, '%s'"%(condition_str,), f), - ] + debug_conditions(line) + [ - Simple_line(i, " stop 1", f), - Endif (i, " endif", f), - Empty_line(i, "! <<< END %s"%(txt,), f), - Empty_line(i, "!", f) - ] - else: - result = [] - return result - - def process_end(line): - '''Set irp_here variable in provider block''' - line.text = "end" - if command_line.do_assert or command_line.do_debug: - i = line.i - f = line.filename - result = [ - Simple_line(i," call irp_leave(irp_here)", f), - line + def process_irp_rw(line, rw, t): + '''Read Write''' + assert type(line) == t + buffer = line.text.split() + if len(buffer) == 2: + dummy, variable = buffer + num = "0" + elif len(buffer) == 3: + dummy, variable, num = buffer + else: + error.fail(line, "Error in IRP_%s statement" % (rw, )) + variable = variable.lower() + i = line.i + f = line.filename + txt = line.text.lstrip() + result = [ + Empty_line(i, "!", f), + t(i, "! >>> %s" % txt, variable), + Provide_all(i, " call %ser_%s('%s')" % (rw, variable, num), f), + Empty_line(i, "! >>> END %s " % (txt, ), f), + Empty_line(line.i, "!", f), ] - else: - result = [ line ] + return result + + def process_irp_read(line): + assert type(line) == Irp_read + return process_irp_rw(line, 'read', Irp_read) + + def process_irp_write(line): + assert type(line) == Irp_write + return process_irp_rw(line, 'writ', Irp_write) + + def process_return(line): + assert type(line) == Return + if command_line.do_assert or command_line.do_debug: + newline = Simple_line(line.i, " call irp_leave(irp_here)", line.filename) + result = [newline, line] + else: + result = [line] + return result + + def debug_conditions(line): + '''Find condition in assert statement for debug''' + assert type(line) == Assert + match = re_test.search(line.text) + result = [] + if match is not None: + matches = [match.group(1).strip(), match.group(3).strip()] + for m in matches: + ok = m != "" # not empty + ok = ok and not m.isdigit() # not a digit + ok = ok and "'" not in m # not a string + ok = ok and m.count('(') == m.count(')') # balanced parenthesis + if ok: + result.append( + Simple_line(line.i, " print *, '%s = ', %s" % (m, m), line.filename)) + result.append(Simple_line(line.i, " print *, ''", line.filename)) + return result + + def process_assert(line): + assert type(line) == Assert + if command_line.do_assert: + if '(' not in line.text or ')' not in line.text: + error.fail(line, "Syntax error in ASSERT statement (parentheses)") + condition = "(%s" % (line.text.split('(', 1)[1]) + if condition == "": + error.fail(line, "Error in Assert statement") + condition_str = condition.replace("'", "''") + i = line.i + f = line.filename + txt = line.text.strip() + result = [ + Empty_line(i, "!", f), + Empty_line(i, "! >>> %s" % (txt, ), f), + If(i, " if (.not.%s) then" % (condition, ), f), + Simple_line(i, " call irp_trace", f), + Simple_line(i, " print *, irp_here//': Assert failed:'", f), + Simple_line(i, " print *, ' file: %s, line: %d'" % (f, i), f), + Simple_line(i, " print *, '%s'" % (condition_str, ), f), + ] + debug_conditions(line) + [ + Simple_line(i, " stop 1", f), Endif(i, " endif", f), Empty_line( + i, "! <<< END %s" % (txt, ), f), Empty_line(i, "!", f) + ] + else: + result = [] + return result + + def process_end(line): + '''Add irp_leave if necessary''' + + if command_line.do_assert or command_line.do_debug: + i = line.i + f = line.filename + result = [Simple_line(i, " call irp_leave(irp_here)", f), line] + else: + result = [line] + return result + + def process_begin_provider(line): + assert type(line) == Begin_provider + import string + trans = string.maketrans("[]"," ") + buffer = line.lower.translate(trans).split(',') + + if len(buffer) < 2: + error.fail(line, "Error in Begin_provider statement") + varname = buffer[1].strip() + length = len(varname) + i = line.i + f = line.filename + result = [ + Begin_provider(i, line.text, (f, varname)), + Declaration(i, " character*(%d) :: irp_here = '%s'" % (length, varname), f) + ] + if command_line.do_assert or command_line.do_debug: + result += [Simple_line(i, " call irp_enter(irp_here)", f), ] + return result + + def process_cont_provider(line): + assert type(line) == Cont_provider + buf = line.lower.replace('[', " ").replace(']', "").split(',') + if len(buf) < 2: + error.fail(line, "Error in Cont_provider statement") + varname = buf[1].strip() + i = line.i + f = line.filename + return [Cont_provider(i, line.text, (f, varname))] + + def process_subroutine(line): + assert type(line) == Subroutine + subname = line.subname + length = len(subname) + i = line.i + f = line.filename + result = [ line, Declaration(i, " character*(%d) :: irp_here = '%s'" % (length, subname), f)] + + if command_line.do_assert or command_line.do_debug: + result += [Simple_line(i, " call irp_enter_f(irp_here)", f), ] + return result + + def process_function(line): + assert type(line) == Function + subname = line.subname + length = len(subname) + i = line.i + f = line.filename + result = [ + line, Declaration(i, " character*(%d) :: irp_here = '%s'" % (length, subname), f) + ] + if command_line.do_assert or command_line.do_debug: + result += [Simple_line(i, " call irp_enter_f(irp_here)", f), ] + return result + + def process_program(line): + assert type(line) == Program + program_name = line.lower.split()[1] + temp = [Program(0, "program irp_program", program_name)] + if command_line.do_profile: + temp += [Simple_line(0, "call irp_init_timer()", line.filename)] + if command_line.do_openmp: + temp += [Simple_line(0, " call irp_init_locks_%s()" % (irp_id), line.filename)] + temp += [Call(0, " call %s" % (program_name), line.filename)] + if command_line.do_profile: + temp += [Simple_line(0, "call irp_print_timer()", line.filename)] + + temp += [Simple_line(0, " call irp_finalize_%s()" % (irp_id), line.filename)] + temp += [End(0, "end program", line.filename)] + + result = temp + process_subroutine( + Subroutine(line.i, "subroutine %s" % (program_name, ), line.filename)) + return result + + d = { + Irp_read: process_irp_read, + Irp_write: process_irp_write, + Return: process_return, + Assert: process_assert, + End: process_end, + Begin_provider: process_begin_provider, + Cont_provider: process_cont_provider, + End_provider: process_end, + Subroutine: process_subroutine, + Function: process_function, + Program: process_program, + } + + + result = [] + for line in text: + buffer = [line] + for t in d: + if type(line) == t: + buffer = d[t](line) + break + result += buffer + return result - def process_begin_provider(line): - assert type(line) == Begin_provider - buffer = line.lower.replace('['," ") - buffer = buffer.replace(']',"") - buffer = buffer.split(',') - if len(buffer) < 2: - error.fail(line,"Error in Begin_provider statement") - varname = buffer[1].strip() - length = len(varname) - i = line.i - f = line.filename - result = [ Begin_provider(i,line.text, (f,varname)), - Declaration(i," character*(%d) :: irp_here = '%s'"%(length,varname), f) ] - if command_line.do_assert or command_line.do_debug: - result += [ - Simple_line(i," call irp_enter(irp_here)", f), - ] - return result - - def process_cont_provider(line): - assert type(line) == Cont_provider - buffer = line.lower.replace('['," ") - buffer = buffer.replace(']',"") - buffer = buffer.split(',') - if len(buffer) < 2: - error.fail(line,"Error in Cont_provider statement") - varname = buffer[1].strip() - i = line.i - f = line.filename - return [ Cont_provider(i,line.text,(f,varname)) ] - - def process_subroutine(line): - assert type(line) == Subroutine - subname = find_subname(line) - length = len(subname) - i = line.i - f = line.filename - result = [ line, - Declaration(i," character*(%d) :: irp_here = '%s'"%(length,subname), f) ] - if command_line.do_assert or command_line.do_debug: - result += [ - Simple_line(i," call irp_enter_f(irp_here)", f), - ] - return result - - def process_function(line): - assert type(line) == Function - subname = find_subname(line) - length = len(subname) - i = line.i - f = line.filename - result = [ line, - Declaration(i," character*(%d) :: irp_here = '%s'"%(length,subname), f) ] - if command_line.do_assert or command_line.do_debug: - result += [ - Simple_line(i," call irp_enter_f(irp_here)", f), - ] - return result - - - def process_program(line): - assert type(line) == Program - program_name = line.lower.split()[1] - temp = [ Program(0,"program irp_program",program_name) ] - if command_line.do_profile: - temp += [ Simple_line(0,"call irp_init_timer()",line.filename) ] - if command_line.do_openmp: - temp += [ Simple_line(0," call irp_init_locks_%s()"%(irp_id),line.filename) ] - temp += [ Call(0," call %s"%(program_name),line.filename) ] - if command_line.do_profile: - temp += [ Simple_line(0,"call irp_print_timer()",line.filename) ] - temp += [ Simple_line(0," call irp_finalize_%s()"%(irp_id),line.filename) ] - temp += [ End(0,"end program",line.filename) ] - result = temp + \ - process_subroutine( Subroutine(line.i,"subroutine %s"%(program_name,),line.filename) ) - return result - - d = { Irp_read : process_irp_read, - Irp_write : process_irp_write, - Return : process_return, - Assert : process_assert, - End : process_end, - Begin_provider : process_begin_provider, - Cont_provider : process_cont_provider, - End_provider : process_end, - Subroutine : process_subroutine, - Function : process_function, - Program : process_program, - } - - result = [] - for line in text: - buffer = [ line ] - for t in d: - if type(line) == t: - buffer = d[t](line) - break - result += buffer - return result - ###################################################################### def change_includes(text): - '''Deals with include files''' - result = [] - for line in text: - if type(line) == Include: - txt = line.text.replace('"',"'").split("'") - if len(txt) != 3: - print txt - error.fail(line,"Error in include statement") - directory = (("./"+line.filename).rsplit('/',1)[0]+'/')[2:] - if directory == "": - filename = txt[1].strip() - else: - filename = directory+txt[1].strip() - try: - file = open(filename,'r') - file.close() - result.append(Include(line.i,"! include '%s'"%filename,filename)) - result += create_preprocessed_text(filename) - except IOError: - result.append(Declaration(line.i,line.text,line.filename)) - else: - result.append(line) - return result + '''Deals with include files''' + result = [] + for line in text: + if type(line) == Include: + txt = line.text.replace('"', "'").split("'") + if len(txt) != 3: + error.fail(line, "Error in include statement") + directory = (("./" + line.filename).rsplit('/', 1)[0] + '/')[2:] + if directory == "": + filename = txt[1].strip() + else: + filename = directory + txt[1].strip() + try: + result.append(Include(line.i, "! include '%s'" % filename, filename)) + result += Preprocess_text(filename).preprocessed_text + except IOError: + result.append(Declaration(line.i, line.text, line.filename)) + else: + result.append(line) + return result + ###################################################################### def process_old_style_do(text): - '''Changes old-style do loops to new style''' - assert type(text) == list + # (List[Line]) -> List[Line] + '''Changes archaic do loops to new style + DO 1 i=1,10''' - def change_matching_enddo(begin,number): - for i in range(begin+1,len(text)): - line = text[i] - if type(line) in [Continue,Enddo]: - buffer = line.text.split() - if buffer[0] == number: - text[i] = Enddo(line.i," enddo",line.filename) - return - error.fail(text[begin],"Old-style do loops should end with 'continue' or 'end do'") + def change_matching_enddo(begin, number): + for i,line in enumerate(text[begin+1:]): + if isinstance(line,(Continue,Enddo)) and line.text.split()[0] == number: + text[begin+1+i] = Enddo(line.i, " enddo", line.filename) + return + + from util import logger + logger.error(text[begin], "(%s) Old-style do loops should end with 'continue' or 'end do'" % text[begin]) + from util import sys + sys.exit(1) + + result = [] + for i in range(len(text)): + line = text[i] + if type(line) == Do: + buffer = line.text.split() + try: + if buffer[1].isdigit(): + number = buffer.pop(1) + change_matching_enddo(i, number) + line.text = " ".join(buffer) + except IndexError: + pass + result.append(line) + return result - result = [] - for i in range(len(text)): - line = text[i] - if type(line) == Do: - buffer = line.text.split() - try: - if buffer[1].isdigit(): - number = buffer.pop(1) - change_matching_enddo(i,number) - line.text = " ".join(buffer) - except IndexError: - pass - result.append(line) - return result ###################################################################### def change_single_line_ifs(text): - '''Changes: -if (test) result + # List[Line] -> List[Line] + '''Changes: `if (test) result` + into + `if (test) then + result + endif`''' -to + regex = r"\(.*?\)" -if (test) then - result -endif''' + result = [] + for line in text: + if type(line) == If: + if line.lower.endswith("then"): + result.append(line) + else: + buffer = line.text + begin = buffer.find('(') + if begin == -1: + logger.error("No '(' in if statemnt: %s" % line) + sys.exit(1) + + level = 0 + instring = False + for i, c in enumerate(buffer[begin:]): + if c == "'": + instring = not instring + if instring: + pass + elif c == '(': + level += 1 + elif c == ')': + level -= 1 + if level == 0: + end = begin + i + 1 + break + if level != 0: + logger.error("If statement not valid: %s (%s)" % (line, line.filename)) + sys.exit(1) + + test = buffer[:end] + code = buffer[end:] + i = line.i + f = line.filename + result.append(If(i, "%s then" % (test, ), f)) + result += get_type(i, f, code, code.lower(),code.lower(), False)[0] + result.append(Endif(i, " endif", f)) + else: + result.append(line) + return result - assert type(text) == list - result = [] - for line in text: - if type(line) == If: - if line.lower.endswith("then"): - result.append(line) - else: - buffer = line.text - begin = buffer.find('(') - if begin < 0: - error.fail(line,"Error in if statement") - level = 0 - instring = False - for i,c in enumerate(buffer[begin:]): - if c == "'": - instring = not instring - if instring: - pass - elif c == '(': - level +=1 - elif c == ')': - level -= 1 - if level == 0: - end = begin+i+1 - break - if level != 0: - error.fail(line,"Error in if statement") - test = buffer[:end] - code = buffer[end:] - i = line.i - f = line.filename - result.append( If(i,"%s then"%(test,),f) ) - result += get_type(i,f,code,False)[0] - result.append( Endif(i," endif",f) ) - else: - result.append(line) - return result ###################################################################### -def check_begin_end(text): - '''Checks x...endx consistence''' - - filter_line = lambda line: type(line) in [ Do, Enddo, If, Endif, \ - Program, Begin_provider, End_provider, \ - Subroutine, Function, End, Begin_doc, End_doc ] - text = filter(filter_line, text) - - d = { 'do' : Do, 'enddo': Enddo, - 'if' : If, 'endif': Endif, - '_doc': Begin_doc, 'end_doc': End_doc} - assert type(text) == list - - def find_matching_end_ifdo(begin,x): - level = 1 - for i in range(begin+1,len(text)): - line = text[i] - if type(line) == d[x]: - level += 1 - elif type(line) == d["end%s"%(x,)]: - level -= 1 - if level == 0: - return True - elif type(line) in [End, End_provider]: - break - error.fail(text[begin],"Missing 'end%s'"%(x,)) - - def find_matching_end_subfunpro(begin,x): - line = text[begin] - for i in range(begin+1,len(text)): - line = text[i] - if type(line) == x: - return - if type(line) in [ Subroutine, Function, Program, Begin_provider ]: - error.fail(text[begin],type(line).str+" is not closed") - error.fail(text[begin],type(line).str + " is not closed") +def check_begin_end(raw_text): + # List[Line] -> None + '''Checks x...endx consistence - level = 0 - for i,line in enumerate(text): - if type(line) == Begin_doc: - find_matching_end_ifdo(i,'_doc') - for i,line in enumerate(text): - if type(line) == Do: - find_matching_end_ifdo(i,'do') - elif type(line) == If: - find_matching_end_ifdo(i,'if') - elif type(line) in [Subroutine, Function, Program]: - level += 1 - find_matching_end_subfunpro(i,End) - elif type(line) == Begin_provider: - level += 1 - find_matching_end_subfunpro(i,End_provider) - elif type(line) == End: - level -= 1 - elif type(line) == End_provider: - level -= 1 - if level < 0: - error.fail(line,"Beginning of block not matched") + Note: + fortran 'ifdef' statement may cause this function to bug. + Indeed we count the numboer of 'x' statement and compare it to the number of 'endx'. + Maybe more of one 'x' statement in defined cause in 'ifdef/else/endif' statement. + ''' - return True + d_block = {Enddo: [Do], + Endif: [If], + End_provider: [Begin_provider], + End_doc: [Begin_doc], + End: [Program, Subroutine, Function], + End_module: [Module], + End_interface: [Interface]} + + from collections import defaultdict + d_type = defaultdict(list) + + for line in raw_text: + d_type[type(line)].append(line) + + for t_end, l_begin in d_block.iteritems(): + n_end = len(d_type[t_end]) + n_begin = sum(len(d_type[t_begin]) for t_begin in l_begin) + + if n_end != n_begin: + + if n_end > n_begin: + logger.error("You have more close statement than open statement (%s) (%s)",line.filename,t_end) + else: + logger.error('You have more end statement than open statenemt for (%s) (%s)' % (line.filename, t_end)) + + for i in zip([l for i in l_begin for l in d_type[i]], d_type[t_end]): + logger.debug(i) + + sys.exit(1) ###################################################################### def remove_ifdefs(text): - assert type(text) == list - result = [] - do_print = True - for line in text: - if type(line) == Irp_If: - var = line.text.split()[1] - do_print = var in command_line.defined - elif type(line) == Irp_Else: - do_print = not do_print - elif type(line) == Irp_Endif: - do_print = True - else: - if do_print: - result.append(line) - return result + assert type(text) == list + result = [] + + do_print = True + for line in text: + if type(line) == Irp_If: + var = line.text.split()[1] + do_print = var in command_line.defined + elif type(line) == Irp_Else: + do_print = not do_print + elif type(line) == Irp_Endif: + do_print = True + elif do_print: + result.append(line) + + return result + ###################################################################### def check_OpenMP(text): - assert type(text) == list - result = [] - inside_openmp = False - for line in text: - if type(line) == Openmp: - # Detect OpenMP blocks - buffer = line.text.lower().split() - if buffer[1] == "parallel": - inside_openmp = True - if buffer[1] == "end" and buffer[2] == "parallel": - inside_openmp = False - result.append(line) + 'Not working!' + assert type(text) == list + inside_openmp = False + for line in text: + if type(line) == Openmp: + # Detect OpenMP blocks + buffer = line.lower.split() - if inside_openmp: - if type(line) in [ Provide_all, Provide, Touch, SoftTouch ]: - error.fail(line,type(line).str+" is not allowed in an OpenMP block.") + if buffer[1] == "parallel": + inside_openmp = True + elif buffer[1] == "end" and buffer[2] == "parallel": + inside_openmp = False + +# if inside_openmp and isinstance(line, (Provide_all, Provide, Touch, SoftTouch)): +# logger.error("%s is not allowed in an OpenMP block: %s" % (type(line),line)) + + return text - return result ###################################################################### -def create_preprocessed_text(filename): - file = open(filename,"r") - lines = file.readlines() - file.close() - result = get_text(lines,filename) - result = execute_templates(result) - result = execute_shell(result) - fortran_form = form(result) - result = remove_ifdefs(result) - result = remove_comments(result,fortran_form) - result = remove_continuation(result,fortran_form) - result = add_operators(result) - result = change_includes(result) - result = change_single_line_ifs(result) - result = process_old_style_do(result) - result = irp_simple_statements(result) - result = check_OpenMP(result) - check_begin_end(result) - return result +class Preprocess_text(object): + def __init__(self, filename): + self.filename = filename -###################################################################### -preprocessed_text = parallel_loop( lambda x,y: create_preprocessed_text(x), \ - map(lambda x: (x,None), irpf90_files ) ) + @irpy.lazy_property_mutable + def text(self): + with open(self.filename, 'r') as f: + str_ = f.read() + + #Dirty thing. We will replace 'end program' by 'end subroutine' + #because afterward the program will be replaced by a subroutine... + + import re + transform = re.compile(re.escape('end program'), re.IGNORECASE) + + return transform.sub('end subroutine', str_) + + @irpy.lazy_property_mutable + def text_align(self): + from command_line import command_line + return self.text.replace("$IRP_ALIGN", command_line.align) + + @irpy.lazy_property + def text_lower(self): + return self.text_align.lower() + + @irpy.lazy_property + def text_lower_canonized(self): + return get_canonized_text(self.text_lower) + + @irpy.lazy_property + def lines(self): + return self.text_align.split('\n') + + @irpy.lazy_property + def lines_lower(self): + return self.text_lower.split('\n') + + @irpy.lazy_property + def lines_lower_canonized(self): + return self.text_lower_canonized.replace("!", " ! ").split('\n') + + @irpy.lazy_property + def lines_overloaded(self): + '''Labeled lines''' + result = [] + is_doc = False + + for i, (l, ll, llc) in enumerate(zip(self.lines, self.lines_lower, self.lines_lower_canonized)): + line, is_doc = get_type(i + 1, self.filename, l, ll, llc, is_doc) + result += line + return result + + @irpy.lazy_property + def preprocessed_text(self): + result = self.lines_overloaded + result = execute_templates(result) + result = execute_shell(result) + fortran_form = form(result) + result = remove_ifdefs(result) + result = remove_comments(result, fortran_form) + + result = remove_continuation(result, fortran_form) + result = add_operators(result) + result = change_includes(result) + result = change_single_line_ifs(result) + + result = process_old_style_do(result) + result = irp_simple_statements(result) + result = check_OpenMP(result) + + check_begin_end(result) + + return result -###################################################################### -def debug(): - for filename, txt in preprocessed_text: - if filename == 'invert.irp.f': - print "=== "+filename+" ===" - for line in txt: - print line - print irpf90_files if __name__ == '__main__': - debug() - + debug() diff --git a/src/profile.py b/src/profile.py index 7ff7fe4..02094e2 100644 --- a/src/profile.py +++ b/src/profile.py @@ -45,22 +45,15 @@ import subprocess import tempfile import os import threading +from irpf90_t import irpdir def build_rdtsc(): - file,filename = tempfile.mkstemp() - filename += ".c" + filename = irpdir+"irp_rdtsc.c" file = open(filename,'w') file.write(rdtsc) file.close() - def t(): - p = subprocess.Popen(["gcc","-O2",filename,"-c","-o","irp_rdtsc.o"]) - p.communicate() - os.remove(filename) - threading.Thread(target=t).start() - -def build_module(): - from variables import variables +def build_module(variables): data = """ module irp_timer double precision :: irp_profile(3,%(n)d) @@ -104,11 +97,10 @@ subroutine irp_init_timer double precision :: irp_rdtsc, t0 irp_profile = 0.d0 irp_rdtsc_shift = 0.d0 - do i=1,1000 + do i=1,1000000 t0 = irp_rdtsc() - irp_rdtsc_shift = irp_rdtsc_shift + (irp_rdtsc()-t0) enddo - irp_rdtsc_shift = 1.d-3*irp_rdtsc_shift + irp_rdtsc_shift = 1.d-6*(irp_rdtsc()-t0) %(text)s end @@ -177,9 +169,7 @@ end file.write(data) file.close() -def run(): - build_module() +def run(d_entity): + build_module(d_entity) build_rdtsc() -if __name__ == "__main__": - build_rdtsc() diff --git a/src/regexps.py b/src/regexps.py index 1aecc8f..61d77e1 100644 --- a/src/regexps.py +++ b/src/regexps.py @@ -47,7 +47,7 @@ re_decl = re.compile( "".join( [ r"^\ *", r"|external *(::)?", r"|equivalence *(::)?", r"|type", - r"|end ?type", + r"|endtype", r")[^=(]" ] ) ) diff --git a/src/routine.py b/src/routine.py new file mode 100644 index 0000000..8f31b49 --- /dev/null +++ b/src/routine.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python +# IRPF90 is a Fortran90 preprocessor written in Python for programming using +# the Implicit Reference to Parameters (IRP) method. +# Copyright (C) 2009 Anthony SCEMAMA +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Anthony Scemama +# LCPQ - IRSAMC - CNRS +# Universite Paul Sabatier +# 118, route de Narbonne +# 31062 Toulouse Cedex 4 +# scemama@irsamc.ups-tlse.fr + + +from irpf90_t import * + +from util import logger + +try: + import irpy +except: + import lib_irpy as irpy + +class Routine(object): + ''' + A collection of list corresponding of a Routine (Subroutine, or function) + ''' + + + ############################################################ + def __init__(self,text): + assert type(text) == list + assert len(text) > 0 + + self.text = text + self.prototype = self.text[0] + assert isinstance(self.prototype, (Subroutine, Function)) + + ############################################################ + @irpy.lazy_property_mutable + def called_by(self): + raise AttributeError + + ############################################################ + @irpy.lazy_property + def name(self): + '''Name is lowercase''' + return self.prototype.subname + + ############################################################ + @irpy.lazy_property + def is_function(self): + return "function" in self.prototype.lower + + ############################################################ + @irpy.lazy_property + def is_subroutine(self): + return "subroutine" in self.prototype.lower + + ############################################################ + @irpy.lazy_property + def doc(self): + + l_doc = [ l for l in self.text if isinstance(l,Doc) ] + if not l_doc: + logger.info("Subroutine '%s' is not documented"%(self.name)) + return [l.text.lstrip()[1:] for l in l_doc] + + ############################################################ + @irpy.lazy_property + def touches_my_self(self): + return set(x for line in self.text for x in line.text.split()[1:] if isinstance(line,(Touch, SoftTouch))) + + @irpy.lazy_property_mutable + def touches_ancestor(self): + raise AttributeError + + @irpy.lazy_property + def touches(self): + return list(self.touches_my_self.union(self.touches_ancestor)) + + ############################################################ + @irpy.lazy_property + def regexp(self): + import re + return re.compile(r"([^a-z0-9'\"_]|^)%s([^a-z0-9_]|$)"%(self.name),re.I) + + ############################################################ + @irpy.lazy_property + def calls(self): + return set(line.text.split('(',1)[0].split()[1].lower() for line in self.text if isinstance(line,Call)) diff --git a/src/subroutine.py b/src/subroutine.py deleted file mode 100644 index 0eb4acf..0000000 --- a/src/subroutine.py +++ /dev/null @@ -1,131 +0,0 @@ -#!/usr/bin/env python -# IRPF90 is a Fortran90 preprocessor written in Python for programming using -# the Implicit Reference to Parameters (IRP) method. -# Copyright (C) 2009 Anthony SCEMAMA -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Anthony Scemama -# LCPQ - IRSAMC - CNRS -# Universite Paul Sabatier -# 118, route de Narbonne -# 31062 Toulouse Cedex 4 -# scemama@irsamc.ups-tlse.fr - - -from irpf90_t import * -from util import * -import error - -class Sub(object): - - ############################################################ - def __init__(self,text): - assert type(text) == list - assert len(text) > 0 - assert type(text[0]) in [Subroutine, Function] - self.text = text - self.called_by = [] - - ############################################################ - def name(self): - '''Name is lowercase''' - if '_name' not in self.__dict__: - self._name = find_subname(self.line) - return self._name - name = property(name) - - ############################################################ - def is_function(self): - if '_is_function' not in self.__dict__: - self._is_function = "function" in self.line.lower - return self._is_function - is_function = property(is_function) - - ############################################################ - def doc(self): - if '_doc' not in self.__dict__: - def f(l): return - buffer = filter(lambda l:type(l) == Doc, self.text) - self._doc = map(lambda l: l.text.lstrip()[1:], buffer) - if buffer == []: - error.warn(None,"Subroutine %s is not documented"%(self.name)) - return self._doc - doc = property(doc) - - ############################################################ - def line(self): - if '_line' not in self.__dict__: - self._line = self.text[0] - return self._line - line = property(line) - - ############################################################ - def touches(self): - if '_touches' not in self.__dict__: - from subroutines import subroutines - self._touches = [] - for line in filter(lambda x: type(x) in [Touch, SoftTouch],self.text): - self._touches += line.text.split()[1:] - for sub in self.calls: - if sub in subroutines: - self._touches += subroutines[sub].touches - self._touches = make_single(self._touches) - return self._touches - touches = property(touches) - - ############################################################ - def needs(self): - if '_needs' not in self.__dict__: - import parsed_text - self._needs = make_single(self._needs) - return self._needs - needs = property(needs) - - ############################################################ - def to_provide(self): - if '_to_provide' not in self.__dict__: - import parsed_text - return self._to_provide - to_provide = property(to_provide) - - ############################################################ - def regexp(self): - if '_regexp' not in self.__dict__: - import re - self._regexp = re.compile( \ - r"([^a-z0-9'\"_]|^)%s([^a-z0-9_]|$)"%(self.name),re.I) - return self._regexp - regexp = property(regexp) - - ############################################################ - def calls(self): - if '_calls' not in self.__dict__: - buffer = filter(lambda x: type(x) == Call,self.text) - self._calls = [] - for line in buffer: - sub = line.text.split('(',1)[0].split()[1].lower() - self._calls.append(sub) - self._calls = make_single(self._calls) - return self._calls - calls = property(calls) - -###################################################################### -if __name__ == '__main__': - from preprocessed_text import preprocessed_text - from variables import variables - from subroutines import subroutines - print map(lambda x: variables[x].needs, subroutines['full_ci'].needs) - print subroutines['full_ci'].calls diff --git a/src/subroutines.py b/src/subroutines.py deleted file mode 100644 index 67444b6..0000000 --- a/src/subroutines.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python -# IRPF90 is a Fortran90 preprocessor written in Python for programming using -# the Implicit Reference to Parameters (IRP) method. -# Copyright (C) 2009 Anthony SCEMAMA -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Anthony Scemama -# LCPQ - IRSAMC - CNRS -# Universite Paul Sabatier -# 118, route de Narbonne -# 31062 Toulouse Cedex 4 -# scemama@irsamc.ups-tlse.fr - - -from util import * -from subroutine import * -from variables import variables -from variable import Variable -from irpf90_t import * - -def create_subroutines(): - from preprocessed_text import preprocessed_text - result = {} - for filename, text in preprocessed_text: - buffer = [] - inside = False - for line in text: - if type(line) in [ Subroutine, Function ]: - inside = True - if inside: - buffer.append(line) - if isinstance(line,End): - if inside: - v = Sub(buffer) - result[v.name] = v - buffer = [] - inside = False - return result - -def create_called_by(subs,vars): - for s in subs.values() + vars.values(): - if type(s) == Variable and s.same_as != s.name: - continue - for x in s.calls: - try: - subs[x].called_by.append(s.name) - except KeyError: - pass - - for s in subs.values(): - s.called_by = make_single(s.called_by) - s.called_by.sort() - -subroutines = create_subroutines() -create_called_by(subroutines,variables) - -if __name__ == '__main__': - for v in subroutines.keys(): - print v diff --git a/src/touches.py b/src/touches.py index 0690558..b2533bf 100644 --- a/src/touches.py +++ b/src/touches.py @@ -24,50 +24,42 @@ # 31062 Toulouse Cedex 4 # scemama@irsamc.ups-tlse.fr +from irpf90_t import irp_id,irpdir +import os +from util import lazy_write_file -from irpf90_t import * -from util import * -from variables import variables -from modules import modules +def create(modules,variables): + # (Dict[str,Module]. Dict[str, Variable]) -> None + '''Create the fortran90 finalize subroutine and the touched one''' -FILENAME=irpdir+'irp_touches.irp.F90' - -def create(): - out = [] - l = variables.keys() - l.sort - main_modules = filter(lambda x: modules[x].is_main, modules) + finalize = "subroutine irp_finalize_%s\n"%(irp_id) - for m in filter(lambda x: not modules[x].is_main, modules): - finalize += " use %s\n"%(modules[m].name) - for v in l: - var = variables[v] - var_in_main = False - for m in main_modules: - if var.fmodule == modules[m].name: - var_in_main = True - break - if not var_in_main: - if var.is_touched: - out += var.toucher - if var.dim != []: + for m in filter(lambda x: not modules[x].is_main and modules[x].has_irp_module, modules): + finalize += " use %s\n"%(modules[m].name) + + main_modules_name =[ m.name for m in modules.values() if m.is_main] + + out = [] + for v,var in variables.iteritems(): + + if var.fmodule not in main_modules_name: + #if var.is_self_touched: + out += var.toucher + if var.dim: finalize += " if (allocated(%s)) then\n"%v finalize += " %s_is_built = .False.\n"%var.same_as finalize += " deallocate(%s)\n"%v finalize += " endif\n" + finalize += "end\n" - - if out != []: + if out: out = map(lambda x: "%s\n"%(x),out) out += finalize - - if not same_file(FILENAME,out): - file = open(FILENAME,'w') - file.writelines(out) - file.close() + + filename=os.path.join(irpdir,'irp_touches.irp.F90') + lazy_write_file(filename,''.join(out)) if __name__ == '__main__': create() - diff --git a/src/util.py b/src/util.py index 191e3cd..3c63060 100644 --- a/src/util.py +++ b/src/util.py @@ -24,169 +24,282 @@ # 31062 Toulouse Cedex 4 # scemama@irsamc.ups-tlse.fr + +# ~#~#~#~#~# +# L o g e r +# ~#~#~#~#~# +''' +Level Numeric value +CRITICAL 50 +ERROR 40 +WARNING 30 +INFO 20 +DEBUG 10 +NOTSET 0 +''' +import logging +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger('Irpf90') +logger.setLevel(30) + +# ~#~#~#~#~# +# / / _ R E L A T E D +# ~#~#~#~#~# + +def chunkify(l,n_chunk): + # (List[any], int) -> List [ List[any] ] + '''Split the list on n_chunk''' + len_ = len(l) + n = max(1, len_ / n_chunk ) + return [ l[i:i + n] for i in xrange(0, len_, n) ] + + +import multiprocessing +def parmap(f, it, parallel=False): + # (Callable, Iterable, bool) -> List + '''Parallel version of the std map function + + The parallel flag is set to togle the // execusion + + Note: + - We try to use the Mulprocesses map is possible else we use our own + - The order of the sequence if concerved + - Will use all the processesor possible + - We return a List + - The traceback is loose if an error occur but a Exception is raise. + ''' + + if not parallel: + return map(f, it) + + nproc = multiprocessing.cpu_count() + + # ~!~!~! + # Parallelisation STD + # ~!~!~ + + # This 'hang' on Travis and I don't know why... + # https://docs.python.org/2/library/pickle.html#what-can-be-pickled-and-unpickled + #from cPickle import PicklingError + #try: + # p = multiprocessing.Pool(nproc) + # l_res = p.map(f, it,nproc) + #except PicklingError: + # pass + #else: + # return l_res + + # ~!~!~! + # Parallelisation By Us + # ~!~!~ + + # To optimize the // performance, + # we merge the task into chunk + # In this implementation, we minimizise the communication + # (aka 1 job by processor) + + it_chunk = chunkify(l=it,n_chunk=nproc) + def F(chunk): + # (List[any]) -> (List[any]) + '''Same as 'f' but for a chunck''' + return map(f,chunk) + + + q_in = multiprocessing.JoinableQueue() + q_out = multiprocessing.Queue() + # All the worker will sepuku after reseaving this message + # Remove that we need to always put in `q_in` a not None value. + stop_condition = None + + def worker(): + # () -> None + '''Read a task from q_in, excute it, and store it in q_out + + Note: + - We use 'F' and not 'f'. + - The for loop will break when stop_contition occur + - We get, and put an idx to allow the possibility of ordering afterward + - We store any exeception, to raise her afterward + ''' + for i, x in iter(q_in.get, stop_condition): + + try: + result = F(x) + except BaseException as e: + t = e + else: + t = (i, result) + + q_out.put(t) + q_in.task_done() + + q_in.task_done() + + # Process' creation + l_proc = [multiprocessing.Process(target=worker) for _ in range(nproc)] + for p in l_proc: + p.daemon = True + p.start() + + # Add the job to the queue (Note we add an idx, this will all) + for i, x in enumerate(it_chunk): + q_in.put((i, x)) + + # Now add the stop contidion and join + # (Because q_in.get is blocking we don't need to join the queue before) + for _ in l_proc: + q_in.put(stop_condition) + q_in.join() + + # Get all the chunk and join the process + l_res = [q_out.get() for _ in range(len(it_chunk))] + + for p in l_proc: + p.join() + + # Check if error have occured + try: + from itertools import ifilter + e = next(ifilter(lambda t: isinstance(t,BaseException), l_res)) + except StopIteration: + # Now we need first to order the result, and secondly to flatte it + return [item for _, chunk in sorted(l_res) for item in chunk] + else: + raise e + +# ~#~#~#~#~# +# I O _ R E L A T E D +# ~#~#~#~#~# +import hashlib import os -NTHREADS=1 #int(os.getenv('OMP_NUM_THREADS',1)) +def cached_file(filename, text): + # (str,str) -> bool + '''Check if file locatte at filename containt the same data as text -def strip(x): - return x.strip() + Return: + True if data is the same, false otherwise + ''' -def lower(x): - return x.lower() + def digest(data): + # (str) -> str + '''compute an uniq data id''' + return hashlib.md5(data).hexdigest() -def same_file(filename,txt): - assert isinstance(filename,str) - if (type(txt) == list): - buffer = ''.join(txt) - else: - buffer = txt - - try: - file = open(filename,"r") - except IOError: - return False - stream = file.read() - file.close() - - if len(stream) != len(buffer): - return False - if stream != buffer: - return False - return True - -def build_dim(dim): - if len(dim) == 0: - return "" - else: - return "(%s)"%( ",".join(dim) ) - -def build_dim_colons(v): - d = v.dim - if d == []: - return "" - else: - x = map(lambda x: ":", d) - return "(%s)"%(','.join(x)) - - -import error -def find_subname(line): - buffer = line.lower - if not buffer.endswith(')'): - buffer += "()" - buffer = buffer.split('(') - buffer = buffer[0].split() - if len(buffer) < 2: - error.fail(line,"Syntax Error") - return buffer[-1] - -def make_single(l): - d = {} - for x in l: - d[x] = True - return d.keys() - -def flatten(l): - if type(l) == list: - result = [] - for i in range(len(l)): - elem = l[i] - result += flatten(elem) - return result - else: - return [l] - -def dimsize(x): - assert isinstance(x,str) - buffer = x.split(':') - if len(buffer) == 1: - return x - else: - assert len(buffer) == 2 - size = "" - b0, b1 = buffer - if b0.replace('-','').isdigit() and b1.replace('-','').isdigit(): - size = str( int(b1) - int(b0) + 1 ) + try: + text_ref = open(filename, 'rb').read() + except IOError: + return False else: - if b0.replace('-','').isdigit(): - size = "(%s) - (%d)"%(b1,int(b0)-1) - elif b1.replace('-','').isdigit(): - size = "(%d) - (%s)"%(int(b1)+1,b0) - else: - size = "(%s) - (%s) + 1"%(b1,b0) - return size + return digest(text_ref) == digest(text) -def put_info(text,filename): - assert type(text) == list - if len(text) > 0: - assert type(text[0]) == tuple - from irpf90_t import Line - assert type(text[0][0]) == list - assert isinstance(text[0][1], Line) - lenmax = 80 - len(filename) - format = "%"+str(lenmax)+"s ! %s:%4s" - for vars,line in text: - line.text = format%(line.text.ljust(lenmax),line.filename,str(line.i)) - return text -import cPickle as pickle -import os, sys -def parallel_loop(f,source): - pidlist = range(NTHREADS) +def lazy_write_file(filename, text, conservative=False,touch=False): + # (str, str, bool) -> None + '''Write data lazily in filename location. - src = [ [] for i in xrange(NTHREADS) ] - index = 0 - try: - source = map( lambda x: (len(x[1]),(x[0], x[1])), source ) - source.sort() - source = map( lambda x: x[1], source ) - except: - pass - for i in source: - index += 1 - if index == NTHREADS: - index = 0 - src[index].append(i) + Note: + If convervative is set, we don't overwrite. + ''' - thread_id = 0 - fork = 1 - r = range(0,NTHREADS) - for thread_id in xrange(1,NTHREADS): - r[thread_id], w = os.pipe() - fork = os.fork() - if fork == 0: - os.close(r[thread_id]) - w = os.fdopen(w,'w') - break + if not os.path.exists(filename) or not cached_file(filename, text) and not conservative: + with open(filename, 'w') as f: + f.write(text) + elif touch: + os.utime(filename,None) + +def listdir(directory, abspath=False): + #(str, bool) -> List[str] + '''Replacement of the std:listdir but with the possibility to get the abosulte path''' + + l_filename = os.listdir(directory) + if not abspath: + return l_filename else: - os.close(w) - r[thread_id] = os.fdopen(r[thread_id],'r') - pidlist[thread_id] = fork - thread_id = 0 + return [os.path.abspath(os.path.join(directory, f)) for f in l_filename] - result = [] - for filename, text in src[thread_id]: - result.append( (filename, f(filename,text)) ) - result.sort() +def check_output(*popenargs, **kwargs): + """Run command with arguments and return its output as a byte string. + Backported from Python 2.7 as it's implemented as pure python on stdlib. + >>> check_output(['/usr/bin/python', '--version']) + Python 2.6.2 + """ + import subprocess + process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs) + output, unused_err = process.communicate() + retcode = process.poll() + if retcode: + cmd = kwargs.get("args") + if cmd is None: + cmd = popenargs[0] + error = subprocess.CalledProcessError(retcode, cmd) + error.output = output + raise error + return output - if fork == 0: - pickle.dump(result,w,-1) - w.close() - os._exit(0) - - for i in xrange(1,NTHREADS): - result += pickle.load(r[i]) - r[i].close() - os.waitpid(pidlist[i],0)[1] - - return result +# ~#~#~#~#~# +# L i s t +# ~#~#~#~#~# +def uniquify(l,sort=False): + # (Iter, bool) -> List[Any] + '''Uniquify a immutable iterable. Don't preserve the order''' + r = list(set(l)) + if not sort: + return r + else: + return sorted(r) -if __name__ == '__main__': - print "10",dimsize("10") #-> "10" - print "0:10",dimsize("0:10") # -> "11" - print "0:x",dimsize("0:x") # -> "x+1" - print "-3:x",dimsize("-3:x") # -> "x+1" - print "x:y",dimsize("x:y") # -> "y-x+1" - print "x:5",dimsize("x:5") # -> "y-x+1" +def OrderedUniqueList(l): + # (Iter, bool) -> List[Any] + '''Uniquify a immutable iterable. Don't preserve the order''' + return sorted(set(l)) + +def flatten(l_2d): + # (List [ List[Any] ]) -> List + '''Construct a copy of the 2d list collapsed into one dimension. + + Note: + - We collapse in a C-style fashion (row_major). + ''' + + return [item for l_1d in l_2d for item in l_1d] + + +# ~#~#~#~#~# +# I R P _ R E L A T E D +# ~#~#~#~#~# +def build_dim(l_dim, colons=False): + # (List[str],bool) -> str + '''Contruct a valid fortran90 array dimension code from a list dimension + + Exemple: + [4,8] -> (4,8) if not colons + [4,8] -> (:,:) if colons + + ''' + if not l_dim: + return "" + + l_dim_colons = [':'] * len(l_dim) if colons else l_dim + + return "(%s)" % (",".join(l_dim_colons)) + + +def build_use(l_ent, d_ent): + # (List, Dict[str,Entity]) -> list + '''Contruct the fortran90 'use' statement for the list of entity''' + return OrderedUniqueList(" use %s" % d_ent[x].fmodule for x in l_ent) + +def build_call_provide(l_ent, d_ent): + # (List, Dict[str,Entity]) -> list + '''Construct the fortran 90 call the provider needed by the list of entity''' + def fun(x): + return [ " if (.not.%s_is_built) then" % x, + " call provide_%s" % x, + " endif"] + + # Get the corect name (in the case of multiple provider line) + l_same_as = OrderedUniqueList(d_ent[x].same_as for x in l_ent) + return flatten(map(fun, l_same_as)) diff --git a/src/variable.py b/src/variable.py deleted file mode 100644 index 56a61a8..0000000 --- a/src/variable.py +++ /dev/null @@ -1,685 +0,0 @@ -#!/usr/bin/env python -# IRPF90 is a Fortran90 preprocessor written in Python for programming using -# the Implicit Reference to Parameters (IRP) method. -# Copyright (C) 2009 Anthony SCEMAMA -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Anthony Scemama -# LCPQ - IRSAMC - CNRS -# Universite Paul Sabatier -# 118, route de Narbonne -# 31062 Toulouse Cedex 4 -# scemama@irsamc.ups-tlse.fr - - -from irpf90_t import * -from util import * -import error -from command_line import command_line - -class Variable(object): - - ############################################################ - def __init__(self,text,label,name = None): - assert type(text) == list - assert len(text) > 0 - assert type(text[0]) == Begin_provider - self.label = label - self.text = text - if name is not None: - self._name = name - - ############################################################ - def is_touched(self): - if '_is_touched' not in self.__dict__: - from variables import variables - result = self.is_read - for i in self.children: - if variables[i].is_touched: - result = True - break - self._is_touched = result - return self._is_touched - is_touched = property(is_touched) - - ############################################################ - def has_openmp(self): - if '_has_openmp' not in self.__dict__: - self._has_openmp = False - self.builder() - return self._has_openmp - has_openmp = property(has_openmp) - - ############################################################ - def is_written(self): - if '_is_written' not in self.__dict__: - from variables import variables - result = False - for i in self.parents: - if variables[i].is_written: - result = True - break - self._is_written = result - return self._is_written - is_written = property(is_written) - - ############################################################ - def is_read(self): - if '_is_read' not in self.__dict__: - from variables import variables - result = False - for i in self.parents: - if variables[i].is_read: - result = True - break - self._is_read = result - return self._is_read - is_read = property(is_read) - - ############################################################ - def is_main(self): - if '_is_main' not in self.__dict__: - self._is_main = (self.name == self.same_as) - return self._is_main - is_main = property(is_main) - - ############################################################ - def name(self): - '''Name is lowercase''' - if '_name' not in self.__dict__: - buffer = None - text = self.text - for line in text: - if type(line) == Begin_provider: - self._name = line.filename[1] - break - return self._name - name = property(name) - - ############################################################ - def doc(self): - if '_doc' not in self.__dict__: - text = self.text - buffer = filter(lambda l:type(l) == Doc, text) - self._doc = map(lambda l: l.text.lstrip()[1:], buffer) - if buffer == []: - error.warn(None,"Variable %s is not documented"%(self.name)) - return self._doc - doc = property(doc) - - ############################################################ - def documented(self): - if '_documented' not in self.__dict__: - self._documented = (self.doc != []) - return self._documented - documented = property(documented) - - ############################################################ - def includes(self): - if '_includes' not in self.__dict__: - self._includes = [] - text = self.text - for line in filter(lambda x: type(x) == Include,text): - self._includes.append(line.filename) - make_single(self._includes) - return self._includes - includes = property(includes) - - ############################################################ - def calls(self): - if '_calls' not in self.__dict__: - self._calls = [] - text = self.text - for line in filter(lambda x: type(x) == Call,text): - sub = line.text.split('(',1)[0].split()[1].lower() - self._calls.append(sub) - make_single(self._calls) - return self._calls - calls=property(fget=calls) - - ############################################################ - def others(self): - if '_others' not in self.__dict__: - result = [] - append = result.append - f = lambda l: type(l) in [Begin_provider, Cont_provider] - text = self.text - lines = filter(f, text) - for line in lines: - append(line.filename[1]) - result.remove(self.name) - self._others = result - return self._others - others = property(others) - - ############################################################ - def same_as(self): - if '_same_as' not in self.__dict__: - if type(self.line) == Begin_provider: - result = self.name - else: - result = self.text[0].filename[1] - self._same_as = result - return self._same_as - same_as = property(same_as) - - ############################################################ - def allocate(self): - if '_allocate' not in self.__dict__: - if not self.is_main: - self._allocate = [] - else: - from variables import variables - def f(var): - return variables[var].dim != [] - self._allocate = filter ( f, self.others + [self.name] ) - return self._allocate - allocate = property(allocate) - - ############################################################ - def dim(self): - if '_dim' not in self.__dict__: - line = self.line.text.split('!')[0] - buffer = line.replace(']','').split(',',2) - if len(buffer) == 2: - self._dim = [] - else: - buffer = buffer[2].strip()[1:-1].split(',') - self._dim = map(strip,buffer) - return self._dim - dim = property(dim) - - ############################################################ - def type(self): - if '_type' not in self.__dict__: - line = self.line.text - buffer = line.split(',')[0] - try: - buffer = buffer.split('[')[1].strip() - except IndexError: - error.fail(None,"Error in definition of %s."%(self.name)) - if self.dim != []: - buffer = "%s, allocatable"%(buffer) - self._type = buffer - return self._type - type = property(type) - - ############################################################ - def fmodule(self): - if '_fmodule' not in self.__dict__: - self._fmodule = self.line.filename[0].replace('/','__').split('.irp.f')[0]+'_mod' - return self._fmodule - fmodule = property(fmodule) - - ############################################################ - def regexp(self): - if '_regexp' not in self.__dict__: - import re - self._regexp = re.compile( \ - r"([^a-z0-9'\"_]|^)%s([^a-z0-9_]|$)"%(self.name),re.I) - return self._regexp - regexp = property(regexp) - - ############################################################ - def line(self): - if '_line' not in self.__dict__: - f = lambda l: type(l) in [Begin_provider, Cont_provider] - text = self.text - lines = filter(f, text) - for line in lines: - buffer = line.filename[1] - if self._name == buffer: - self._line = line - break - assert '_line' in self.__dict__ - return self._line - line = property(line) - - ############################################################ - def header(self): - if '_header' not in self.__dict__: - name = self.name - self._header = [ " %s :: %s %s"%(self.type, name, build_dim_colons(self) ) ] - if command_line.coarray: - if self.dim == []: - self._header[0] += " [*]" - else: - self._header[0] += " [:]" - if self.dim != [] and command_line.align != '1': - self._header += [" !DIR$ ATTRIBUTES ALIGN: %s :: %s"%(command_line.align,name)] - if self.is_main: - self._header += [ " logical :: %s_is_built = .False."%(name) ] - return self._header - header = property(header) - - ############################################################ - def toucher(self): - if '_toucher' not in self.__dict__: - if not self.is_main: - self._toucher = [] - else: - from modules import modules - from variables import variables - if '_needed_by' not in self.__dict__: - import parsed_text - parents = self.parents - parents.sort() - mods = map(lambda x: variables[x].fmodule, parents) - mods = make_single(mods)+[self.fmodule] - name = self.name - result = [ "subroutine touch_%s"%(name) ] - result += map(lambda x: " Use %s"%(x),mods) - result.append(" implicit none") - if command_line.do_debug: - length = str(len("touch_%s"%(name))) - result += [ " character*(%s) :: irp_here = 'touch_%s'"%(length,name) ] - if command_line.do_debug: - result += [ " call irp_enter(irp_here)" ] - result += map( lambda x: " %s_is_built = .False."%(x), parents) - result.append(" %s_is_built = .True."%(name)) - if command_line.do_debug: - result.append(" call irp_leave(irp_here)") - result.append("end subroutine touch_%s"%(name)) - result.append("") - self._toucher = result - return self._toucher - toucher = property(toucher) - - ########################################################## - def locker(self): - if '_locker' not in self.__dict__: - if not command_line.do_openmp: - self._locker = [] - else: - from modules import modules - from variables import variables - name = self.name - result = [ "subroutine irp_lock_%s(set)"%(name) ] - result += [ " use omp_lib", - " implicit none", - " logical, intent(in) :: set", - " integer(kind=omp_nest_lock_kind),save :: %s_lock"%(name), - " integer,save :: ifirst", - ] - if command_line.do_debug: - length = str(len("irp_lock_%s"%(name))) - result += [ " character*(%s) :: irp_here = 'irp_lock_%s'"%(length,name), - " call irp_enter(irp_here)" ] - result += [ " if (ifirst == 0) then", - " ifirst = 1", - " call omp_init_nest_lock(%s_lock)"%(name), - " endif", - " if (set) then", - " call omp_set_nest_lock(%s_lock)"%(name), - " else", - " call omp_unset_nest_lock(%s_lock)"%(name), - " endif", - ] - if command_line.do_debug: - result.append(" call irp_leave(irp_here)") - result.append("end subroutine irp_lock_%s"%(name)) - result.append("") - self._locker = result - return self._locker - locker = property(locker) - - ########################################################## - def reader(self): - if '_reader' not in self.__dict__: - if not self.is_main: - self._reader = [] - else: - if '_needs' not in self.__dict__: - import parsed_text - from variables import variables - name = self.name - result = [ \ - "subroutine reader_%s(irp_num)"%(name), - " use %s"%(self.fmodule), - " implicit none", - " character*(*), intent(in) :: irp_num", - " logical :: irp_is_open", - " integer :: irp_iunit" ] - if command_line.do_debug: - length = len("reader_%s"%(self.name)) - result += [\ - " character*(%d) :: irp_here = 'reader_%s'"%(length,name), - " call irp_enter(irp_here)" ] - result += map(lambda x: " call reader_%s(irp_num)"%(x),self.needs) - result += [ \ - " irp_is_open = .True.", - " irp_iunit = 9", - " do while (irp_is_open)", - " irp_iunit = irp_iunit+1", - " inquire(unit=irp_iunit,opened=irp_is_open)", - " enddo"] - for n in [ name ]+self.others: - result += [\ - " open(unit=irp_iunit,file='irpf90_%s_'//trim(irp_num),form='FORMATTED',status='OLD',action='READ')"%(n), - " read(irp_iunit,*) %s%s"%(n,build_dim_colons(variables[n])), - " close(irp_iunit)" ] - result += [ \ - " call touch_%s"%(name), - " %s_is_built = .True."%(name) ] - if command_line.do_debug: - result.append(" call irp_leave(irp_here)") - result.append("end subroutine reader_%s"%(name)) - result.append("") - self._reader = result - return self._reader - reader = property(reader) - - ########################################################## - def writer(self): - if '_writer' not in self.__dict__: - if not self.is_main: - self._writer = [] - else: - from variables import variables - if '_needs' not in self.__dict__: - import parsed_text - name = self.name - result = [ \ - "subroutine writer_%s(irp_num)"%(name), - " use %s"%(self.fmodule), - " implicit none", - " character*(*), intent(in) :: irp_num", - " logical :: irp_is_open", - " integer :: irp_iunit" ] - if command_line.do_debug: - length = len("writer_%s"%(self.name)) - result += [\ - " character*(%d) :: irp_here = 'writer_%s'"%(length,name), - " call irp_enter(irp_here)" ] - result += [ \ - " if (.not.%s_is_built) then"%(self.same_as), - " call provide_%s"%(self.same_as), - " endif" ] - result += map(lambda x: " call writer_%s(irp_num)"%(x),self.needs) - result += [ \ - " irp_is_open = .True.", - " irp_iunit = 9", - " do while (irp_is_open)", - " irp_iunit = irp_iunit+1", - " inquire(unit=irp_iunit,opened=irp_is_open)", - " enddo" ] - for n in [ name ] + self.others: - result += [\ - " open(unit=irp_iunit,file='irpf90_%s_'//trim(irp_num),form='FORMATTED',status='UNKNOWN',action='WRITE')"%(n), - " write(irp_iunit,*) %s%s"%(n,build_dim_colons(variables[n])), - " close(irp_iunit)" ] - if command_line.do_debug: - result.append(" call irp_leave(irp_here)") - result.append("end subroutine writer_%s"%(name)) - result.append("") - self._writer = result - return self._writer - writer = property(writer) - - ########################################################## - def free(self): - if '_free' not in self.__dict__: - name = self.name - result = [ "!","! >>> FREE %s"%(name), - " %s_is_built = .False."%(self.same_as) ] - if self.dim != []: - if command_line.do_memory: - result += [ \ - " if (allocated(%s)) then"%(name), - " deallocate (%s)"%(name), - " print *, 'Deallocating %s'"%(name), - " endif" ] - else: - result += [ \ - " if (allocated(%s)) then"%(name), - " deallocate (%s)"%(name), - " endif" ] - result.append("! <<< END FREE") - self._free = result - return self._free - free = property(free) - - ########################################################## - def provider(self): - if '_provider' not in self.__dict__: - if not self.is_main: - self._provider = [] - else: - if '_to_provide' not in self.__dict__: - import parsed_text - from variables import variables, build_use, call_provides - name = self.name - same_as = self.same_as - - def build_alloc(name): - self = variables[name] - if self.dim == []: - return [] - - def do_size(): - result = " print *, ' size: (" - result += ','.join(self.dim) - return result+")'" - - def check_dimensions(): - result = map(lambda x: "(%s>0)"%(dimsize(x)), self.dim) - result = ".and.".join(result) - result = " if (%s) then"%(result) - return result - - def dimensions_OK(): - result = [ " irp_dimensions_OK = .True." ] - for i,k in enumerate(self.dim): - result.append(" irp_dimensions_OK = irp_dimensions_OK.AND.(SIZE(%s,%d)==(%s))"%(name,i+1,dimsize(k))) - return result - - def do_allocate(): - if command_line.coarray: - result = " allocate(%s(%s)[*],stat=irp_err)" - else: - result = " allocate(%s(%s),stat=irp_err)" - result = result%(name,','.join(self.dim)) - if command_line.do_memory: - tmp = "\n print *, %s, 'Allocating %s(%s)'" - d = ','.join(self.dim) - result += tmp%('size('+name+')',name,d) - return result - - result = [ " if (allocated (%s) ) then"%(name) ] - result += dimensions_OK() - result += [\ - " if (.not.irp_dimensions_OK) then", - " deallocate(%s,stat=irp_err)"%(name), - " if (irp_err /= 0) then", - " print *, irp_here//': Deallocation failed: %s'"%(name), - do_size(), - " endif"] - if command_line.do_memory: - result += [\ - " print *, 'Deallocating %s'"%(name) ] - result.append(check_dimensions()) - result.append(do_allocate()) - result += [\ - " if (irp_err /= 0) then", - " print *, irp_here//': Allocation failed: %s'"%(name), - do_size(), - " endif", - " endif", - " endif", - " else" ] - result.append(check_dimensions()) - result.append(do_allocate()) - result += [\ - " if (irp_err /= 0) then", - " print *, irp_here//': Allocation failed: %s'"%(name), - do_size(), - " endif", - " endif", - " endif" ] - return result - - result = [] - if command_line.directives and command_line.inline in ["all","providers"]: - result += [ "!DEC$ ATTRIBUTES FORCEINLINE :: provide_%s"%(name) ] - result += [ "subroutine provide_%s"%(name) ] - result += build_use( [same_as]+self.to_provide ) - if command_line.do_openmp: - result += [" use omp_lib"] - result.append(" implicit none") - length = len("provide_%s"%(name)) - result += [\ - " character*(%d) :: irp_here = 'provide_%s'"%(length,name), - " integer :: irp_err ", - " logical :: irp_dimensions_OK", - "!$ integer :: nthreads"] - if command_line.do_openmp: - result.append(" call irp_lock_%s(.True.)"%(same_as)) - if command_line.do_assert or command_line.do_debug: - result.append(" call irp_enter(irp_here)") - result += call_provides(self.to_provide) - result += flatten( map(build_alloc,[self.same_as]+self.others) ) - result += [ " if (.not.%s_is_built) then"%(same_as), - " call bld_%s"%(same_as), - " %s_is_built = .True."%(same_as), "" ] - result += [ " endif" ] - if command_line.do_assert or command_line.do_debug: - result.append(" call irp_leave(irp_here)") - if command_line.do_openmp: - result.append(" call irp_lock_%s(.False.)"%(same_as)) - result.append("end subroutine provide_%s"%(name) ) - result.append("") - self._provider = result - return self._provider - provider = property(provider) - - ########################################################## - def builder(self): - if '_builder' not in self.__dict__: - if not self.is_main: - self._builder = [] - else: - import parsed_text - from variables import build_use, call_provides - for filename,buffer in parsed_text.parsed_text: - if self.line.filename[0].startswith(filename): - break - text = [] - same_as = self.same_as - inside = False - for vars,line in buffer: - if type(line) == Begin_provider: - if line.filename[1] == same_as: - inside = True - vars = [] - if inside: - text.append( (vars,line) ) - text += map( lambda x: ([],Simple_line(line.i,x,line.filename)), call_provides(vars) ) - if command_line.do_profile and type(line) == Begin_provider: - text.append( ( [], Declaration(line.i," double precision :: irp_rdtsc, irp_rdtsc1, irp_rdtsc2",line.filename) ) ) - text.append( ( [], Simple_line(line.i," irp_rdtsc1 = irp_rdtsc()",line.filename) ) ) - if type(line) == End_provider: - if inside: - break - name = self.name - text = parsed_text.move_to_top(text,Declaration) - text = parsed_text.move_to_top(text,Implicit) - text = parsed_text.move_to_top(text,Use) - text = map(lambda x: x[1], text) -# inside_omp = False - for line in filter(lambda x: type(x) not in [ Begin_doc, End_doc, Doc], text): - if type(line) == Begin_provider: - result = [] - if command_line.directives and command_line.inline in ["all","builders"]: - result += [ "!DEC$ ATTRIBUTES INLINE :: bld_%s"%(same_as) ] - result += [ "subroutine bld_%s"%(name) ] - result += build_use([name]+self.needs) - elif type(line) == Cont_provider: - pass - elif type(line) == End_provider: - if command_line.do_profile: - result += [ " irp_rdtsc2 = irp_rdtsc()" , - " call irp_set_timer(%d,(irp_rdtsc2-irp_rdtsc1))"%self.label ] - result.append( "end subroutine bld_%s"%(name) ) - break - elif type(line) == Openmp: - # Detect OpenMP blocks - buffer = line.text.lower().split() - if buffer[1] == "parallel": -# inside_omp = True - self._has_openmp = True -# if buffer[1] == "end" and buffer[2] == "parallel": -# inside_omp = False - result.append(line.text) - else: -# if inside_omp: -# if type(line) in [ Provide_all, Provide, Touch, SoftTouch ]: -# error.fail(line,str(type(line))+"is not allowed in an OpenMP block.") - result.append(line.text) - self._builder = result - return self._builder - builder = property(builder) - - ########################################################## - def children(self): - if '_children' not in self.__dict__: - if not self.is_main: - self._children = [] - from variables import variables - if '_needs' not in self.__dict__: - import parsed_text - result = [] - for x in self.needs: - result.append(x) - try: - result += variables[x].children - except RuntimeError: - pass # Exception will be checked after - self._children = make_single(result) - if self.name in result: - error.fail(self.line,"Cyclic dependencies:\n%s"%(str(self._children))) - return self._children - children = property(children) - - ########################################################## - def parents(self): - if '_parents' not in self.__dict__: - if not self.is_main: - self._parents = [] - else: - from variables import variables - if '_needed_by' not in self.__dict__: - import parsed_text - result = [] - for x in self.needed_by: - result.append(x) - try: - result += variables[x].parents - except RuntimeError: - pass # Exception will be checked after - self._parents = make_single(result) - if self.name in result: - error.fail(self.line,"Cyclic dependencies:\n%s"%(str(self._parents))) - return self._parents - parents = property(parents) - -###################################################################### -if __name__ == '__main__': - from preprocessed_text import preprocessed_text - from variables import variables - #for v in variables.keys(): - # print v - for line in variables['e_loc'].parents: - print line diff --git a/src/variables.py b/src/variables.py deleted file mode 100644 index cf2a409..0000000 --- a/src/variables.py +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env python -# IRPF90 is a Fortran90 preprocessor written in Python for programming using -# the Implicit Reference to Parameters (IRP) method. -# Copyright (C) 2009 Anthony SCEMAMA -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Anthony Scemama -# LCPQ - IRSAMC - CNRS -# Universite Paul Sabatier -# 118, route de Narbonne -# 31062 Toulouse Cedex 4 -# scemama@irsamc.ups-tlse.fr - - -from variable import * -from irpf90_t import * -from command_line import command_line -from util import * - -###################################################################### -def create_variables(): - from preprocessed_text import preprocessed_text - result = {} - icount = 0 - for filename, text in preprocessed_text: - buffer = [] - inside = False - for line in text: - if type(line) == Begin_provider: - inside = True - if inside: - buffer.append(line) - if type(line) == End_provider: - inside = False - icount += 1 - v = Variable(buffer,icount) - result[v.name] = v - for other in v.others: - result[other] = Variable(buffer,icount,other) - buffer = [] - return result - -variables = create_variables() - -###################################################################### -def build_use(vars): - result = map(lambda x: " use %s"%(variables[x].fmodule), vars) - result = make_single(result) - return result - -###################################################################### -def call_provides(vars,opt=False): - vars = make_single( map(lambda x: variables[x].same_as, vars) ) - if opt: - all_children = flatten( map(lambda x: variables[x].children, vars )) - vars = filter(lambda x: x not in all_children,vars) - def fun(x): - result = [] - result += [ \ - " if (.not.%s_is_built) then"%(x) ] - result += [ \ - " call provide_%s"%(x) ] - result += [ \ - " endif" ] - return result - - result = flatten ( map (fun, vars) ) - return result - -###################################################################### -if __name__ == '__main__': - for v in variables.keys(): - print v diff --git a/src/version.py b/src/version.py index 26a0a01..1b23640 100644 --- a/src/version.py +++ b/src/version.py @@ -1 +1 @@ -version = "1.6.7" +version = "2.0.0" diff --git a/src/vim.py b/src/vim.py index 3012393..b0d6778 100644 --- a/src/vim.py +++ b/src/vim.py @@ -39,7 +39,7 @@ def install(): file.close() if not os.access(VIM+"/syntax",os.F_OK): os.mkdir(VIM+"/syntax") - wd = os.path.abspath(os.path.dirname(__file__))+"/../vim" + wd = os.path.abspath(os.path.dirname(__file__)) os.symlink(wd+"/irpf90.vim",VIM+"/syntax/irpf90.vim") except: pass