xo-facet: facet template [WIP]
This commit is contained in:
parent
a8ff0ffec3
commit
eadf26bb9c
5 changed files with 298 additions and 0 deletions
40
xo-facet/codegen/abstract_facet.hpp.j2
Normal file
40
xo-facet/codegen/abstract_facet.hpp.j2
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
/** @file {{ abstract_facet_fname }}
|
||||||
|
*
|
||||||
|
* Generated automagically from ingredients:
|
||||||
|
* 1. code generator:
|
||||||
|
* [{{genfacet}}]
|
||||||
|
* arguments:
|
||||||
|
* --input [{{genfacet_input}}]
|
||||||
|
* 2. jinja2 template for abstract facet .hpp file:
|
||||||
|
* [{{ abstract_facet_hpp_j2 }}]
|
||||||
|
* 3. idl for facet methods
|
||||||
|
* [{{ idl_fname }}]
|
||||||
|
**/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// includes (via {facet_includes})
|
||||||
|
{% for include_fname in facet_includes %}
|
||||||
|
#include {{include_fname}}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
namespace {{facet_ns1}} {
|
||||||
|
namespace {{facet_ns2}} {
|
||||||
|
|
||||||
|
/**
|
||||||
|
{{abstract_facet_doc}}
|
||||||
|
**/
|
||||||
|
class {{abstract_facet}} {
|
||||||
|
public:
|
||||||
|
{% for method in methods %}
|
||||||
|
|
||||||
|
/** {{method.doc}} **/
|
||||||
|
virtual {{method.return_type}} {{method.name}}({{method.args | args}}) {{method | qualifiers}} = 0;
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
}; /*{{abstract_facet}}*/
|
||||||
|
|
||||||
|
template <typename DRepr>
|
||||||
|
|
||||||
|
} /*namespace {{facet_ns2}}*/
|
||||||
|
} /*namespace {{facet_ns1}}*/
|
||||||
115
xo-facet/codegen/genfacet.py
Executable file
115
xo-facet/codegen/genfacet.py
Executable file
|
|
@ -0,0 +1,115 @@
|
||||||
|
#! /usr/bin/env python3
|
||||||
|
#
|
||||||
|
# genfacet.py
|
||||||
|
|
||||||
|
import json5
|
||||||
|
import argparse
|
||||||
|
from pathlib import Path
|
||||||
|
from jinja2 import Environment, FileSystemLoader
|
||||||
|
|
||||||
|
def load_idl(path):
|
||||||
|
with open(path) as f:
|
||||||
|
return json5.load(f)
|
||||||
|
|
||||||
|
def format_method_qualifiers(method):
|
||||||
|
""" Build qualifier string: const noexcept
|
||||||
|
"""
|
||||||
|
quals = []
|
||||||
|
if method.get('const', False):
|
||||||
|
quals.append('const')
|
||||||
|
if method.get('noexcept', False):
|
||||||
|
quals.append('noexcept')
|
||||||
|
|
||||||
|
return ' '.join(quals)
|
||||||
|
|
||||||
|
def format_args(args, include_names=True):
|
||||||
|
""" Format argument list for a method
|
||||||
|
"""
|
||||||
|
if not args:
|
||||||
|
return ''
|
||||||
|
if include_names:
|
||||||
|
return ', '.join(f"{p['type']} {p['name']}" for p in args)
|
||||||
|
else:
|
||||||
|
return ', '.join(p['type'] for p in args)
|
||||||
|
|
||||||
|
def format_arg_names(args):
|
||||||
|
""" Format argument names, for forwarding
|
||||||
|
"""
|
||||||
|
return ', '.join(p['name'] for p in args)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('--input', required=True, help='input IDL JSON5 file')
|
||||||
|
parser.add_argument('--output', required=True, help='output directory')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
idl_fname = args.input
|
||||||
|
idl = load_idl(idl_fname)
|
||||||
|
output_dir = Path(args.output)
|
||||||
|
output_dir.mkdir(parents=False, exist_ok=True)
|
||||||
|
|
||||||
|
# setup jinja2
|
||||||
|
template_dir = Path(__file__).parent
|
||||||
|
#template_dir = Path(__file__).parent / 'codegen'
|
||||||
|
|
||||||
|
print(f'template_dir: [{template_dir}]')
|
||||||
|
|
||||||
|
env = Environment(loader = FileSystemLoader(template_dir),
|
||||||
|
trim_blocks = True,
|
||||||
|
lstrip_blocks = True)
|
||||||
|
|
||||||
|
# custom filters
|
||||||
|
env.filters['qualifiers'] = format_method_qualifiers
|
||||||
|
env.filters['args'] = format_args
|
||||||
|
env.filters['argnames'] = format_arg_names
|
||||||
|
|
||||||
|
facet_includes = idl['includes']
|
||||||
|
facet_ns1 = idl['namespace1']
|
||||||
|
facet_ns2 = idl['namespace2']
|
||||||
|
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'])
|
||||||
|
|
||||||
|
abstract_facet = f'A{facet_name}'
|
||||||
|
abstract_facet_fname = f'{abstract_facet}.hpp'
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'genfacet': __file__,
|
||||||
|
'genfacet_input': args.input,
|
||||||
|
#
|
||||||
|
'facet_includes': facet_includes,
|
||||||
|
'facet_ns1': facet_ns1,
|
||||||
|
'facet_ns2': facet_ns2,
|
||||||
|
#'name': facet_name,
|
||||||
|
'idl_fname': idl_fname,
|
||||||
|
#
|
||||||
|
'abstract_facet_hpp_j2': 'abstract_facet.hpp.j2',
|
||||||
|
'abstract_facet': abstract_facet,
|
||||||
|
'abstract_facet_fname': abstract_facet_fname,
|
||||||
|
'abstract_facet_doc': facet_doc,
|
||||||
|
#
|
||||||
|
'methods': methods
|
||||||
|
}
|
||||||
|
|
||||||
|
# generate .hpp files
|
||||||
|
|
||||||
|
templates = {}
|
||||||
|
templates[abstract_facet_fname] = context['abstract_facet_hpp_j2']
|
||||||
|
|
||||||
|
for output_file, template_name in templates.items():
|
||||||
|
print(f'output_file: [{output_file}]')
|
||||||
|
print(f'template_name: [{template_name}]')
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
53
xo-gc/include/xo/gc/detail/AGCObject.hpp
Normal file
53
xo-gc/include/xo/gc/detail/AGCObject.hpp
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
/** @file AGCObject.hpp
|
||||||
|
*
|
||||||
|
* @author Roland Conybeare, Dec 2025
|
||||||
|
**/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Allocator.hpp"
|
||||||
|
#include "xo/facet/facet_implementation.hpp"
|
||||||
|
#include "xo/facet/typeseq.hpp"
|
||||||
|
#include "xo/facet/obj.hpp" // for obj<AAllocator> in shallow_copy
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
namespace mm {
|
||||||
|
using Copaque = const void *;
|
||||||
|
using Opaque = void *;
|
||||||
|
|
||||||
|
/** @class AObject
|
||||||
|
* @brief Abstract facet for collector-eligible data
|
||||||
|
*
|
||||||
|
* Data that supports AGCObject can have memory managed
|
||||||
|
* by ACollector
|
||||||
|
**/
|
||||||
|
struct AGCObject {
|
||||||
|
using size_type = std::size_t;
|
||||||
|
|
||||||
|
/** RTTI: unique id# for actual runtime data representation **/
|
||||||
|
virtual int32_t _typeseq() const noexcept = 0;
|
||||||
|
|
||||||
|
virtual size_type shallow_size(Copaque d) const noexcept = 0;
|
||||||
|
virtual Opaque * shallow_copy(Copaque d,
|
||||||
|
obj<AAllocator> mm) const noexcept = 0;
|
||||||
|
virtual size_type forward_children(Opaque d) const noexcept = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// implementation IGCObject_DRepr of AGCObject for state DRepr
|
||||||
|
// should provide a specialization:
|
||||||
|
//
|
||||||
|
// template <>
|
||||||
|
// struct xo::facet::FacetImplementation<AGCObjectx, DRepr> {
|
||||||
|
// using ImplType = IGCObject_DRepr;
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// then IGCObject_ImplType<DRepr> --> IGCObject_DRepr
|
||||||
|
//
|
||||||
|
template <typename DRepr>
|
||||||
|
using IGCObject_ImplType = xo::facet::FacetImplType<AGCObject, DRepr>;
|
||||||
|
} /*namespace mm*/
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
/* end AGCObject.hpp */
|
||||||
47
xo-object2/idl/Sequence.json5
Normal file
47
xo-object2/idl/Sequence.json5
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
{
|
||||||
|
includes: ["<xo/gc/GCObject.hpp>"],
|
||||||
|
namespace1: "xo",
|
||||||
|
namespace2: "scm",
|
||||||
|
facet: "Sequence",
|
||||||
|
brief: "an ordered collection of variants",
|
||||||
|
doc: [
|
||||||
|
"Elements appear in some determinstic order.",
|
||||||
|
"Sequence is GC-aware --> elements must be GC-aware"
|
||||||
|
],
|
||||||
|
methods: [
|
||||||
|
// bool is_empty() const noexcept
|
||||||
|
{
|
||||||
|
name: "is_empty",
|
||||||
|
doc: ["true iff sequence is empty"],
|
||||||
|
return_type: "bool",
|
||||||
|
args: [],
|
||||||
|
const: true,
|
||||||
|
noexcept: true,
|
||||||
|
attributes: [],
|
||||||
|
},
|
||||||
|
|
||||||
|
// bool is_finite() const noexcept
|
||||||
|
{
|
||||||
|
name: "is_finite",
|
||||||
|
doc: ["true iff sequence is finite"],
|
||||||
|
return_type: "bool",
|
||||||
|
args: [],
|
||||||
|
const: true,
|
||||||
|
noexcept: true,
|
||||||
|
attributes: [],
|
||||||
|
},
|
||||||
|
|
||||||
|
// obj<AGCObject> at(size_type index) const;
|
||||||
|
{
|
||||||
|
name: "at",
|
||||||
|
doc: ["return element @p index of this sequence"],
|
||||||
|
return_type: "obj<AGCObject>",
|
||||||
|
args: [
|
||||||
|
{type: "size_type", name: "index"},
|
||||||
|
],
|
||||||
|
const: true,
|
||||||
|
noexcept: false,
|
||||||
|
attributes: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
43
xo-object2/include/xo/object2/ASequence.hpp
Normal file
43
xo-object2/include/xo/object2/ASequence.hpp
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
/** @file ASequence.hpp
|
||||||
|
*
|
||||||
|
* Generated automagically from ingredients:
|
||||||
|
* 1. code generator:
|
||||||
|
* [/home/roland/proj/xo-umbrella2/xo-object2/../xo-facet/codegen/genfacet.py]
|
||||||
|
* arguments:
|
||||||
|
* --input [./idl/Sequence.json5]
|
||||||
|
* 2. jinja2 template for abstract facet .hpp file:
|
||||||
|
* [abstract_facet.hpp.j2]
|
||||||
|
* 3. idl for facet methods
|
||||||
|
* [./idl/Sequence.json5]
|
||||||
|
**/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// includes (via {facet_includes})
|
||||||
|
#include <xo/gc/GCObject.hpp>
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
namespace scm {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Elements appear in some determinstic order.
|
||||||
|
Sequence is GC-aware --> elements must be GC-aware
|
||||||
|
**/
|
||||||
|
class ASequence {
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** true iff sequence is empty **/
|
||||||
|
virtual bool is_empty() const noexcept = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/** true iff sequence is finite **/
|
||||||
|
virtual bool is_finite() const noexcept = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/** return element @p index of this sequence **/
|
||||||
|
virtual obj<AGCObject> at(size_type index) const = 0;
|
||||||
|
|
||||||
|
}; /*ASequence*/
|
||||||
|
|
||||||
|
} /*namespace scm*/
|
||||||
|
} /*namespace xo*/
|
||||||
Loading…
Add table
Add a link
Reference in a new issue