This commit is contained in:
Baudouin Raoult 2023-06-27 09:59:47 +01:00
parent ec5758e548
commit 5f79174d71
3 changed files with 253 additions and 166 deletions

View File

@ -41,6 +41,47 @@ class Member:
self.type += "*" self.type += "*"
class Arg:
def __init__(self, name, type) -> None:
self.name = name
self.type = type
if self.name[0] == "*":
self.name = self.name[1:]
self.type += "*"
class Function:
def __init__(self, name, result, args, template=None) -> None:
self._name = name
self._result = result
self._template = template
self._args = []
self._lines = []
for arg in [a.strip() for a in args.split(",")]:
bits = arg.split()
type = " ".join(bits[:-1])
name = bits[-1]
self._args.append(Arg(name, type))
def add_line(self, line):
self._lines.append(line)
@property
def args_declaration(self):
return ", ".join([f"{a.type} {a.name}" for a in self._args])
@property
def call_args(self):
return ", ".join([a.name for a in self._args])
@property
def body(self):
return ""
return "\n".join(self._lines)
class Method: class Method:
def __init__(self, name, result, args, template=None) -> None: def __init__(self, name, result, args, template=None) -> None:
self.name = name self.name = name
@ -72,7 +113,6 @@ class Method:
return True return True
class SimpleMethod(Method): class SimpleMethod(Method):
def tidy_lines(self, klass): def tidy_lines(self, klass):
this = [r"\bself\b"] this = [r"\bself\b"]
@ -111,7 +151,7 @@ class CompareMethod(Method):
class DumpMethod(Method): class DumpMethod(Method):
def tidy_lines(self, klass): def tidy_lines(self, klass):
# For now, just remove the method # For now, just remove the method
self.lines = ['#if 0'] + self.lines[1:-1] + ['#endif'] self.lines = ["#if 0"] + self.lines[1:-1] + ["#endif"]
class StaticProc(Method): class StaticProc(Method):
@ -147,70 +187,157 @@ class Class:
*, *,
path, path,
class_, class_,
inherited_procs, functions,
other_procs, top_level_code,
top_level,
includes, includes,
factory_name, factory_name,
SUPER=[], super,
IMPLEMENTS=[], implements,
MEMBERS=[], members,
): ):
assert factory_name is not None assert factory_name is not None
self.class_ = class_ self._class = class_
self.name, self.cname = self.tidy_class_name(path) self._name, self.cname = self.tidy_class_name(path)
self.inherited_procs = inherited_procs self._top_level_code = top_level_code
self.factory_name = factory_name self._factory_name = factory_name
self._members = members
self._functions = functions
self.self = None self._body_includes = includes
self.a = None
self.header_includes = [] if super is None:
self.body_includes = includes self._super, _ = self.tidy_class_name(class_)
if SUPER: self._include_dir = "cpp"
self.super, _ = self.tidy_class_name(SUPER[0])
self.src = args.target
else: else:
self.super, _ = self.tidy_class_name(class_) self._super, _ = self.tidy_class_name(super)
self.src = "cpp" self._include_dir = args.target
self.members = [Member(m) for m in MEMBERS if m != ""] def finalise(self, other_classes):
self._other_classes = other_classes
for p in inherited_procs.values(): # Classify functions
p.tidy_lines(self) self._inherided_methods = []
self._private_methods = []
self._static_functions = []
self.inherited_methods = [
p
for p in inherited_procs.values()
if p.name
not in (
"init",
"destroy",
)
]
init = [p for p in inherited_procs.values() if p.name == "init"]
self.constructor = (
init[0]
if init
else SimpleMethod(
"init",
"void",
"grib_accessor* a, const long length, grib_arguments* args",
)
)
init = [p for p in inherited_procs.values() if p.name == "destroy"] @property
self.destructor = init[0] if init else SimpleMethod("destroy", "void", "void") def name(self):
return self._name
for p in other_procs.values(): @property
p.tidy_lines(self) def factory_name(self):
return self._factory_name
self.private_methods = [p for p in other_procs.values() if p.has_this()] @property
self.static_procs = [p for p in other_procs.values() if not p.has_this()] def super(self):
return self._super
self.top_level = defaultdict(list) @property
for k, v in top_level.items(): def top_level_code(self):
self.top_level[k] = [self.tidy_top_level(p) for p in v] return self._top_level_code
@property
def members(self):
# if self.super in self.other_classes:
# return self.other_classes[self.super].members + self._members
return self._members
@property
def include_super(self):
return "/".join([self._include_dir] + self.namespaces + [self._super + ".h"])
@property
def include_header(self):
return "/".join([args.target] + self.namespaces + [self._super + ".h"])
@property
def header_includes(self):
return []
@property
def body_includes(self):
return []
@property
def namespaces(self):
return ["eccodes", self._class]
@property
def namespaces_reversed(self):
return reversed(self.namespaces)
@property
def constructor(self):
if "init" in self._functions:
return self._functions["init"]
return Function("a")
@property
def destructor(self):
if "destroy" in self._functions:
return self._functions["destroy"]
return Function("a", "b", "c")
@property
def inherited_methods(self):
return []
@property
def private_methods(self):
return []
@property
def static_functions(self):
return []
# if SUPER:
# self.super, _ = self.tidy_class_name(SUPER[0])
# self.src = args.target
# else:
# self.super, _ = self.tidy_class_name(class_)
# self.src = "cpp"
# self.members = [Member(m) for m in MEMBERS if m != ""]
# for p in inherited_procs.values():
# p.tidy_lines(self)
# self.inherited_methods = [
# p
# for p in inherited_procs.values()
# if p.name
# not in (
# "init",
# "destroy",
# )
# ]
# init = [p for p in inherited_procs.values() if p.name == "init"]
# self.constructor = (
# init[0]
# if init
# else SimpleMethod(
# "init",
# "void",
# "grib_accessor* a, const long length, grib_arguments* args",
# )
# )
# init = [p for p in inherited_procs.values() if p.name == "destroy"]
# self.destructor = init[0] if init else SimpleMethod("destroy", "void", "void")
# for p in other_procs.values():
# p.tidy_lines(self)
# self.private_methods = [p for p in other_procs.values() if p.has_this()]
# self.static_procs = [p for p in other_procs.values() if not p.has_this()]
# self.top_level = defaultdict(list)
# for k, v in top_level.items():
# self.top_level[k] = [self.tidy_top_level(p) for p in v]
def update(self, classes): def update(self, classes):
if self.super in classes: if self.super in classes:
@ -222,47 +349,32 @@ class Class:
def tidy_class_name(self, path): def tidy_class_name(self, path):
path, ext = os.path.splitext(path) path, ext = os.path.splitext(path)
cname = os.path.basename(path) c_name = os.path.basename(path)
name = cname.replace(self.prefix, "") name = c_name.replace(self.prefix, "")
name = to_camel_class(name) name = to_camel_class(name)
return self.rename.get(name, name), cname return self.rename.get(name, name), c_name
def save(self, ext, content): def save(self, ext, content):
target = os.path.join(args.target, *self.namespaces, f"{self.name}.{ext}") target = os.path.join(args.target, *self.namespaces, f"{self.name}.{ext}")
os.makedirs(os.path.dirname(target), exist_ok=True) os.makedirs(os.path.dirname(target), exist_ok=True)
print("Writting ", target)
with open(target, "w") as f: with open(target, "w") as f:
f.write(content) f.write(content)
ret = os.system(f"clang-format -i {target}") ret = os.system(f"clang-format -i {target}")
assert ret == 0 assert ret == 0
print(" ", target)
def dump_header(self): def dump_header(self):
template = env.get_template(f"{self.class_}.h.j2") template = env.get_template(f"{self._class}.h.j2")
self.save( self.save(
"h", "h",
template.render( template.render(c=self),
name=self.name,
super=self.super,
members=self.members,
includes=self.header_includes,
inherited_methods=self.inherited_methods,
private_methods=self.private_methods,
static_procs=self.static_procs,
constructor=self.constructor,
destructor=self.destructor,
namespaces=self.namespaces,
namespace_reversed=reversed(self.namespaces),
include_super="/".join(
[self.src] + self.namespaces + [f"{self.super}.h"]
),
),
) )
def dump_body(self): def dump_body(self):
template = env.get_template(f"{self.class_}.cc.j2") template = env.get_template(f"{self._class}.cc.j2")
def tidy_more(text): def tidy_more(text):
# Some more tidying # Some more tidying
@ -278,26 +390,7 @@ class Class:
self.save( self.save(
"cc", "cc",
tidy_more( tidy_more(template.render(c=self)),
template.render(
name=self.name,
super=self.super,
members=self.members,
includes=self.body_includes,
inherited_methods=self.inherited_methods,
private_methods=self.private_methods,
static_procs=self.static_procs,
constructor=self.constructor,
destructor=self.destructor,
namespaces=self.namespaces,
namespace_reversed=reversed(self.namespaces),
include_header="/".join(
[self.src] + self.namespaces + [f"{self.name}.h"]
),
top_level=self.top_level,
factory_name=self.factory_name,
)
),
) )
def tidy_line(self, line, this=[]): def tidy_line(self, line, this=[]):
@ -408,20 +501,19 @@ CLASSES = dict(
) )
def make_class(classes, path): def parse_file(path):
in_def = False in_def = False
in_imp = False in_imp = False
in_proc = False in_function = False
includes = [] includes = []
factory_name = None factory_name = None
template = None template = None
definitions = {} definitions = {}
inherited_procs = {} functions = {}
other_procs = {}
top_level_lines = [] top_level_lines = []
top_level = defaultdict(list) top_level_code = defaultdict(list)
print(path, file=sys.stderr) print("Parsing", path)
f = open(path, "r") f = open(path, "r")
for line in f: for line in f:
@ -465,36 +557,29 @@ def make_class(classes, path):
m = re.match(r"static\s+([^(]+)\s+(\w+)\s*\(([^(]+)\)", line) m = re.match(r"static\s+([^(]+)\s+(\w+)\s*\(([^(]+)\)", line)
if m: if m:
p = m.group(2) function_name = m.group(2)
top_level[p] = [x for x in top_level_lines] top_level_code[function_name] = [x for x in top_level_lines]
top_level_lines = [] top_level_lines = []
if p in definitions.get("IMPLEMENTS", []): in_function = True
in_proc = True function = functions[function_name] = Function(
method_class = METHOD_CLASS.get(p, SimpleMethod) function_name,
proc = inherited_procs[p] = method_class( m.group(1),
p, m.group(1), m.group(3), template m.group(3),
) template,
depth = stripped_line.count("{") - stripped_line.count("}") )
assert depth >= 0, line depth = stripped_line.count("{") - stripped_line.count("}")
continue assert depth >= 0, line
else:
in_proc = True
proc = StaticProc(p, m.group(1), m.group(3), template)
other_procs[p] = proc
depth = stripped_line.count("{") - stripped_line.count("}")
assert depth >= 0, line
continue
if in_proc: if in_function:
proc.add_line(stripped_line) function.add_line(stripped_line)
depth += stripped_line.count("{") depth += stripped_line.count("{")
depth -= stripped_line.count("}") depth -= stripped_line.count("}")
assert depth >= 0, line assert depth >= 0, line
if depth == 0: if depth == 0:
in_proc = False in_function = False
template = None template = None
del proc del function
continue continue
if stripped_line.startswith("#include"): if stripped_line.startswith("#include"):
@ -511,29 +596,31 @@ def make_class(classes, path):
top_level_lines.append(line) top_level_lines.append(line)
if definitions: if definitions:
top_level["-end-"] = top_level_lines top_level_code["-end-"] = top_level_lines
class_ = definitions.pop("CLASS")[0] class_ = definitions.pop("CLASS")[0]
klass = CLASSES[class_]( klass = CLASSES[class_](
path=path, path=path,
class_=class_, class_=class_,
inherited_procs=inherited_procs, functions=functions,
other_procs=other_procs, top_level_code=top_level_code,
top_level=top_level,
includes=includes, includes=includes,
factory_name=factory_name, factory_name=factory_name,
**definitions, super=definitions["SUPER"][0] if "SUPER" in definitions else None,
implements=definitions.get("IMPLEMENTS", []),
members=[Member(m) for m in definitions.get("MEMBERS", []) if m != ""],
) )
classes[klass.cname] = klass return klass
def main(): def main():
classes = {} classes = {}
for a in args.path: for a in args.path:
make_class(classes, a) klass = parse_file(a)
if klass is not None:
classes[klass.cname] = klass
for klass in classes.values(): for klass in classes.values():
klass.update(classes) klass.finalise(classes)
for klass in classes.values(): for klass in classes.values():
klass.dump() klass.dump()

