Skip to content

Commit

Permalink
Merge pull request #240 from robotpy/trampoline-ns
Browse files Browse the repository at this point in the history
Put trampolines in original class namespace
  • Loading branch information
virtuald authored Dec 19, 2024
2 parents c710cde + 1caea5d commit a2989c4
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 30 deletions.
6 changes: 6 additions & 0 deletions robotpy_build/autowrap/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,12 @@ class BaseClassData:
Render data for each base that a class inherits
"""

#: Just the class name
cls_name: str

#: This ends with ::
namespace_: str

#: C++ name, including all known components
full_cpp_name: str # was x_qualname

Expand Down
50 changes: 35 additions & 15 deletions robotpy_build/autowrap/cxxparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,9 @@ def _count_and_unwrap(
assert False


def _fmt_base_name(typename: PQName) -> typing.Tuple[str, str, str, typing.List[str]]:
def _fmt_base_name(
typename: PQName,
) -> typing.Tuple[str, str, str, str, str, typing.List[str]]:
all_parts = []
nameonly_parts = []

Expand All @@ -209,18 +211,22 @@ def _fmt_base_name(typename: PQName) -> typing.Tuple[str, str, str, typing.List[

if last_segment.specialization:
most_parts = all_parts[:-1]
ns_parts = all_parts[:-1]
all_parts.append(last_segment.format())
most_parts.append(last_segment.name)
tparam_list = [arg.format() for arg in last_segment.specialization.args]
else:
ns_parts = all_parts[:]
all_parts.append(last_segment.name)
most_parts = all_parts
tparam_list = []

return (
last_segment.name,
"::".join(most_parts),
"::".join(all_parts),
"::".join(nameonly_parts),
"::".join(ns_parts),
tparam_list,
)

Expand Down Expand Up @@ -287,7 +293,6 @@ class ClassStateData(typing.NamedTuple):
defer_protected_fields: typing.List[Field]

# Needed for trampoline
cls_cpp_identifier: str
template_argument_list: str
base_template_params: str
base_template_args: str
Expand Down Expand Up @@ -751,7 +756,6 @@ def on_class_start(self, state: AWClassBlockState) -> typing.Optional[bool]:
defer_private_virtual_methods=[],
defer_protected_fields=[],
# Trampoline data
cls_cpp_identifier=cls_cpp_identifier,
template_argument_list=template_argument_list,
base_template_args=base_template_args_s,
base_template_params=base_template_params_s,
Expand Down Expand Up @@ -824,28 +828,38 @@ def _process_class_bases(
if base.access == "private":
continue

cpp_name, cpp_name_w_templates, dep_cpp_name, tparam_list = _fmt_base_name(
base.typename
)
(
cpp_name,
full_cpp_name,
cpp_name_w_templates,
dep_cpp_name,
base_ns,
tparam_list,
) = _fmt_base_name(base.typename)
if ignored_bases.pop(cpp_name_w_templates, None):
continue

# Sometimes, we can't guess all the information about the base, so the
# user needs to specify it explicitly.
user_bqual = class_data.base_qualnames.get(cpp_name)
user_bqual = class_data.base_qualnames.get(full_cpp_name)
if user_bqual:
cpp_name_w_templates = user_bqual
# TODO: sometimes need to add this to pybase_params, but
# that would require parsing this more. Seems sufficiently
# obscure, going to omit it for now.
tp = user_bqual.find("<")
if tp == -1:
cpp_name = user_bqual
full_cpp_name = user_bqual
template_params = ""
else:
cpp_name = user_bqual[:tp]
full_cpp_name = user_bqual[:tp]
template_params = user_bqual[tp + 1 : -1]
dep_cpp_name = cpp_name
dep_cpp_name = full_cpp_name
ns_idx = full_cpp_name.rfind("::")
if ns_idx == -1:
base_ns = ""
else:
base_ns = full_cpp_name[:ns_idx]
else:
# TODO: we don't handle nested child classes with templates here
# ... but that has to be rather obscure?
Expand All @@ -858,15 +872,21 @@ def _process_class_bases(
# If no explicit namespace specified, we assume base classes
# live in the same namespace as the class
if len(base.typename.segments) == 1:
cpp_name = f"{cls_namespace}::{cpp_name}"
base_ns = cls_namespace
full_cpp_name = f"{cls_namespace}::{full_cpp_name}"
cpp_name_w_templates = f"{cls_namespace}::{cpp_name_w_templates}"
dep_cpp_name = f"{cls_namespace}::{dep_cpp_name}"

base_identifier = cpp_name.translate(_qualname_trans)
base_identifier = full_cpp_name.translate(_qualname_trans)

if base_ns:
base_ns = f"{base_ns}::"

bases.append(
BaseClassData(
full_cpp_name=cpp_name,
cls_name=cpp_name,
namespace_=base_ns,
full_cpp_name=full_cpp_name,
full_cpp_name_w_templates=cpp_name_w_templates,
full_cpp_name_identifier=base_identifier,
dep_cpp_name=dep_cpp_name,
Expand Down Expand Up @@ -1242,8 +1262,8 @@ def on_class_end(self, state: AWClassBlockState) -> None:
if cdata.template_argument_list:
tmpl = f", {cdata.template_argument_list}"

trampoline_cfg = f"rpygen::PyTrampolineCfg_{cdata.cls_cpp_identifier}<{cdata.template_argument_list}>"
tname = f"rpygen::PyTrampoline_{cdata.cls_cpp_identifier}<typename {ctx.full_cpp_name}{tmpl}, typename {trampoline_cfg}>"
trampoline_cfg = f"{ctx.namespace}::PyTrampolineCfg_{ctx.cpp_name}<{cdata.template_argument_list}>"
tname = f"{ctx.namespace}::PyTrampoline_{ctx.cpp_name}<typename {ctx.full_cpp_name}{tmpl}, typename {trampoline_cfg}>"
tvar = f"{ctx.cpp_name}_Trampoline"

ctx.trampoline = TrampolineData(
Expand Down
31 changes: 16 additions & 15 deletions robotpy_build/autowrap/render_cls_rpy_include.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,8 @@ def _render_cls_trampoline(
for base in cls.bases:
r.writeln(f"#include <rpygen/{ base.full_cpp_name_identifier }.hpp>")

r.writeln("\nnamespace rpygen {")

if cls.namespace:
r.writeln(f"\nusing namespace {cls.namespace};")
r.writeln(f"\nnamespace {cls.namespace.strip('::')} {{")

if hctx.using_declarations:
r.writeln()
Expand All @@ -122,24 +120,24 @@ def _render_cls_trampoline(
#

r.writeln(
f"\ntemplate <{postcomma(template_parameter_list)}typename CfgBase = EmptyTrampolineCfg>"
f"\ntemplate <{postcomma(template_parameter_list)}typename CfgBase = rpygen::EmptyTrampolineCfg>"
)

if cls.bases:
r.writeln(f"struct PyTrampolineCfg_{cls.full_cpp_name_identifier} :")
r.writeln(f"struct PyTrampolineCfg_{cls.cpp_name} :")

with r.indent():
for base in cls.bases:
r.writeln(
f"PyTrampolineCfg_{base.full_cpp_name_identifier}<{postcomma(base.template_params)}"
f"{base.namespace_}PyTrampolineCfg_{base.cls_name}<{postcomma(base.template_params)}"
)

r.writeln("CfgBase")

for base in cls.bases:
r.writeln(">")
else:
r.writeln(f"struct PyTrampolineCfg_{cls.full_cpp_name_identifier} : CfgBase")
r.writeln(f"struct PyTrampolineCfg_{cls.cpp_name} : CfgBase")

r.writeln("{")

Expand All @@ -164,11 +162,11 @@ def _render_cls_trampoline(
r.writeln(
f"template <typename PyTrampolineBase{precomma(template_parameter_list)}, typename PyTrampolineCfg>"
)
r.writeln(f"using PyTrampolineBase_{cls.full_cpp_name_identifier} =")
r.writeln(f"using PyTrampolineBase_{cls.cpp_name} =")

for base in cls.bases:
r.rel_indent(2)
r.writeln(f"PyTrampoline_{base.full_cpp_name_identifier}<")
r.writeln(f"{base.namespace_}PyTrampoline_{base.cls_name}<")

with r.indent():
r.writeln("PyTrampolineBase")
Expand All @@ -184,8 +182,8 @@ def _render_cls_trampoline(
;
template <typename PyTrampolineBase{ precomma(template_parameter_list) }, typename PyTrampolineCfg>
struct PyTrampoline_{ cls.full_cpp_name_identifier } : PyTrampolineBase_{ cls.full_cpp_name_identifier }<PyTrampolineBase{ precomma(template_argument_list) }, PyTrampolineCfg> {{
using PyTrampolineBase_{ cls.full_cpp_name_identifier }<PyTrampolineBase{ precomma(template_argument_list) }, PyTrampolineCfg>::PyTrampolineBase_{ cls.full_cpp_name_identifier };
struct PyTrampoline_{ cls.cpp_name } : PyTrampolineBase_{ cls.cpp_name }<PyTrampolineBase{ precomma(template_argument_list) }, PyTrampolineCfg> {{
using PyTrampolineBase_{ cls.cpp_name }<PyTrampolineBase{ precomma(template_argument_list) }, PyTrampolineCfg>::PyTrampolineBase_{ cls.cpp_name };
"""
)

