67 Various utility functions. 69 Permission to use, modify, and distribute this software is given under the 70 terms of the NumPy License. See http://scipy.org. 72 NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. 73 Author: Pearu Peterson <pearu@cens.ioc.ee> 109 is_name = re.compile(
r"^[a-z_]\w*$", re.I).match
110 name_re = re.compile(
r"[a-z_]\w*", re.I).match
111 is_entity_decl = re.compile(
r"^[a-z_]\w*", re.I).match
112 is_int_literal_constant = re.compile(
r"^\d+(_\w+|)$").match
113 module_file_extensions = [
".f",
".f90",
".f95",
".f03",
".f08"]
116 def split_comma(line, item=None, comma=",", keep_empty=False, brackets=None):
117 """Split (an optionally bracketed) comma-separated list into 118 items and return a list containing them. If supplied then 119 brackets must be a list of containing two strings, the first 120 being the opening bracket and the second the closing bracket.""" 126 if not isinstance(brackets, tuple):
127 raise ParseError(
"split_comma: brackets must be a tuple")
128 if len(brackets) != 2:
130 "split_comma: brackets tuple must contain " 131 "just two items but got: {0}",
136 if not line.startswith(open)
or not line.endswith(close):
138 line = line.strip(brackets[0])
139 line = line.strip(brackets[1])
142 for s
in line.split(comma):
144 if not s
and not keep_empty:
148 newitem = item.copy(line,
True)
149 apply_map = newitem.apply_map
150 for s
in newitem.get_line().split(comma):
151 s = apply_map(s).strip()
152 if not s
and not keep_empty:
158 def extract_bracketed_list_items(line, item=None):
159 """Takes any line that contains "xxx (a,b,...) yyy" and returns 160 a list of items corresponding to a, b, ... Anything outside of 161 the parentheses is ignored. Only works for strings containing 162 a single set of parentheses.""" 163 if line.count(
"(") > 1
or line.count(
")") > 1:
165 "parse_bracketed_list: more than one opening/closing parenthesis " 166 "found in string '{0}'; this is not supported".format(line)
168 idx1 = line.find(
"(")
169 idx2 = line.rfind(
")")
170 if idx1 < 0
or idx2 < 0
or idx2 < idx1:
172 "parse_bracketed_list: failed to find expression within " 173 "parentheses in '{0}'".format(line)
175 items = split_comma(line[idx1 : idx2 + 1], item, brackets=(
"(",
")"))
177 for idx
in range(len(items)):
178 itm = item.copy(items[idx])
180 for rpart
in itm.get_line().split(
":"):
181 rlst.append(itm.apply_map(rpart.strip()))
186 def parse_array_spec(line, item=None):
188 for spec
in split_comma(line, item):
189 items.append(tuple(split_comma(spec, item, comma=
":", keep_empty=
True)))
193 def specs_split_comma(line, item=None, upper=False):
194 specs0 = split_comma(line, item)
199 kw = spec[:i].strip().upper()
200 v = spec[i + 1 :].strip()
201 specs.append(
"%s = %s" % (kw, v))
209 def parse_bind(line, item=None):
210 if not line.lower().startswith(
"bind"):
213 newitem = item.copy(line, apply_map=
True)
214 newline = newitem.get_line()
217 newline = newline[4:].lstrip()
218 i = newline.find(
")")
219 assert i != -1, repr(newline)
221 for a
in specs_split_comma(newline[1:i].strip(), newitem, upper=
True):
223 rest = newline[i + 1 :].lstrip()
225 rest = newitem.apply_map(rest)
229 def parse_result(line, item=None):
230 if not line.lower().startswith(
"result"):
232 line = line[6:].lstrip()
234 assert i != -1, repr(line)
235 name = line[1:i].strip()
236 assert is_name(name), repr(name)
237 return name, line[i + 1 :].lstrip()
240 def filter_stmts(content, classes):
241 """Pop and return classes instances from content.""" 244 for i
in range(len(content)):
246 if isinstance(stmt, classes):
255 def get_module_files(directory, _cache={}):
256 if directory
in _cache:
257 return _cache[directory]
258 module_line = re.compile(
r"(\A|^)module\s+(?P<name>\w+)\s*(!.*|)$", re.I | re.M)
261 for ext
in module_file_extensions:
262 files += glob.glob(os.path.join(directory,
"*" + ext))
265 for name
in module_line.findall(f.read()):
268 print(d[name],
"already defines", name)
271 _cache[directory] = d
275 def get_module_file(name, directory, _cache={}):
276 fn = _cache.get(name,
None)
279 if name.endswith(
"_module"):
280 for ext
in module_file_extensions:
281 f1 = os.path.join(directory, name[:-7] + ext)
282 if os.path.isfile(f1):
286 for ext
in module_file_extensions:
287 files += glob.glob(os.path.join(directory,
"*" + ext))
289 if module_in_file(name, fn):
295 def module_in_file(name, filename):
297 pattern = re.compile(
r"\s*module\s+(?P<name>[a-z]\w*)", re.I).match
298 encoding = {
"encoding":
"UTF-8"}
299 f = io.open(filename,
"r", **encoding) 302 if m
and m.group(
"name").lower() == name:
308 def str2stmt(string, isfree=True, isstrict=False):
309 """Convert Fortran code to Statement tree.""" 310 from .readfortran
import Line, FortranStringReader
311 from .parsefortran
import FortranParser
313 reader = FortranStringReader(string, isfree, isstrict)
314 parser = FortranParser(reader)
318 while len(block.content) == 1:
319 block = block.content[0]
323 def show_item_on_failure(func, _exception_depth=[0]):
325 Decorator for analyze methods. 331 except AnalyzeError
as msg:
332 clsname = self.__class__.__name__
333 self.error(
"%s.analyze error: %s" % (clsname, msg))
334 traceback.print_exc()
335 except ParseError
as msg:
336 self.error(
"parse error: %s" % (msg))
337 except Exception
as msg:
338 _exception_depth[0] += 1
339 if _exception_depth[0] == 1:
340 self.error(
"exception triggered here: %s %s" % (Exception, msg))
342 _exception_depth[0] = 0
351 """Meta class for ``classes``.""" 353 __abstractmethods__ =
False 355 def __getattr__(self, name):
357 cls = _classes_cache.get(name)
359 raise AttributeError(
"instance does not have attribute %r" % (name))
364 """Make classes available as attributes of this class. 366 To add a class to the attributes list, one must use:: 368 class Name(metaclass=classes): 370 in the definition of the class. 372 In addition, apply the following tasks: 374 * decorate analyze methods with show_item_on_failure 377 def __new__(metacls, name, bases, dict):
378 if "analyze" in dict:
379 dict[
"analyze"] = show_item_on_failure(dict[
"analyze"])
380 cls = type.__new__(metacls, name, bases, dict)
381 _classes_cache[name] = cls