diff --git a/example/Makefile b/example/Makefile index 76d3850..c026e2a 100644 --- a/example/Makefile +++ b/example/Makefile @@ -1,13 +1,69 @@ -IRPF90 = python ../src/irpf90.py -I input -a -d -FC = ifort -FCFLAGS= -O2 -NINJA = +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/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/build_file.py b/src/build_file.py new file mode 100644 index 0000000..c4428ab --- /dev/null +++ b/src/build_file.py @@ -0,0 +1,526 @@ +#!/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$(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$(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$(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] + needed_modules += [ + "%s.irp.o" % (x.filename) for x in l_module if x.name in t.needed_modules_usr + ] + + 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_module = True + if not inline_module: + #Wrong name, this not work! + #list_of_includes = ' '.join(map(lambda x: dress(x, in_root=True), t.includes)) + raise NotImplemented + else: + 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$(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_F90}", + " short_out = {short_target_o}", + "" + ] + + l_build_make += [ + "{target_module_o}: {target_module_F90} | {list_of_includes} {list_of_modules_irp}", + "\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 -r '^\s*program' *.irp.f | awk '{print $$2}')", + "", + ".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/create_man.py b/src/create_man.py index 63d6512..5479dc0 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/cython_setup.py b/src/cython_setup.py index 6bb2e85..9010539 100755 --- a/src/cython_setup.py +++ b/src/cython_setup.py @@ -29,24 +29,13 @@ from distutils.extension import Extension from Cython.Distutils import build_ext import os -to_remove = """cython_setup.py version.py command_line.py""".split() +to_remove = """__init__.py 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 -) - - - +for f in os.listdir('.') if f.emswith(".py") and not f in to_remove: + module = f.split('.')[0] + ext_modules.append(Extension(module,list(f))) +setup(name = 'IRPF90 extensions', + cmdclass = {'build_ext': build_ext}, + ext_modules = ext_modules) diff --git a/src/entity.py b/src/entity.py new file mode 100644 index 0000000..5d9d1ec --- /dev/null +++ b/src/entity.py @@ -0,0 +1,729 @@ +#!/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(lline_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 + l_builder_text_raw = [ + x[1] for x in parsed_text.move_to_top_list(text, [Declaration, Implicit, Use]) + ] + result.extend( + line.text for line in l_builder_text_raw + 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/error.py b/src/error.py deleted file mode 100644 index 811759c..0000000 --- a/src/error.py +++ /dev/null @@ -1,66 +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 sys -from irpf90_t import * -from command_line import command_line -do_warnings = command_line.do_warnings - -###################################################################### -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) - - -###################################################################### -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) - - -###################################################################### -if __name__ == '__main__': - line = Empty_line(3,"empty", "testfile") - fail(line, "Message") - 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 4437c0f..fe321bc 100644 --- a/src/irp_stack.py +++ b/src/irp_stack.py @@ -253,13 +253,8 @@ subroutine irp_trace 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..21fb198 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,74 @@ # 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_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_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 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_codelet: + import profile + profile.build_rdtsc() + import codelet + codelet.run() - if command_line.do_codelet: - import profile - profile.build_rdtsc() - import codelet - codelet.run() + if not command_line.do_run: + return - if not command_line.do_run: - return + comm_world.create_buildfile(command_line.do_ninja) + comm_world.write_modules() + + comm_world.create_touches() + comm_world.create_man() - init() + if command_line.do_profile: + import profile + profile.run() - import irp_stack - irp_stack.create() - - import makefile - makefile.create() - - 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/src/irpf90_t.py b/src/irpf90_t.py index 68ffca9..b58a78c 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' +] +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..198200a 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..6d86467 --- /dev/null +++ b/src/irpy_files.py @@ -0,0 +1,319 @@ +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)''' + import parsed_text + d_entity = self.d_entity + d_routine = self.d_routine + + # ~ # ~ # ~ + # F i r s t R o u n d + # ~ # ~ # ~ + 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) + + #Touch routine + parsed_text.build_sub_needs(parsed_text_0, d_routine) + parsed_text.parsed_moved_to_top(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) + + parsed_text.parsed_moved_to_top(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/locks.py b/src/locks.py deleted file mode 100644 index 892d0cd..0000000 --- a/src/locks.py +++ /dev/null @@ -1,58 +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 command_line import command_line - -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/src/makefile.py b/src/makefile.py deleted file mode 100644 index 8b1ff56..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..2885b62 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,227 @@ # 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 = [] + + for vars, line in text: + 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 = [] + + for vars, line in text: + if isinstance(line, (Subroutine, Function, Program,Interface,Module)): + inside += 1 + + 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, 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', '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 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 [" %s" % line.text for _, line in self.residual_text_use_dec.dec] + + @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 + 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 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 + from parsed_text import move_to_top_list + return [line.text for _, line in move_to_top_list(result, [Declaration, Implicit, Use])] - 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 + @irpy.lazy_property + def needed_modules(self): + l = set(x.split()[1] for x in self.generated_text + self.head + self.residual_text + if x.lstrip().startswith("use ")) - 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) + if self.name in l: + l.remove(self.name) - def use(self): - if '_use' not in self.__dict__: - self.residual_text - return self._use - use = property(use) + return l - def dec(self): - if '_dec' not in self.__dict__: - self.residual_text - return self._dec - dec = property(dec) + + @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")] - 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) - -###################################################################### - -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 b6d98b8..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", "irp_rdtsc.o" ] - l_common_s += [ "irp_profile.irp.F90", "irp_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..53cd4b6 100644 --- a/src/parsed_text.py +++ b/src/parsed_text.py @@ -24,526 +24,484 @@ # 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)) ) - 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) + for i, line in enumerate(text): -update_variables() -parsed_text = get_parsed_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: + 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): + 'This function is Unpure' + 'test will be modify' + + assert type(text) == list + assert set(it).issubset([NoDep, Declaration, Implicit, Use, Cont_provider]) + + from collections import defaultdict + d_permutation = defaultdict(list) + + # ~ # ~ # ~ + # G e t P e r m u t a t i o n + # ~ # ~ # ~ + + inside = False + for i, (l_var, line) in enumerate(text): + t = type(line) + if t in [Begin_provider, Program, Subroutine, Function]: + begin = i + inside = True + elif t in [End_provider, End]: + inside = False + elif inside and t in it: + d_permutation[t].append([begin, (l_var, line), i]) + + # ~ # ~ # ~ + # O r d e r t h e m + # ~ # ~ # ~ + + d_insert = defaultdict(list) + d_remove = defaultdict(list) + for t in reversed(it): + for begin, tline, idx_remove in d_permutation[t]: + d_insert[begin].append(tline) + d_remove[begin].append(idx_remove) + + # ~ # ~ # ~ + # D o t h e m + # ~ # ~ # ~ + + for idx in sorted(d_remove.keys()): + + padding = 0 + for tline in d_insert[idx]: + text.insert(idx + padding + 1, tline) + padding += 1 + + for idx_remove in sorted(d_remove[idx]): + text.pop(idx_remove + padding) + padding += -1 + return text + + +def parsed_moved_to_top(parsed_text): + 'This subroutine is unpur:' + ' inout(parsed_text)' + + l = [NoDep, Declaration, Implicit, Use, Cont_provider] + for _, text in parsed_text: + move_to_top_list(text, l) ###################################################################### +def build_sub_needs(parsed_text, d_subroutine): + #(List[ Tuple[List[Entity], Tuple[int,List[Line]] ]]) -> None + '''Set the needs, and provides arguements of Routine present in parsed_text + + Note: + This function is unpure + ''' -def move_to_top(text,t): - assert type(text) == list - assert t in [ NoDep, Declaration, Implicit, Use, Cont_provider ] + 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)] - 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)) + 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)] - return text - -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 - - -###################################################################### -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 - -build_sub_needs() + 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): + '''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() + 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") - result.reverse() + result.reverse() - # 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 + # 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 - #return parallel_loop(func,parsed_text) + 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 632066a..f00cdc1 100644 --- a/src/preprocessed_text.py +++ b/src/preprocessed_text.py @@ -26,18 +26,18 @@ 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_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,874 +46,900 @@ 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 } -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) - 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 - 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) - 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''' + result = [] + + def remove_after_bang(line): + match = re_comment.match(line) + if not match: + return line + else: + return ''.join(str_ for str_ in match.groups() if str_).rstrip() + + 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 == "" 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 = "" + 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: - 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): - '''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): + '''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] + 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: + logger.warning("You have maybe more close statement than open statement (%s) (%s)",line.filename,t_end) + sys.exit(1) + elif n_end < n_begin: + logger.warning('You have mayble more end statement than open statenemt for (%s) (%s)' % (line.filename, t_end)) + 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) + 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: + return f.read() + + @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 15158b2..4b3dbce 100644 --- a/src/profile.py +++ b/src/profile.py @@ -60,7 +60,7 @@ def build_rdtsc(): # threading.Thread(target=t).start() def build_module(): - from variables import variables + from irpy_files import variables data = """ module irp_timer double precision :: irp_profile(3,%(n)d) 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..31a4532 --- /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..3d44d1e 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=True): + # (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 43d0d59..0000000 --- a/src/variable.py +++ /dev/null @@ -1,697 +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 - def print_dot(x,done): - if x.children == []: - return - for i in x.needs: - pair = (x.name, i) - if pair not in done: - print "%s -> %s"%( x.name, i ) - done[pair] = None - print_dot(variables[i],done) - - print "digraph G { " -# print_dot(variables['e_loc'], {}) - print_dot(variables['psi_value'], {}) - print "}" 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 cad6119..1b23640 100644 --- a/src/version.py +++ b/src/version.py @@ -1 +1 @@ -version = "1.6.9" +version = "2.0.0"