diff options
author | David Robillard <d@drobilla.net> | 2019-03-17 17:31:05 +0100 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2019-03-17 17:31:05 +0100 |
commit | 406f89271452fdb573c7e28113b1ed08ff2b4eda (patch) | |
tree | d2dcbaf61f3749f73dc7a5e10d3fc6cd5e6e129a /Tools/fc_scan.py | |
parent | 7983a5aae615290d04fd43cbc2752f8cf4a46d10 (diff) | |
download | suil-406f89271452fdb573c7e28113b1ed08ff2b4eda.tar.gz suil-406f89271452fdb573c7e28113b1ed08ff2b4eda.tar.bz2 suil-406f89271452fdb573c7e28113b1ed08ff2b4eda.zip |
Squashed 'waflib/' changes from 915dcb1..e7a29b6
e7a29b6 Upgrade to waf 2.0.15
8280f9d Add command for running executables from the build directory
8073c1a Make make_simple_dox() safe in case of exception
70d03b8 Avoid use of global counter hacks for configuration display
b7d689a Rewrite test framework
94deadf Automatically add options and move add_flags() to options context
f4259ee Reduce system include path noise
927b608 Automatically display configuration header
c44b8f3 Set line justification from a constant in the wscript
a48e26f Automatically detect if wscript has a test hook
ef66724 Save runtime variables in the environment
63bcbcd Clean up TestContext
b1d9505 Add ExecutionContext for setting runtime environment
387c1df Add show_diff() and test_file_equals() utilities
29d4d29 Fix in-tree library paths
9fde01f Add custom configuration context
6d3612f Add lib_path_name constant
git-subtree-dir: waflib
git-subtree-split: e7a29b6b9b2f842314244c23c14d8f8f560904e1
Diffstat (limited to 'Tools/fc_scan.py')
-rw-r--r-- | Tools/fc_scan.py | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/Tools/fc_scan.py b/Tools/fc_scan.py new file mode 100644 index 0000000..0824c92 --- /dev/null +++ b/Tools/fc_scan.py @@ -0,0 +1,120 @@ +#! /usr/bin/env python +# encoding: utf-8 +# DC 2008 +# Thomas Nagy 2016-2018 (ita) + +import re + +INC_REGEX = r"""(?:^|['">]\s*;)\s*(?:|#\s*)INCLUDE\s+(?:\w+_)?[<"'](.+?)(?=["'>])""" +USE_REGEX = r"""(?:^|;)\s*USE(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(\w+)""" +MOD_REGEX = r"""(?:^|;)\s*MODULE(?!\s+(?:PROCEDURE|SUBROUTINE|FUNCTION))\s+(\w+)""" +SMD_REGEX = r"""(?:^|;)\s*SUBMODULE\s*\(([\w:]+)\)\s*(\w+)""" + +re_inc = re.compile(INC_REGEX, re.I) +re_use = re.compile(USE_REGEX, re.I) +re_mod = re.compile(MOD_REGEX, re.I) +re_smd = re.compile(SMD_REGEX, re.I) + +class fortran_parser(object): + """ + This parser returns: + + * the nodes corresponding to the module names to produce + * the nodes corresponding to the include files used + * the module names used by the fortran files + """ + def __init__(self, incpaths): + self.seen = [] + """Files already parsed""" + + self.nodes = [] + """List of :py:class:`waflib.Node.Node` representing the dependencies to return""" + + self.names = [] + """List of module names to return""" + + self.incpaths = incpaths + """List of :py:class:`waflib.Node.Node` representing the include paths""" + + def find_deps(self, node): + """ + Parses a Fortran file to obtain the dependencies used/provided + + :param node: fortran file to read + :type node: :py:class:`waflib.Node.Node` + :return: lists representing the includes, the modules used, and the modules created by a fortran file + :rtype: tuple of list of strings + """ + txt = node.read() + incs = [] + uses = [] + mods = [] + for line in txt.splitlines(): + # line by line regexp search? optimize? + m = re_inc.search(line) + if m: + incs.append(m.group(1)) + m = re_use.search(line) + if m: + uses.append(m.group(1)) + m = re_mod.search(line) + if m: + mods.append(m.group(1)) + m = re_smd.search(line) + if m: + uses.append(m.group(1)) + mods.append('{0}:{1}'.format(m.group(1),m.group(2))) + return (incs, uses, mods) + + def start(self, node): + """ + Start parsing. Use the stack ``self.waiting`` to hold nodes to iterate on + + :param node: fortran file + :type node: :py:class:`waflib.Node.Node` + """ + self.waiting = [node] + while self.waiting: + nd = self.waiting.pop(0) + self.iter(nd) + + def iter(self, node): + """ + Processes a single file during dependency parsing. Extracts files used + modules used and modules provided. + """ + incs, uses, mods = self.find_deps(node) + for x in incs: + if x in self.seen: + continue + self.seen.append(x) + self.tryfind_header(x) + + for x in uses: + name = "USE@%s" % x + if not name in self.names: + self.names.append(name) + + for x in mods: + name = "MOD@%s" % x + if not name in self.names: + self.names.append(name) + + def tryfind_header(self, filename): + """ + Adds an include file to the list of nodes to process + + :param filename: file name + :type filename: string + """ + found = None + for n in self.incpaths: + found = n.find_resource(filename) + if found: + self.nodes.append(found) + self.waiting.append(found) + break + if not found: + if not filename in self.names: + self.names.append(filename) + |