Skip to content

Commit

Permalink
[sourcegen] Simplify scaffolding templates
Browse files Browse the repository at this point in the history
  • Loading branch information
ischoegl committed Dec 31, 2024
1 parent 4279c87 commit 0b623d9
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 171 deletions.
145 changes: 35 additions & 110 deletions interfaces/sourcegen/sourcegen/clib/_CLibSourceGenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ def _reverse_crosswalk(c_func: CFunc, base: str) -> tuple[dict[str, str], set[st
if c_ix == len(c_args):
break
cxx_type = cxx_func.ret_type

# handle output buffer
if "string" in cxx_type:
buffer = ["auto out",
f"copyString(out, {c_args[c_ix+1].name}, {c_name});",
Expand All @@ -193,7 +195,7 @@ def _reverse_crosswalk(c_func: CFunc, base: str) -> tuple[dict[str, str], set[st

cxx_type = cxx_arg.p_type
if check_array:
# need to create buffer variable
# need to handle cross-walked parameter with length information
c_prev = c_args[c_ix-1].name
line = None
if "vector" in cxx_type:
Expand Down Expand Up @@ -227,141 +229,64 @@ def _reverse_crosswalk(c_func: CFunc, base: str) -> tuple[dict[str, str], set[st
cxx_type = cxx_func.ret_type
if cxx_type.endswith("int") or cxx_type.endswith("size_t"):
error = ["ERR", "ERR"]
if cxx_type.endswith("double"):
elif cxx_type.endswith("double"):
error = ["DERR", "DERR"]
if "shared_ptr" in cxx_type:
elif "shared_ptr" in cxx_type:
obj_base = cxx_type.split("<")[-1].split(">")[0]
if obj_base == base:
buffer = ["auto& obj", "", f"{obj_base}Cabinet::index(obj)"]
else:
buffer = ["auto& obj", "", f"{obj_base}Cabinet::index(obj, {handle})"]
error = ["-2", "ERR"]
elif cxx_type.endswith("void"):
buffer = ["", "", "0"]

ret = {
"handle": handle, "lines": lines, "buffer": buffer, "uses": uses,
"cxx_base": base, "cxx_name": cxx_func.name, "cxx_args": args,
"c_func": c_func.name, "cxx_implements": cxx_func.short_declaration(),
"error": error,
"cxx_implements": cxx_func.short_declaration(), "error": error,
"c_func": c_func.name, "c_args": [arg.name for arg in c_func.arglist],
}
return ret, bases

def _scaffold_function(
self, c_func: CFunc, recipe: Recipe) -> tuple[str, set[str]]:
"""Scaffold body of CLib function via jinja."""
loader = Environment(loader=BaseLoader, trim_blocks=True, lstrip_blocks=True)
template = loader.from_string(self._templates["clib-function"])
args, bases = self._reverse_crosswalk(c_func, recipe.base)
return template.render(**args), bases

def _scaffold_constructor(
self, c_func: CFunc, recipe: Recipe) -> tuple[str, set[str]]:
"""Scaffold body of CLib constructor function via jinja."""
loader = Environment(loader=BaseLoader, trim_blocks=True, lstrip_blocks=True)
template = loader.from_string(self._templates["clib-constructor"])
args, bases = self._reverse_crosswalk(c_func, recipe.base)
return template.render(**args), bases

def _scaffold_destructor(
self, c_func: CFunc, recipe: Recipe) -> tuple[str, set[str]]:
"""Scaffold body of CLib destructor function via jinja."""
loader = Environment(loader=BaseLoader, trim_blocks=True, lstrip_blocks=True)
template = loader.from_string(self._templates["clib-destructor"])
args, bases = self._reverse_crosswalk(c_func, recipe.base)
return template.render(**args), bases

def _scaffold_method(
self, c_func: CFunc, recipe: Recipe) -> tuple[str, set[str]]:
"""Scaffold body of CLib method via jinja."""
loader = Environment(loader=BaseLoader, trim_blocks=True, lstrip_blocks=True)
template = loader.from_string(self._templates["clib-method"])
args, bases = self._reverse_crosswalk(c_func, recipe.base)
return template.render(**args, what="method"), bases

def _scaffold_getter(self, c_func: CFunc, recipe: Recipe) -> tuple[str, set[str]]:
"""Scaffold body of CLib getter function via jinja."""
loader = Environment(loader=BaseLoader, trim_blocks=True, lstrip_blocks=True)
cxx_func = c_func.implements
size_fcn = f"{cxx_func.uses[0].name}()" if cxx_func.uses else ""
args = {
"c_arg": [arg.name for arg in c_func.arglist],
"cxx_base": recipe.base, "cxx_name": cxx_func.name,
"cxx_implements": cxx_func.short_declaration(),
"c_func": c_func.name, "size_fcn": size_fcn, "obj_base": "",
}

if "string" in cxx_func.ret_type:
template = loader.from_string(self._templates["clib-string-getter"])
elif "void" in cxx_func.ret_type:
template = loader.from_string(self._templates["clib-array-getter"])
elif "shared_ptr" in cxx_func.ret_type:
args["obj_base"] = cxx_func.ret_type.split("<")[-1].split(">")[0]
template = loader.from_string(self._templates["clib-object-getter"])
elif "double" in c_func.ret_type:
args["is_integer"] = False,
template = loader.from_string(self._templates["clib-simple-getter"])
elif "int" in c_func.ret_type:
args["is_integer"] = True,
template = loader.from_string(self._templates["clib-simple-getter"])
else:
logging.critical(f"Failed to scaffold getter: {args['cxx_implements']}")
sys.exit(1)

return template.render(**args), {args["obj_base"]}

def _scaffold_setter(self, c_func: CFunc, recipe: Recipe) -> tuple[str, set[str]]:
"""Scaffold body of CLib setter function via jinja."""
loader = Environment(loader=BaseLoader, trim_blocks=True, lstrip_blocks=True)
cxx_func = c_func.implements
size_fcn = f"{cxx_func.uses[0].name}()" if cxx_func.uses else ""
args = {
"c_arg": [arg.name for arg in c_func.arglist],
"cxx_base": recipe.base, "cxx_name": cxx_func.name,
"cxx_implements": cxx_func.short_declaration(),
"c_func": c_func.name, "size_fcn": size_fcn, "obj_base": "",
}

p_type = cxx_func.arglist[0].p_type
simple = ["string&", "int", "size_t", "double"]
if "*" in p_type:
template = loader.from_string(self._templates["clib-array-setter"])
elif any(typ in p_type.split() for typ in simple):
template = loader.from_string(self._templates["clib-simple-setter"])
elif "shared_ptr" in p_type:
args["obj_base"] = p_type.split("<")[-1].split(">")[0]
template = loader.from_string(self._templates["clib-object-setter"])
else:
logging.critical(f"Failed to scaffold getter: {args['cxx_implements']}")
sys.exit(1)

return template.render(**args), {args["obj_base"]}

def _scaffold_body(self, c_func: CFunc, recipe: Recipe) -> tuple[str, set[str]]:
"""Scaffold body of generic CLib function via jinja."""
loader = Environment(loader=BaseLoader, trim_blocks=True, lstrip_blocks=True)
args, bases = self._reverse_crosswalk(c_func, recipe.base)
args["what"] = recipe.what

if recipe.what == "noop":
return loader.from_string(self._templates["clib-noop"]).render(), {""}
template = loader.from_string(self._templates["clib-noop"])

elif recipe.what == "function":
template = loader.from_string(self._templates["clib-function"])

if recipe.what == "function":
return self._scaffold_function(c_func, recipe)
elif recipe.what == "constructor":
template = loader.from_string(self._templates["clib-constructor"])

if recipe.what == "constructor":
return self._scaffold_constructor(c_func, recipe)
elif recipe.what == "destructor":
template = loader.from_string(self._templates["clib-destructor"])

if recipe.what == "destructor":
return self._scaffold_destructor(c_func, recipe)
elif recipe.what == "method":
template = loader.from_string(self._templates["clib-method"])

if recipe.what == "method":
return self._scaffold_method(c_func, recipe)
elif recipe.what == "getter":
if "void" in c_func.implements.ret_type:
template = loader.from_string(self._templates["clib-array-getter"])
else:
template = loader.from_string(self._templates["clib-method"])

if recipe.what == "getter":
return self._scaffold_getter(c_func, recipe)
elif recipe.what == "setter":
if "*" in c_func.implements.arglist[0].p_type:
template = loader.from_string(self._templates["clib-array-setter"])
else:
template = loader.from_string(self._templates["clib-method"])

if recipe.what == "setter":
return self._scaffold_setter(c_func, recipe)
else:
_logger.critical(f"Method not implemented: {cxx_type!r}.")
exit(1)

cxx_func = c_func.implements
return f"// {recipe.what}: {cxx_func.short_declaration()}", {""}
return template.render(**args), bases

def _resolve_recipe(self, recipe: Recipe, quiet: bool=True) -> CFunc:
"""Build CLib header from recipe and doxygen annotations."""
Expand Down
81 changes: 20 additions & 61 deletions interfaces/sourcegen/sourcegen/clib/templates.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,11 @@ clib-function: |-
{{ line }}
{% endfor %}
{% if buffer %}
{% if buffer[0] %}
{{ buffer[0] }} = {{ cxx_name }}({{ ', '.join(cxx_args) }});
{% else %}
{{ cxx_name }}({{ ', '.join(cxx_args) }});
{% endif %}
{% if buffer[1] %}
{{ buffer[1] }}
{% endif %}
Expand Down Expand Up @@ -142,7 +146,11 @@ clib-method: |-
{{ line }}
{% endfor %}
{% if buffer %}
{% if buffer[0] %}
{{ buffer[0] }} = {{ cxx_base }}Cabinet::at({{ handle }})->{{ cxx_name }}({{ ', '.join(cxx_args) }});
{% else %}
{{ cxx_base }}Cabinet::at({{ handle }})->{{ cxx_name }}({{ ', '.join(cxx_args) }});
{% endif %}
{% if buffer[1] %}
{{ buffer[1] }}
{% endif %}
Expand All @@ -154,60 +162,20 @@ clib-method: |-
return handleAllExceptions({{ error[0] }}, {{ error[1] }});
}
clib-simple-getter: |-
try {
// getter: {{ cxx_implements }}
return {{ base }}Cabinet::at({{ c_arg[0] }})->{{ cxx_name }}();
} catch (...) {
{% if is_integer %}
return handleAllExceptions(ERR, ERR);
{% else %}
return handleAllExceptions(DERR, DERR);
{% endif %}
}
clib-string-getter: |-
try {
// getter: {{ cxx_implements }}
auto out = {{ cxx_base }}Cabinet::at({{ c_arg[0] }})->{{ cxx_name }}();
copyString(out, {{ c_arg[2] }}, {{ c_arg[1] }});
return int(out.size());
} catch (...) {
return handleAllExceptions(-1, ERR);
}
clib-array-getter: |-
try {
// getter: {{ cxx_implements }}
auto& obj = {{ cxx_base }}Cabinet::at({{ c_arg[0] }});
{% if size_fcn %}
if ({{ c_arg[1] }} != obj->{{ size_fcn }}) {
auto& obj = {{ cxx_base }}Cabinet::at({{ handle }});
{% if uses %}
if ({{ c_arg[1] }} != obj->{{ uses[0][1] }}()) {
throw CanteraError("{{ c_func }}",
"Invalid output array size; expected size {} but received {}.",
obj->{{ size_fcn }}, {{ c_arg[1] }});
obj->{{ uses[0][1] }}(), {{ c_arg[1] }});
}
{% else %}
// no size checking specified
{% endif %}
obj->{{ cxx_name }}({{ c_arg[2] }});
return 0;
} catch (...) {
return handleAllExceptions(-1, ERR);
}
clib-object-getter: |-
try {
// getter: {{ cxx_implements }}
auto& obj = {{ cxx_base }}Cabinet::at({{ c_arg[0] }});
return {{ obj_base }}Cabinet::index(obj->{{ cxx_name }}(), {{ c_arg[0] }});
} catch (...) {
return handleAllExceptions(-2, ERR);
}
clib-simple-setter: |-
try {
// setter: {{ cxx_implements }}
{{ cxx_base }}Cabinet::at({{ c_arg[0] }})->{{ cxx_name }}({{ c_arg[1] }});
obj->{{ cxx_name }}({{ cxx_arg[0] }});
return 0;
} catch (...) {
return handleAllExceptions(-1, ERR);
Expand All @@ -216,31 +184,22 @@ clib-simple-setter: |-
clib-array-setter: |-
try {
// setter: {{ cxx_implements }}
auto& obj = {{ cxx_base }}Cabinet::at({{ c_arg[0] }});
{% if size_fcn %}
if ({{ c_arg[1] }} != obj->{{ size_fcn }}) {
auto& obj = {{ cxx_base }}Cabinet::at({{ handle }});
{% if uses %}
if ({{ c_arg[1] }} != obj->{{ uses[0][1] }}()) {
throw CanteraError("{{ c_func }}",
"Invalid input array size; expected size {} but received {}.",
obj->{{ size_fcn }}, {{ c_arg[1] }});
obj->{{ uses[0][1] }}(), {{ c_arg[1] }});
}
{% else %}
// no size checking specified
{% endif %}
obj->{{ cxx_name }}({{ c_arg[2] }});
obj->{{ cxx_name }}({{ cxx_arg[0] }});
return 0;
} catch (...) {
return handleAllExceptions(-1, ERR);
}
clib-object-setter: |-
try {
// setter: {{ cxx_implements }}
{{ cxx_base }}Cabinet::at({{ c_arg[0] }})->{{ cxx_name }}({{ obj_base }}Cabinet::at({{ c_arg[1] }}));
return 0;
} catch (...) {
return handleAllExceptions(-2, ERR);
}
clib-noop: |-
// no-op
return 0;
Expand Down Expand Up @@ -273,7 +232,7 @@ clib-source-file: |-
using namespace Cantera;
extern "C" {
{% for source_entry in source_entries %}
{{ source_entry | indent(4) }}
{% for entry in source_entries %}
{{ entry | indent(4) }}
{% endfor %}
}

0 comments on commit 0b623d9

Please sign in to comment.