View File

@ -8,21 +8,21 @@
* virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction. * virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction.
*/ */
#include "{{ include_header }}" #include "{{ c.include_header }}"
{% for i in includes %} {% for i in c.body_includes %}
#include {{ i }} #include {{ i }}
{% endfor %} {% endfor %}
{% for n in namespaces %}namespace {{ n }} { {% for n in c.namespaces %}namespace {{ n }} {
{% endfor %} {% endfor %}
{% for line in top_level['-start-'] %}{{ line }} {% for line in c.top_level_code['-start-'] %}{{ line }}
{% endfor %} {% endfor %}
{% for m in static_procs %} {% for m in c.static_functions %}
{% for line in top_level[m.name] %}{{ line }} {% for line in c.top_level_code[m.name] %}{{ line }}
{% endfor %} {% endfor %}
static {{ m.result }} {{ m.name }}({{ m.args }}) { static {{ m.result }} {{ m.name }}({{ m.args }}) {
{{ m.body }} {{ m.body }}
@ -30,20 +30,20 @@ static {{ m.result }} {{ m.name }}({{ m.args }}) {
{% endfor %} {% endfor %}
{% for line in top_level['init'] %}{{ line }} {% for line in c.top_level_code['init'] %}{{ line }}
{% endfor %} {% endfor %}
{{ name }}::{{ name }}({{constructor.args}}) : {{ super }}({{ constructor.call_args }}){ {{ c.name }}::{{ c.name }}({{c.constructor.args_declaration}}) : {{ c.super }}({{ c.constructor.call_args }}){
{{ constructor.body }} {{ c.constructor.body }}
} }
{% for line in top_level['destroy'] %}{{ line }} {% for line in c.top_level_code['destroy'] %}{{ line }}
{% endfor %} {% endfor %}
{{ name }}::~{{ name }}() { {{ c.name }}::~{{ c.name }}() {
{{ destructor.body }} {{ c.destructor.body }}
} }
{% for m in inherited_methods %} {% for m in c.inherited_methods %}
{% for line in top_level[m.name] %}{{ line }} {% for line in c.top_level_code[m.name] %}{{ line }}
{% endfor %} {% endfor %}
{{ m.result }} {{ name }}::{{ m.name }}({{ m.args }}) const { {{ m.result }} {{ name }}::{{ m.name }}({{ m.args }}) const {
@ -51,24 +51,24 @@ static {{ m.result }} {{ m.name }}({{ m.args }}) {
} }
{% endfor %} {% endfor %}
{% for m in private_methods %} {% for m in c.private_methods %}
{% for line in top_level[m.name] %}{{ line }} {% for line in c.top_level_code[m.name] %}{{ line }}
{% endfor %} {% endfor %}
{{ m.result }} {{ name }}::{{ m.name }}({{ m.args }}) const { {{ m.result }} {{ name }}::{{ m.name }}({{ m.args }}) const {
{{ m.body }} {{ m.body }}
} }
{% endfor %} {% endfor %}
void {{ name }}::print(std::ostream& s) const { void {{ c.name }}::print(std::ostream& s) const {
s << "{{ name }}[" s << "{{ c.name }}["
{% for m in members %} << "{{ m.name }}=" << {{ m.name }} {% if not loop.last %}<< ',' {% endif %} {% for m in c.members %} << "{{ m.name }}=" << {{ m.name }} {% if not loop.last %}<< ',' {% endif %}
{% endfor %} << "]"; {% endfor %} << "]";
} }
{% for line in top_level['-end-'] %}{{ line }} {% for line in c.top_level_code['-end-'] %}{{ line }}
{% endfor %} {% endfor %}
static AccessorMaker<{{ name }}> maker("{{ factory_name }}"); static AccessorMaker<{{ c.name }}> maker("{{ c.factory_name }}");
{% for n in namespace_reversed %}} // namespace {{ n }} {% for n in c.namespaces_reversed %}} // namespace {{ n }}
{% endfor %} {% endfor %}

View File

@ -10,48 +10,48 @@
#pragma once #pragma once
#include "{{ include_super }}" #include "{{ c.include_super }}"
{% for i in includes %} {% for i in c.header_includes %}
#include {{ i }} #include {{ i }}
{% endfor %} {% endfor %}
{% for n in namespaces %}namespace {{ n }} { {% for n in c.namespaces %}namespace {{ n }} {
{% endfor %} {% endfor %}
class {{ name }} : public {{ super }} { class {{ c.name }} : public {{ c.super }} {
public: public:
{{ name }}({{constructor.args}}); {{ c.name }}({{c.constructor.args_declaration}});
virtual ~{{ name }}(); virtual ~{{ c.name }}();
private: private:
// No copy allowed // No copy allowed
{{ name }}(const {{ name }}&); {{ c.name }}(const {{ c.name }}&);
{{ name }}& operator=(const {{ name }}&); {{ c.name }}& operator=(const {{ c.name }}&);
protected: protected:
// Inherited methods // Inherited methods
// Protected for now // Protected for now
{% for m in inherited_methods %} {% for m in c.inherited_methods %}
virtual {{ m.result }} {{ m.name }}({{ m.args }}) const override;{% endfor %} virtual {{ m.result }} {{ m.name }}({{ m.args_declaration }}) {{ m.const }} override;{% endfor %}
virtual void print(std::ostream& s) const override; virtual void print(std::ostream& s) const override;
private: private:
// Private methods // Private methods
{% for m in private_methods %} {% for m in c.private_methods %}
{{ m.result }} {{ m.name }}({{ m.args }}) const;{% endfor %} {{ m.result }} {{ m.name }}({{ m.args }}) const;{% endfor %}
// Members // Members
{% for m in members %}{{ m.type }} {{ m.name }}; {% for m in c.members %}{{ m.type }} {{ m.name }};
{% endfor %} {% endfor %}
}; };
{% for n in namespace_reversed %}} // namespace {{ n }} {% for n in c.namespaces_reversed %}} // namespace {{ n }}
{% endfor %} {% endfor %}