Expand All @@ -194,7 +192,7 @@ def _render_cls_trampoline(
r.write_trim(
f"""
template <typename PyTrampolineBase{ precomma(template_parameter_list) }, typename PyTrampolineCfg>
struct PyTrampoline_{ cls.full_cpp_name_identifier } : PyTrampolineBase {{
struct PyTrampoline_{ cls.cpp_name } : PyTrampolineBase {{
using PyTrampolineBase::PyTrampolineBase;
"""
)
Expand Down Expand Up @@ -234,11 +232,11 @@ def _render_cls_trampoline(
with r.indent():
all_decls = ", ".join(p.decl for p in fn.all_params)
all_names = ", ".join(p.arg_name for p in fn.all_params)
r.writeln(f"PyTrampoline_{cls.full_cpp_name_identifier}({all_decls}) :")
r.writeln(f"PyTrampoline_{cls.cpp_name}({all_decls}) :")

if cls.bases:
r.writeln(
f" PyTrampolineBase_{cls.full_cpp_name_identifier}<PyTrampolineBase{precomma(trampoline.tmpl_args)}, PyTrampolineCfg>({all_names})"
f" PyTrampolineBase_{cls.cpp_name}<PyTrampolineBase{precomma(trampoline.tmpl_args)}, PyTrampolineCfg>({all_names})"
)
else:
r.writeln(f" PyTrampolineBase({all_names})")
Expand Down Expand Up @@ -284,7 +282,10 @@ def _render_cls_trampoline(
r.writeln()
r.write_trim(trampoline.inline_code)

r.writeln("};\n\n}; // namespace rpygen")
r.writeln("};\n\n")

if cls.namespace:
r.writeln(f"}}; // namespace {cls.namespace}")


def _render_cls_trampoline_virtual_method(
Expand Down
1 change: 1 addition & 0 deletions tests/cpp/pyproject.toml.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ generate = [
{ lifetime = "lifetime.h" },
{ nested = "nested.h" },
{ ns_class = "ns_class.h" },
{ ns_hidden = "ns_hidden.h" },
{ operators = "operators.h" },
{ overloads = "overloads.h" },
{ parameters = "parameters.h" },
Expand Down
31 changes: 31 additions & 0 deletions tests/cpp/rpytest/ft/include/ns_hidden.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#pragma once

namespace n {
enum class E {
Item,
};
};

namespace o {
struct O {
O() = default;
virtual ~O() = default;
};

class AnotherC;
};

namespace n::h {
class C : public o::O {
public:
// E is resolved here because it's in the parent namespace but our
// trampoline was originally in a different namespace and failed
virtual E fn() { return E::Item; }
};
};

struct o::AnotherC {
AnotherC() = default;
virtual ~AnotherC() = default;
virtual int fn() { return 1; }
};

0 comments on commit a2989c4

Please sign in to comment.