# -*- coding: utf-8 -*-
"""
Compiler stage 5: Code formatting
---------------------------------
This module implements the formatting of UFC code from a given
dictionary of generated C++ code for the body of each UFC function.
It relies on templates for UFC code available as part of the module
ufc_utils.
"""
# Copyright (C) 2009-2017 Anders Logg
#
# This file is part of FFC.
#
# FFC is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# FFC 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with FFC. If not, see <http://www.gnu.org/licenses/>.
# Python modules
import os
# FFC modules
from ffc.log import info, error, begin, end, dstr
from ffc import __version__ as FFC_VERSION
from ffc.backends.ufc import __version__ as UFC_VERSION
from ffc.classname import make_classname
from ffc.backends.ufc import templates, visibility_snippet, factory_decl, factory_impl
from ffc.parameters import compilation_relevant_parameters
format_template = { "ufc comment" : """\
// This code conforms with the UFC specification version %(ufc_version)s
// and was automatically generated by FFC version %(ffc_version)s.
""",
"dolfin comment" : """\
// This code conforms with the UFC specification version %(ufc_version)s
// and was automatically generated by FFC version %(ffc_version)s.
//
// This code was generated with the option '-l dolfin' and
// contains DOLFIN-specific wrappers that depend on DOLFIN.
""",
"header_h" : """\
#ifndef __%(prefix_upper)s_H
#define __%(prefix_upper)s_H
""",
"header_c" : """\
#include "%(prefix)s.h"
""",
"footer" : """\
#endif
"""
}
[docs]def generate_factory_functions(prefix, kind, classname):
publicname = make_classname(prefix, kind, "main")
code_h = factory_decl % {
"basename": "ufc::%s" % kind,
"publicname": publicname,
}
code_c = factory_impl % {
"basename": "ufc::%s" % kind,
"publicname": publicname,
"privatename": classname
}
return code_h, code_c
[docs]def generate_jit_factory_functions(code, prefix):
# Extract code
(code_finite_elements, code_dofmaps, code_coordinate_mappings,
code_integrals, code_forms, includes) = code
if code_forms:
# Direct jit of form
code_h, code_c = generate_factory_functions(
prefix, "form", code_forms[-1]["classname"])
elif code_coordinate_mappings:
# Direct jit of coordinate mapping
code_h, code_c = generate_factory_functions(
prefix, "coordinate_mapping", code_coordinate_mappings[-1]["classname"])
else:
# Direct jit of element
code_h, code_c = generate_factory_functions(
prefix, "finite_element", code_finite_elements[-1]["classname"])
fh, fc = generate_factory_functions(
prefix, "dofmap", code_dofmaps[-1]["classname"])
code_h += fh
code_c += fc
return code_h, code_c
return code_h, code_c
[docs]def write_code(code_h, code_c, prefix, parameters):
# Write file(s)
_write_file(code_h, prefix, ".h", parameters)
if code_c:
_write_file(code_c, prefix, ".cpp", parameters)
def _format_h(class_type, code, parameters, jit=False):
"Format header code for given class type."
if jit:
return templates[class_type + "_jit_header"] % code + "\n"
elif parameters["split"]:
return templates[class_type + "_header"] % code + "\n"
else:
return templates[class_type + "_combined"] % code + "\n"
def _format_c(class_type, code, parameters, jit=False):
"Format implementation code for given class type."
if jit:
return templates[class_type + "_jit_implementation"] % code + "\n"
elif parameters["split"]:
return templates[class_type + "_implementation"] % code + "\n"
else:
return ""
def _write_file(output, prefix, postfix, parameters):
"Write generated code to file."
filename = os.path.join(parameters["output_dir"], prefix + postfix)
with open(filename, "w") as hfile:
hfile.write(output)
info("Output written to " + filename + ".")
def _generate_comment(parameters):
"Generate code for comment on top of file."
# Drop irrelevant parameters
parameters = compilation_relevant_parameters(parameters)
# Generate top level comment
args = {"ffc_version": FFC_VERSION, "ufc_version": UFC_VERSION}
if parameters["format"] == "ufc":
comment = format_template["ufc comment"] % args
elif parameters["format"] == "dolfin":
comment = format_template["dolfin comment"] % args
else:
error("Unable to format code, unknown format \"%s\".", parameters["format"])
# Add parameter information
comment += "//\n"
comment += "// This code was generated with the following parameters:\n"
comment += "//\n"
comment += "\n".join([""] + ["//" + (" " + l) for l in dstr(parameters).split("\n")][:-1])
comment += "\n"
return comment
def _generate_includes(includes, parameters):
default_h_includes = [
"#include <ufc.h>",
]
default_cpp_includes = [
# TODO: Avoid adding these includes if we don't need them:
"#include <iostream>",
"#include <stdexcept>",
"#include <algorithm>",
]
external_includes = set("#include <%s>" % inc for inc in parameters.get("external_includes", ()))
s = set(default_h_includes + default_cpp_includes) | includes
s2 = (set(default_cpp_includes) | external_includes) - s
includes_h = "\n".join(sorted(s)) + "\n" if s else ""
includes_cpp = "\n".join(sorted(s2)) + "\n" if s2 else ""
return includes_h, includes_cpp