From 209128d73f1ac087aaee2a2302b3ce20a1670159 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 24 Dec 2025 23:11:14 -0500 Subject: [PATCH] xo-facet: expand genfacet.py, generate IFoo_Any.hpp --- codegen/abstract_facet.hpp.j2 | 40 +++++++++++++++++-- codegen/genfacet.py | 44 ++++++++++++++++++--- codegen/iface_facet_any.hpp.j2 | 72 ++++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+), 10 deletions(-) create mode 100644 codegen/iface_facet_any.hpp.j2 diff --git a/codegen/abstract_facet.hpp.j2 b/codegen/abstract_facet.hpp.j2 index ff9c61f..a100fd7 100644 --- a/codegen/abstract_facet.hpp.j2 +++ b/codegen/abstract_facet.hpp.j2 @@ -1,4 +1,4 @@ -/** @file {{ abstract_facet_fname }} +/** @file {{abstract_facet_fname}} * * Generated automagically from ingredients: * 1. code generator: @@ -17,24 +17,56 @@ {% for include_fname in facet_includes %} #include {{include_fname}} {% endfor %} +#include +#include +#include namespace {{facet_ns1}} { namespace {{facet_ns2}} { +using Copaque = const void *; +using Opaque = void *; + /** {{abstract_facet_doc}} **/ class {{abstract_facet}} { public: - {% for method in methods %} + // types + {% for ty in types %} + /** {{ty.doc}} **/ + using {{ty.name}} = {{ty.definition}}; + {% endfor %} - /** {{method.doc}} **/ - virtual {{method.return_type}} {{method.name}}({{method.args | args}}) {{method | qualifiers}} = 0; + // const methods + /** RTTI: unique id# for actual runtime data representation **/ + virtual int32_t _typeseq() const noexcept = 0; + {% for md in const_methods %} + /** {{md.doc}} **/ + virtual {{md.return_type}} {{md.name}}({{md.args | args}}) {{md | qualifiers}} = 0; + {% endfor %} + // nonconst methods + {% for md in nonconst_methods %} + /** {{md.doc}} **/ + virtual {{md.return_type}} {{md.name}}({{md.args | args}}) {{md | qualifiers}} = 0; {% endfor %} }; /*{{abstract_facet}}*/ +/** Implementation {{iface_facet}}_DRepr of {{abstract_facet}} for state DRepr + * should provide a specialization: + * + * template <> + * struct xo::facet::FacetImplementation<{{abstract_facet}}, DRepr> { + * using Impltype = {{iface_facet}}_DRepr; + * }; + * + * then {{iface_facet_impltype}} --> {{iface_facet}}_DRepr + **/ template +using {{iface_facet_impltype}} = xo::facet::FacetImplType<{{abstract_facet}}, DRepr>; } /*namespace {{facet_ns2}}*/ } /*namespace {{facet_ns1}}*/ + +/* {{abstract_face_fname}} */ diff --git a/codegen/genfacet.py b/codegen/genfacet.py index aab098f..36b8396 100755 --- a/codegen/genfacet.py +++ b/codegen/genfacet.py @@ -32,6 +32,9 @@ def format_args(args, include_names=True): else: return ', '.join(p['type'] for p in args) +def format_args_nonames(args): + return format_args(args, False) + def format_arg_names(args): """ Format argument names, for forwarding """ @@ -61,6 +64,7 @@ def main(): # custom filters env.filters['qualifiers'] = format_method_qualifiers env.filters['args'] = format_args + env.filters['argtypes'] = format_args_nonames env.filters['argnames'] = format_arg_names facet_includes = idl['includes'] @@ -69,12 +73,29 @@ def main(): facet_name = idl['facet'] # e.g. Sequence facet_brief = idl['brief'] facet_doc = '\n'.join(idl['doc']) - methods = idl['methods'] - for method in methods: - method['doc'] = '\n'.join(method['doc']) + + types = idl['types'] + for ty in types: + ty['doc'] = '\n'.join(ty['doc']) + + const_methods = idl['const_methods'] + for md in const_methods: + md['args'] = [{'type': "Copaque", 'name': "data"}] + md['args'] + md['doc'] = '\n'.join(md['doc']) + + nonconst_methods = idl['nonconst_methods'] + for md in nonconst_methods: + md['args'] = [{'type': "Opaque", 'name': "data"}] + md['args'] + md['doc'] = '\n'.join(md['doc']) abstract_facet = f'A{facet_name}' abstract_facet_fname = f'{abstract_facet}.hpp' + # + iface_facet = f'I{facet_name}' + iface_facet_impltype = f'{iface_facet}_ImplType' + # + iface_facet_any = f'{iface_facet}_Any' + iface_facet_any_fname = f'{iface_facet_any}.hpp' context = { 'genfacet': __file__, @@ -91,13 +112,25 @@ def main(): 'abstract_facet_fname': abstract_facet_fname, 'abstract_facet_doc': facet_doc, # - 'methods': methods + 'iface_facet': iface_facet, + 'iface_facet_impltype': iface_facet_impltype, + # + 'iface_facet_any': iface_facet_any, + 'iface_facet_any_hpp_j2': 'iface_facet_any.hpp.j2', + 'iface_facet_any_fname': iface_facet_any_fname, + # + 'types': types, + # + 'const_methods': const_methods, + # + 'nonconst_methods': nonconst_methods, } # generate .hpp files templates = {} templates[abstract_facet_fname] = context['abstract_facet_hpp_j2'] + templates[iface_facet_any_fname] = context['iface_facet_any_hpp_j2'] for output_file, template_name in templates.items(): print(f'output_file: [{output_file}]') @@ -105,11 +138,10 @@ def main(): template = env.get_template(template_name) content = template.render(**context) - + (output_dir / output_file).write_text(content) print(f"Generated {output_dir}/{output_file}") if __name__ == '__main__': main() - diff --git a/codegen/iface_facet_any.hpp.j2 b/codegen/iface_facet_any.hpp.j2 new file mode 100644 index 0000000..11bbef3 --- /dev/null +++ b/codegen/iface_facet_any.hpp.j2 @@ -0,0 +1,72 @@ +/** @file {{iface_facet_any_fname}} + * + * Generated automagically from ingredients: + * 1. code generator: + * [{{genfacet}}] + * arguments: + * --input [{{genfacet_input}}] + * 2. jinja2 template for abstract facet .hpp file: + * [{{ iface_facet_any_hpp_j2 }}] + * 3. idl for facet methods + * [{{ idl_fname }}] + **/ + +#pragma once + +#include "{{abstract_facet_fname}}" +#include + +namespace {{facet_ns1}} { namespace {{facet_ns2}} { class {{iface_facet_any}}; } } + +namespace xo { +namespace facet { + +template <> +struct FacetImplementation<{{facet_ns1}}::{{facet_ns2}}::{{abstract_facet}}, + DVariantPlaceholder> +{ + using ImplType = {{facet_ns1}}::{{facet_ns2}}::{{iface_facet_any}}; +}; + +} +} + +namespace {{facet_ns1}} { +namespace {{facet_ns2}} { + +/** @class {{iface_facet_any}} + * @brief {{abstract_facet}} implementation for empty variant instance + **/ +class {{iface_facet_any}} : public {{abstract_facet}} { +public: + {% for ty in types %} + using {{ty.name}} = {{abstract_facet}}::{{ty.name}}; + {% endfor %} + + const {{abstract_facet}} * iface() const { return std::launder(this); } + + // from {{abstract_facet}} + + // const methods + int32_t _typeseq() const noexcept override { return s_typeseq; } + {% for md in const_methods %} + [[noreturn]] {{md.return_type}} {{md.name}}({{md.args | argtypes}}) {{md | qualifiers}} override { _fatal(); } + {% endfor %} + + // nonconst methods + {% for md in nonconst_methods %} + [[noreturn]] {{md.return_type}} {{md.name}}({{md.args | argtypes}}) {{md | qualifiers}} override { _fatail(); } + {% endfor %} + +private: + [[noreturn]] static void _fatal(); + +public: + static int32_t s_typeseq; + static bool _valid; +}; + +} /*namespace {{facet_ns2}} */ +} /*namespace {{facet_ns1}} */ + +/* {{iface_facet_any_fname}} */