Commit 82d15974 authored by David Thompson's avatar David Thompson
Browse files

WIP: Improvements to autogeneration...

... so that the test compiles and runs with autogenerated code.
parent 2c5ba0ef
......@@ -12,10 +12,83 @@ nodeClasses = {
'smtk::graph::Component': {
# All markup components inherit this base class used by several arc types.
'smtk::markup::Component': {
'header-forward-classes': ['smtk::markup::Group', 'smtk::markup::Label'],
'arcs': {
'groups': { 'type': 'Groups', 'template': 'Arcs', 'dest-type': 'smtk::markup::Group' },
'labels': { 'type': 'Labels', 'template': 'Arcs', 'dest-type': 'smtk::markup::Label' }
},
'members': {
'type_index': {
'type': 'static const Component::Index', 'access': 'public',
'description': 'A unique integer corresponding to the component type.',
},
'name': {
'type': 'std::string',
},
},
'internal-classes': {
'ModifyName': {
'type': 'struct',
'description': 'A functor for changing the name of a component.',
'body': """
struct Component::ModifyName
{
ModifyName(const std::string& nextName)
: m_name(nextName)
{
}
void operator()(Component::Ptr& c)
{
c->m_name = m_name;
}
std::string m_name;
};
"""
},
},
'methods': {
'index': {
'attributes': { 'virtual': True },
'signature': 'Component::Index index() const',
'description': 'The index is a compile-time intrinsic of the derived resource; as such, it cannot be set.',
'body': """return std::type_index(typeid(*this)).hash_code();""",
},
'name': {
'signature': 'std::string name() const override',
'description': 'Return the component\'s name.',
'body': """
return m_name;
""",
},
'setName': {
'signature': 'bool setName(const std::string& name)',
'description': """Set the component's name.""",
'body': """
if (name == m_name)
{
return false;
}
auto owner = std::dynamic_pointer_cast<smtk::markup::Resource>(this->resource());
if (owner)
{
// We are not allowed to set our name directly since
// our owning resource has indexed us by name.
return owner->modifyComponent(*this, ModifyName(name));
}
m_name = name;
return true;
""",
}
},
'type-aliases': {
'Index': 'std::size_t'
},
'source-includes': [
'smtk/markup/Resource.h',
],
# Indexing components
# These components are used to enumerate the domain of discrete and parametric datasets.
'smtk::markup::Domain': {
......@@ -96,7 +169,7 @@ nodeClasses = {
},
'visit' : {
'signature': 'smtk::common::Visit visit(Visitor visitor) const',
'description': 'Call \a visitor on each alloted ID.',
'description': 'Call \\a visitor on each alloted ID.',
'attributes': [ 'pure virtual' ]
}
},
......@@ -123,6 +196,12 @@ nodeClasses = {
},
# Organizational components
'smtk::markup::Ontology': {
'header-includes': [
'smtk/markup/IdSpace.h',
],
'type-aliases': {
'IdType': 'smtk::markup::IdSpace::IdType'
},
'description': 'A collection of labels related to one another by relationships, typically imported from an OWL',
'members': {
'url': { 'type': 'std::string' },
......@@ -320,12 +399,16 @@ nodeClasses = {
'methods': {
'name': {
'signature': 'std::string name() const',
'attributes': { 'override': True },
'body': """
return m_name;
return m_name.data();
"""
},
},
'smtk::markup::LabelMap': {
'header-includes': [
'smtk/markup/IdSpace.h'
],
'description': 'A mapping from an IdSpace to an integer label, with optional string names for each integer.',
'members': {
'names' : { 'type': 'std::unordered_map<smtk::markup::IdSpace::IdType, smtk::string::Token>', 'description': 'A set of labels that form the image of the label-map.' },
......@@ -341,16 +424,25 @@ nodeClasses = {
},
'smtk::markup::OntologyIdentifier': {
'type-aliases': {
'IdType' : 'smtk::markup::Ontology::IdType',
'Token' : 'smtk::string::Token',
},
'header-includes': [
'smtk/markup/Ontology.h',
'smtk/string/Token.h',
],
'members': {
'id': { 'type': 'IdType', 'description': 'A URL in the ontology''s schema that can be queried for relationships.' },
'ontologyId': {
'type': 'OntologyIdentifier::Token',
'description': 'A URL in the ontology''s schema that can be queried for relationships.' },
},
'arcs': {
'ontology': { 'type': 'OntologySource', 'template': 'Arc', 'dest-type': 'smtk::markup::Ontology' },
},
},
'smtk::markup::Comment': {
'header-includes': [
'smtk/string/Token.h',
],
'members': {
'data': { 'type': 'smtk::string::Token', 'description': 'Text of the comment.' },
'mimetype': { 'type': 'smtk::string::Token', 'description': 'Mime type of the comment. The default is "text/plain".' },
......@@ -478,7 +570,7 @@ def generateHeaderHeader(ns, name, inherit, extraIncludes, forwardClasses):
def generateHeaderFooter(ns, name):
nspath = '_'.join(ns) + '_' + name + "_h"
footer = '\n' + closeNamespaces(ns) + '\n'
footer += '#endif // {0}'.format(nspath)
footer += '#endif // {0}\n'.format(nspath)
return footer
def generateSourceHeader(ns, name):
......@@ -494,6 +586,14 @@ def generateSourceFooter(ns, name):
footer = '\n' + closeNamespaces(ns)
return footer
def generateInternalClasses(entry):
code = ''
if 'internal-classes' not in entry:
return code
for internalClassName, internalClass in entry['internal-classes'].items():
code += dedentString(internalClass['body'])
return code
def generateCtorDtor(ns, bareName, classDef, includes):
# TODO: Check classDef for special ctor
code = dedentString("""
......@@ -531,7 +631,7 @@ def generateMethodStubs(ns, bareName, classDef, includes):
for methodName, methodDef in classDef['methods'].items():
if isPureVirtualMethod(methodDef):
continue
sig = methodDef['signature'].replace(methodName, '{0}::{1}'.format(bareName, methodName), 1)
sig = methodDef['signature'].replace(methodName, '{0}::{1}'.format(bareName, methodName), 1).replace(' override','')
if 'body' in methodDef:
code += dedentString(sig) + '\n{{\n{0}}}\n\n'.format(indentString(dedentString(methodDef['body']), 2))
else:
......@@ -542,6 +642,10 @@ def generateMethodStubs(ns, bareName, classDef, includes):
if 'members' in classDef:
for memberName, memberDef in classDef['members'].items():
mType = memberDef['type']
if 'access' in memberDef and memberDef['access'] == 'public':
# Do not provide setter/getter methods; access is direct.
continue;
explicitSetter = True if 'set%s' % camelCase(memberName) in methodNames else False
explicitGetter = True if '%s' % memberName in methodNames else False
# Add a "set" method
......@@ -583,7 +687,7 @@ def generateMethodStubs(ns, bareName, classDef, includes):
""".format(bareName, memberName, camelCase(memberName), mType)) + '\n'
# Add "get" methods
if not explicitGetter:
if not explicitGetter and (memberDef['access'] != 'write-only' if 'access' in memberDef else True):
code += dedentString("""
const {3}& {0}::{1}() const
{{
......@@ -699,27 +803,37 @@ def emitClass(name, classType, classList, inherit, moduleData):
if 'methods' in entry:
headerData += '\n';
methods = entry['methods']
for method in methods:
headerData += ' {0};\n'.format(methods[method]['signature'])
methodNames.add(method)
for methodName, method in methods.items():
if 'description' in method:
description = dedentString(method['description']).split('\n')
for line in description:
headerData += ' /// {0}\n'.format(line)
headerData += ' {0};\n'.format(method['signature'])
methodNames.add(methodName)
# Add accessors for member variables.
if 'members' in entry:
members = entry['members']
for memberName, member in members.items():
access = member['access'] if 'access' in member else 'read-write'
attributes = member['attributes'] if 'attributes' in member else {}
override = ' override' if 'override' in attributes and attributes['override'] else ''
casedName = camelCase(memberName)
headerData += '\n';
if 'description' in member:
description = dedentString(member['description']).split('\n')
for line in description:
headerData += '/// {0}\n'.format(line)
headerData += ' /// {0}\n'.format(line)
if access == 'public':
# Do not provide setter/getter methods, instead declare here.
headerData += ' {0} {1};'.format(member['type'], memberName)
continue # Skip setter/getter generation
# Do not declare a set-method if read-only or explicitly declared.
if (access == 'read-write' or access == 'force-write') and 'set{0}'.format(camelCase(memberName)) not in methodNames:
headerData += ' bool set{0}(const {1}& {2});\n'.format(casedName, member['type'], memberName)
headerData += ' bool set{0}(const {1}& {2}){3};\n'.format(casedName, member['type'], memberName, override)
# Do not declare a get-method if explicitly declared.
if access != 'write-only' and memberName not in methodNames:
headerData += ' const {0}& {1}() const;\n'.format(member['type'], memberName)
headerData += ' {0}& {1}();\n'.format(member['type'], memberName)
headerData += ' const {0}& {1}() const{2};\n'.format(member['type'], memberName, override)
headerData += ' {0}& {1}(){2};\n'.format(member['type'], memberName, override)
# Add accessors for arcs that originate from instances of this class.
if 'arcs' in entry:
arcs = entry['arcs']
......@@ -744,6 +858,14 @@ def emitClass(name, classType, classList, inherit, moduleData):
else:
print('ERROR: Unhandled arc template %s' % arcData['template'])
headerData += '\nprotected:\n'
if 'internal-classes' in entry:
for internalClassName, internalClass in entry['internal-classes'].items():
description = dedentString(internalClass['description']).split('\n') if 'description' in internalClass else []
if len(description):
for line in description:
headerData += ' /// {0}\n'.format(line)
headerData += ' {0} {1};\n'.format(internalClass['type'], internalClassName)
headerData += '\n'
haveProtectedMethods = False
if 'protected-methods' in entry:
haveProtectedMethods = True
......@@ -756,8 +878,10 @@ def emitClass(name, classType, classList, inherit, moduleData):
headerData += '\n'
# print(' Add members')
members = entry['members']
for member in members:
headerData += ' {0} m_{1};\n'.format(members[member]['type'], member)
for memberName, member in members.items():
if 'access' in member and member['access'] == 'public':
continue
headerData += ' {0} m_{1};\n'.format(member['type'], memberName)
headerData += '};\n'
headerData += generateHeaderFooter(ns, bareName)
......@@ -765,14 +889,18 @@ def emitClass(name, classType, classList, inherit, moduleData):
# Source body
sourceData = generateSourceHeader(ns, bareName)
includes = set()
iclss = generateInternalClasses(entry)
cdtor = generateCtorDtor(ns, bareName, entry, includes)
mstub = generateMethodStubs(ns, bareName, entry, includes)
allIncludes = []
if 'header-forward-classes' in entry:
allIncludes += [classNameToHeaderName(x) for x in entry['header-forward-classes']]
if 'source-includes' in entry:
allIncludes += [x for x in entry['source-includes']]
allIncludes += list(includes)
sourceData += includeDirectives(allIncludes)
sourceData += openNamespaces(ns)
sourceData += iclss
sourceData += cdtor
sourceData += mstub
sourceData += generateSourceFooter(ns, bareName)
......@@ -802,7 +930,7 @@ def generate(classList, classType = 'nodes', moduleData = {}, inherit = None):
if inherit is None:
inherit = [] if classType == 'arcs' else ['smtk::graph::Component']
keywords = set(['access', 'arcs', 'attributes', 'body', 'description', 'dest-type', 'enums', 'header-includes', 'header-forward-classes', 'inverse', 'members', 'methods', 'protected-methods', 'signature', 'source-type', 'template', 'type-aliases'])
keywords = set(['access', 'arcs', 'attributes', 'body', 'description', 'dest-type', 'enums', 'header-includes', 'header-forward-classes', 'internal-classes', 'inverse', 'members', 'methods', 'protected-methods', 'signature', 'source-includes', 'source-type', 'template', 'type-aliases'])
for name in classList.keys():
if name in keywords:
continue
......
......@@ -30,4 +30,4 @@ protected:
} // namespace markup
} // namespace smtk
#endif // smtk_markup_AnalyticShape_h
\ No newline at end of file
#endif // smtk_markup_AnalyticShape_h
......@@ -37,9 +37,13 @@ public:
~AssignedIds() override;
/// Returns the range of IDs in the allotment.
std::array<AssignedIds::IdType, 2> range() const;
/// Returns a functor to iterate all assigned IDs. Call the functor until it returns false.
Iterable iterable() const;
/// Returns functor to query the number of allotted ids in the half-open interval [begin, end[.
ContainsFunctor contains() const;
/// Call \a visitor on each alloted ID.
smtk::common::Visit visit(Visitor visitor) const;
bool setSpace(const std::weak_ptr<smtk::markup::IdSpace>& space);
......@@ -58,4 +62,4 @@ protected:
} // namespace markup
} // namespace smtk
#endif // smtk_markup_AssignedIds_h
\ No newline at end of file
#endif // smtk_markup_AssignedIds_h
......@@ -30,4 +30,4 @@ protected:
} // namespace markup
} // namespace smtk
#endif // smtk_markup_BoundaryOperator_h
\ No newline at end of file
#endif // smtk_markup_BoundaryOperator_h
......@@ -35,4 +35,4 @@ protected:
} // namespace markup
} // namespace smtk
#endif // smtk_markup_Box_h
\ No newline at end of file
#endif // smtk_markup_Box_h
......@@ -3,6 +3,7 @@
#define smtk_markup_Comment_h
#include "smtk/markup/Label.h"
#include "smtk/string/Token.h"
namespace smtk
......@@ -24,12 +25,12 @@ public:
~Comment() override;
/// Text of the comment.
/// Text of the comment.
bool setData(const smtk::string::Token& data);
const smtk::string::Token& data() const;
smtk::string::Token& data();
/// Mime type of the comment. The default is "text/plain".
/// Mime type of the comment. The default is "text/plain".
bool setMimetype(const smtk::string::Token& mimetype);
const smtk::string::Token& mimetype() const;
smtk::string::Token& mimetype();
......
// Copyright © Kitware Inc under the [BSD-3-clause license](https://kitware.com/licenses/bsd.md).
#include "smtk/markup/Component.h"
#include "smtk/markup/Group.h"
#include "smtk/markup/Label.h"
#include "smtk/markup/Resource.h"
namespace smtk
......@@ -21,9 +24,17 @@ struct Component::ModifyName
std::string m_name;
};
Component::~Component() = default;
Component::Index Component::index() const
{
return std::type_index(typeid(*this)).hash_code();}
std::string Component::name() const
{
return m_name;
}
bool Component::setName(const std::string& name)
{
if (name == m_name)
......@@ -42,5 +53,6 @@ bool Component::setName(const std::string& name)
return true;
}
} // namespace markup
} // namespace smtk
......@@ -8,22 +8,22 @@
#include "smtk/markup/ArcEditor.h"
namespace smtk {namespace markup { class Group; } }
namespace smtk {namespace markup { class Label; } }
namespace smtk
{
namespace markup
{
class Group;
class Label;
class SMTKMARKUP_EXPORT Component : public smtk::graph::Component
{
public:
using Index = std::size_t;
smtkTypeMacro(smtk::markup::Component);
smtkSuperclassMacro(smtk::graph::Component);
using Index = std::size_t;
template<typename... Args>
Component(Args&&... args)
: smtk::graph::Component(std::forward<Args>(args)...)
......@@ -32,28 +32,25 @@ public:
~Component() override;
/// A unique integer corresponding to the component type.
static const Component::Index type_index;
/**\brief The index is a compile-time intrinsic of the derived resource;
* as such, it cannot be set.
*/
virtual Index index() const { return std::type_index(typeid(*this)).hash_code(); }
/// The index is a compile-time intrinsic of the derived resource; as such, it cannot be set.
Component::Index index() const;
/// Return the component's name.
std::string name() const override { return m_name; }
std::string name() const override;
/// Set the component's name.
bool setName(const std::string& name);
/// A unique integer corresponding to the component type.
static const Component::Index type_index;
ArcEditor<SelfType, smtk::markup::Group> groups() const;
ArcEditor<SelfType, smtk::markup::Label> labels() const;
protected:
std::string m_name;
/// A functor for changing the name of a component.
struct ModifyName;
std::string m_name;
};
} // namespace markup
......
......@@ -37,4 +37,4 @@ protected:
} // namespace markup
} // namespace smtk
#endif // smtk_markup_CompositeSubset_h
\ No newline at end of file
#endif // smtk_markup_CompositeSubset_h
......@@ -40,4 +40,4 @@ protected:
} // namespace markup
} // namespace smtk
#endif // smtk_markup_Cone_h
\ No newline at end of file
#endif // smtk_markup_Cone_h
......@@ -29,4 +29,4 @@ protected:
} // namespace markup
} // namespace smtk
#endif // smtk_markup_DiscreteGeometry_h
\ No newline at end of file
#endif // smtk_markup_DiscreteGeometry_h
......@@ -30,4 +30,4 @@ protected:
} // namespace markup
} // namespace smtk
#endif // smtk_markup_Domain_h
\ No newline at end of file
#endif // smtk_markup_Domain_h
......@@ -35,4 +35,4 @@ protected:
} // namespace markup
} // namespace smtk
#endif // smtk_markup_ExplicitSubset_h
\ No newline at end of file
#endif // smtk_markup_ExplicitSubset_h
......@@ -29,4 +29,4 @@ protected:
} // namespace markup
} // namespace smtk
#endif // smtk_markup_Feature_h
\ No newline at end of file
#endif // smtk_markup_Feature_h
......@@ -35,4 +35,4 @@ protected:
} // namespace markup
} // namespace smtk
#endif // smtk_markup_Frame_h
\ No newline at end of file
#endif // smtk_markup_Frame_h
......@@ -42,4 +42,4 @@ protected:
} // namespace markup
} // namespace smtk
#endif // smtk_markup_Grid_h
\ No newline at end of file
#endif // smtk_markup_Grid_h
......@@ -50,11 +50,6 @@ bool& Group::ownsMembers()
return m_ownsMembers;
}
ArcEditor<Group, Component> Group::members() const
{
ArcEditor<Group, Component> stuff;
return stuff;
}
} // namespace markup
} // namespace smtk
......@@ -39,4 +39,4 @@ protected:
} // namespace markup
} // namespace smtk
#endif // smtk_markup_IdSpace_h
\ No newline at end of file
#endif // smtk_markup_IdSpace_h
......@@ -55,4 +55,4 @@ protected:
} // namespace markup
} // namespace smtk
#endif // smtk_markup_Image_h
\ No newline at end of file
#endif // smtk_markup_Image_h
......@@ -45,4 +45,4 @@ protected:
} // namespace markup
} // namespace smtk
#endif // smtk_markup_ImplicitShape_h
\ No newline at end of file
#endif // smtk_markup_ImplicitShape_h
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment