First Commit
This commit is contained in:
@@ -0,0 +1,444 @@
|
||||
# IfcOpenShell - IFC toolkit and geometry engine
|
||||
# Copyright (C) 2021 Thomas Krijnen <thomas@aecgeeks.com>
|
||||
#
|
||||
# This file is part of IfcOpenShell.
|
||||
#
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# IfcOpenShell is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
import codegen
|
||||
import templates
|
||||
|
||||
from schema import OrderedCaseInsensitiveDict
|
||||
|
||||
from header import USE_VIRTUAL_INHERITANCE
|
||||
|
||||
|
||||
class Implementation(codegen.Base):
|
||||
def __init__(self, mapping):
|
||||
enumeration_functions = []
|
||||
entity_implementations = []
|
||||
schema_entity_statements = []
|
||||
|
||||
schema_name = mapping.schema.name.capitalize()
|
||||
schema_name_upper = mapping.schema.name.upper()
|
||||
|
||||
stringify = lambda s: '"%s"' % s
|
||||
cat = lambda vs: "".join(vs)
|
||||
catc = lambda vs: ", ".join(vs)
|
||||
catnl = lambda vs: "\n".join(vs)
|
||||
cator = lambda vs: " || ".join(vs)
|
||||
nl = lambda s: "%s\n" % s if len(s) else s
|
||||
|
||||
write = lambda str, **kwargs: enumeration_functions.append(str % kwargs)
|
||||
|
||||
collections_by_type = (
|
||||
("entity", mapping.schema.entities),
|
||||
("type_declaration", mapping.schema.simpletypes),
|
||||
("select_type", mapping.schema.selects),
|
||||
("enumeration_type", mapping.schema.enumerations),
|
||||
)
|
||||
self.names = []
|
||||
for _, collection in collections_by_type:
|
||||
self.names.extend(collection.keys())
|
||||
self.names.sort(key=str.lower)
|
||||
|
||||
for name, enum in mapping.schema.enumerations.items():
|
||||
short_name = name[:-4] if name.endswith("Enum") else name
|
||||
context = locals()
|
||||
write(
|
||||
templates.enumeration_function,
|
||||
max_id=len(enum.values),
|
||||
name=name,
|
||||
schema_name=schema_name,
|
||||
schema_name_upper=schema_name_upper,
|
||||
index_in_schema=self.names.index(str(name)),
|
||||
values=catc(map(stringify, enum.values)),
|
||||
from_string_statements=catnl(
|
||||
templates.enum_from_string_stmt % dict(context, **locals()) for value in enum.values
|
||||
),
|
||||
)
|
||||
|
||||
if USE_VIRTUAL_INHERITANCE:
|
||||
for name, enum in mapping.schema.selects.items():
|
||||
write(
|
||||
templates.select_function,
|
||||
name=name,
|
||||
schema_name=schema_name,
|
||||
schema_name_upper=schema_name_upper,
|
||||
index_in_schema=self.names.index(str(name)),
|
||||
)
|
||||
|
||||
write = lambda str, **kwargs: entity_implementations.append(str % kwargs)
|
||||
|
||||
for name, type in mapping.schema.entities.items():
|
||||
parent_type_test = (
|
||||
""
|
||||
if not type.supertypes or len(type.supertypes) != 1
|
||||
else templates.parent_type_test % (type.supertypes[0])
|
||||
)
|
||||
|
||||
constructor_arguments = mapping.get_assignable_arguments(type, include_derived=True)
|
||||
constructor_arguments_str = catc(
|
||||
"%(full_type)s v%(index)d_%(name)s" % a for a in constructor_arguments if not a["is_derived"]
|
||||
)
|
||||
attributes = []
|
||||
constructor_implementations = []
|
||||
write_attr = lambda str, **kwargs: attributes.append(str % kwargs)
|
||||
for arg in constructor_arguments:
|
||||
if not arg["is_inherited"] and not arg["is_derived"]:
|
||||
|
||||
def find_template(arg):
|
||||
simple = mapping.schema.is_simpletype(arg["list_instance_type"])
|
||||
select = arg["list_instance_type"] == "IfcUtil::IfcBaseClass"
|
||||
express = (
|
||||
mapping.flatten_type_string(arg["list_instance_type"]) in mapping.express_to_cpp_typemapping
|
||||
)
|
||||
if arg["is_enum"]:
|
||||
return templates.get_attr_stmt_enum
|
||||
elif arg["is_nested"] and arg["is_templated_list"]:
|
||||
return templates.get_attr_stmt_nested_array
|
||||
elif arg["is_templated_list"] and not (select or simple or express):
|
||||
return templates.get_attr_stmt_array
|
||||
elif arg["non_optional_type"].endswith("*"):
|
||||
return templates.get_attr_stmt_entity
|
||||
else:
|
||||
return templates.get_attr_stmt
|
||||
|
||||
null_check = ""
|
||||
if arg["is_optional"]:
|
||||
attr_check = "if(get_attribute_value(%d).isNull()) { return %%s; }" % (arg["index"] - 1,)
|
||||
if "boost::optional" in arg["full_type"]:
|
||||
null_check = attr_check % "boost::none"
|
||||
else:
|
||||
null_check = attr_check % "nullptr"
|
||||
|
||||
tmpl = find_template(arg)
|
||||
write_attr(
|
||||
templates.const_function,
|
||||
class_name=name,
|
||||
name=arg["name"],
|
||||
arguments="",
|
||||
schema_name=schema_name,
|
||||
schema_name_upper=schema_name_upper,
|
||||
return_type=arg["full_type"],
|
||||
body=tmpl
|
||||
% {
|
||||
"index": arg["index"] - 1,
|
||||
"type": arg["full_type"].replace("::Value", ""),
|
||||
"non_optional_type": arg["non_optional_type"].replace("::Value", ""),
|
||||
"non_optional_type_no_pointer": arg["non_optional_type"]
|
||||
.replace("::Value", "")
|
||||
.replace("*", ""),
|
||||
"list_instance_type": arg["list_instance_type"],
|
||||
"null_check": null_check,
|
||||
},
|
||||
)
|
||||
|
||||
def find_template(arg):
|
||||
simple = mapping.schema.is_simpletype(arg["list_instance_type"])
|
||||
select = arg["list_instance_type"] == "IfcUtil::IfcBaseClass"
|
||||
express = arg["list_instance_type"] in mapping.express_to_cpp_typemapping
|
||||
if arg["is_enum"]:
|
||||
return templates.set_attr_stmt_enum
|
||||
elif arg["is_templated_list"] and not (select or simple or express):
|
||||
return templates.set_attr_stmt_array
|
||||
elif arg["full_type"].endswith("*"):
|
||||
return templates.set_attr_instance
|
||||
else:
|
||||
return templates.set_attr_stmt
|
||||
|
||||
tmpl = find_template(arg)
|
||||
write_attr(
|
||||
templates.function,
|
||||
class_name=name,
|
||||
name="set%s" % arg["name"],
|
||||
arguments="%s v" % arg["full_type"],
|
||||
return_type="void",
|
||||
schema_name=schema_name,
|
||||
schema_name_upper=schema_name_upper,
|
||||
body=tmpl
|
||||
% {
|
||||
"index": arg["index"] - 1,
|
||||
"type": arg["full_type"].replace("::Value", ""),
|
||||
"non_optional_type": arg["non_optional_type"].replace("::Value", ""),
|
||||
"star_if_optional": "*" if "boost::optional" in arg["full_type"] else "",
|
||||
"check_optional_set_begin": "if (v) {" if "boost::optional" in arg["full_type"] else "",
|
||||
"check_optional_set_else": (
|
||||
"} else {" if "boost::optional" in arg["full_type"] else "if constexpr (false)"
|
||||
),
|
||||
"check_optional_set_end": "}" if "boost::optional" in arg["full_type"] else "",
|
||||
},
|
||||
)
|
||||
|
||||
if arg["is_derived"]:
|
||||
constructor_implementations.append(templates.constructor_stmt_derived % {"index": arg["index"] - 1})
|
||||
else:
|
||||
is_optional_non_naked_ptr = arg["is_optional"] and not arg["non_optional_type"].endswith("*")
|
||||
arg_name = "v%(index)d_%(name)s" % arg
|
||||
deref_name = ("*%s" % arg_name) if is_optional_non_naked_ptr else arg_name
|
||||
|
||||
tmpl = (
|
||||
templates.constructor_stmt_array
|
||||
if arg["is_templated_list"]
|
||||
else (
|
||||
templates.constructor_stmt_enum
|
||||
if arg["is_enum"]
|
||||
else (
|
||||
templates.constructor_stmt_instance
|
||||
if arg["full_type"].endswith("*")
|
||||
else templates.constructor_stmt
|
||||
)
|
||||
)
|
||||
)
|
||||
impl = tmpl % {
|
||||
"name": deref_name,
|
||||
"index": arg["index"] - 1,
|
||||
"type": arg["non_optional_type"].replace("::Value", ""),
|
||||
}
|
||||
if is_optional_non_naked_ptr:
|
||||
impl = templates.constructor_stmt_optional % {
|
||||
"name": arg_name,
|
||||
"index": arg["index"] - 1,
|
||||
"stmt": impl,
|
||||
}
|
||||
constructor_implementations.append(impl)
|
||||
|
||||
def get_attribute_index(entity, attr_name):
|
||||
related_entity = mapping.schema.entities[entity]
|
||||
return [
|
||||
a["name"].lower() for a in mapping.get_assignable_arguments(related_entity, include_derived=True)
|
||||
].index(attr_name.lower())
|
||||
|
||||
inverse = [
|
||||
templates.const_function
|
||||
% {
|
||||
"class_name": name,
|
||||
"schema_name": schema_name,
|
||||
"schema_name_upper": schema_name_upper,
|
||||
"name": i.name,
|
||||
"arguments": "",
|
||||
"return_type": "::%s::%s::list::ptr" % (schema_name, i.entity),
|
||||
"body": templates.get_inverse
|
||||
% {
|
||||
"type": i.entity,
|
||||
"type_index": self.names.index(i.entity),
|
||||
"index": get_attribute_index(i.entity, i.attribute),
|
||||
"schema_name": schema_name,
|
||||
"schema_name_upper": schema_name_upper,
|
||||
},
|
||||
}
|
||||
for i in type.inverse
|
||||
]
|
||||
|
||||
superclass = (
|
||||
"%s(std::move(e))" % type.supertypes[0]
|
||||
if len(type.supertypes) == 1
|
||||
else "IfcUtil::IfcBaseEntity(std::move(e))"
|
||||
)
|
||||
|
||||
superclass_num_attrs = (
|
||||
"%s(IfcEntityInstanceData(in_memory_attribute_storage(%%d)))" % type.supertypes[0]
|
||||
if len(type.supertypes) == 1
|
||||
else "IfcUtil::IfcBaseEntity(IfcEntityInstanceData(in_memory_attribute_storage(%d)))"
|
||||
) % len(constructor_arguments)
|
||||
|
||||
write(
|
||||
templates.entity_implementation,
|
||||
name=name,
|
||||
parent_type_test=parent_type_test,
|
||||
constructor_arguments=constructor_arguments_str,
|
||||
constructor_implementation=cat(constructor_implementations),
|
||||
attributes=nl(catnl(attributes)),
|
||||
inverse=nl(catnl(inverse)),
|
||||
superclass=superclass,
|
||||
superclass_num_attrs=superclass_num_attrs,
|
||||
schema_name=schema_name,
|
||||
schema_name_upper=schema_name_upper,
|
||||
index_in_schema=self.names.index(str(name)),
|
||||
)
|
||||
|
||||
selectable_simple_types = sorted(
|
||||
set(sum([b.values for a, b in mapping.schema.selects.items()], []))
|
||||
& set(map(str, mapping.schema.types.keys()))
|
||||
)
|
||||
schema_entity_statements += [
|
||||
templates.schema_entity_stmt % locals() for name, type in mapping.schema.simpletypes.items()
|
||||
]
|
||||
schema_entity_statements += [
|
||||
templates.schema_entity_stmt % locals() for name, type in mapping.schema.enumerations.items()
|
||||
]
|
||||
schema_entity_statements += [
|
||||
templates.schema_entity_stmt % locals() for name, type in mapping.schema.entities.items()
|
||||
]
|
||||
|
||||
enumerable_types = sorted(
|
||||
set(
|
||||
[name for name, type in mapping.schema.types.items()]
|
||||
+ [name for name, type in mapping.schema.entities.items()]
|
||||
)
|
||||
)
|
||||
max_len = max(map(len, enumerable_types))
|
||||
type_name_strings = catc(map(stringify, enumerable_types))
|
||||
string_map_statements = [
|
||||
templates.string_map_statement
|
||||
% {"uppercase_name": name.upper(), "name": name, "padding": " " * (max_len - len(name))}
|
||||
for name in enumerable_types
|
||||
]
|
||||
|
||||
enumeration_index_by_str = OrderedCaseInsensitiveDict((j, i) for i, j in enumerate(enumerable_types))
|
||||
|
||||
def get_parent_id(s):
|
||||
e = mapping.schema.entities.get(s)
|
||||
if e and e.supertypes:
|
||||
return enumeration_index_by_str[e.supertypes[0]]
|
||||
else:
|
||||
return -1
|
||||
|
||||
parent_type_statements = ",".join(map(str, map(get_parent_id, enumerable_types)))
|
||||
|
||||
max_id = len(enumerable_types)
|
||||
|
||||
simple_type_statements = cator("v == Type::%s" % name for name in selectable_simple_types)
|
||||
|
||||
simple_type_impl = []
|
||||
for class_name, type in mapping.schema.simpletypes.items():
|
||||
type_str = mapping.make_type_string(mapping.flatten_type_string(type))
|
||||
attr_type = mapping.make_argument_type(type)
|
||||
superclass = mapping.simple_type_parent(class_name) or "IfcUtil::IfcBaseType"
|
||||
|
||||
simpletype_impl_is = (
|
||||
templates.simpletype_impl_is_with_supertype
|
||||
if superclass
|
||||
else templates.simpletype_impl_is_without_supertype
|
||||
)
|
||||
|
||||
constructor = templates.constructor_single_initlist # if superclass else templates.constructor
|
||||
|
||||
simpletype_impl_cast = (
|
||||
templates.simpletype_impl_cast_templated
|
||||
if mapping.is_templated_list(type)
|
||||
else templates.simpletype_impl_cast
|
||||
)
|
||||
|
||||
simpletype_impl_constructor = (
|
||||
templates.simpletype_impl_constructor_templated
|
||||
if mapping.is_templated_list(type)
|
||||
else templates.simpletype_impl_constructor
|
||||
)
|
||||
|
||||
def compose(params, schema_name=schema_name, schema_name_upper=schema_name_upper):
|
||||
class_name, attr_type, superclass, superclass_init, name, tmpl, return_type, args, body = params
|
||||
index_in_schema = self.names.index(str(class_name))
|
||||
underlying_type = mapping.list_instance_type(type)
|
||||
arguments = ",".join(args)
|
||||
body = body % locals()
|
||||
return tmpl % locals()
|
||||
|
||||
simple_type_impl.append(templates.simpletype_impl_comment % {"name": class_name})
|
||||
simple_type_impl.extend(
|
||||
map(
|
||||
compose,
|
||||
map(
|
||||
lambda x: (class_name, attr_type, superclass) + x,
|
||||
(
|
||||
(
|
||||
"",
|
||||
"Class",
|
||||
templates.function,
|
||||
"const IfcParse::type_declaration&",
|
||||
(),
|
||||
templates.simpletype_impl_class,
|
||||
),
|
||||
(
|
||||
"",
|
||||
"declaration",
|
||||
templates.const_function,
|
||||
"const IfcParse::type_declaration&",
|
||||
(),
|
||||
templates.simpletype_impl_declaration,
|
||||
),
|
||||
(
|
||||
"std::move(e)",
|
||||
"",
|
||||
constructor,
|
||||
"",
|
||||
("IfcEntityInstanceData&& e",),
|
||||
"",
|
||||
),
|
||||
(
|
||||
(
|
||||
"",
|
||||
"",
|
||||
constructor,
|
||||
"",
|
||||
("%s v" % type_str,),
|
||||
(
|
||||
"set_attribute_value(0, v%s);"
|
||||
% ("->generalize()" if mapping.is_templated_list(type) else "")
|
||||
),
|
||||
)
|
||||
if mapping.simple_type_parent(class_name) is None
|
||||
else ("v", "", constructor, "", ("%s v" % type_str,), "")
|
||||
),
|
||||
("", "", templates.cast_function, type_str, (), simpletype_impl_cast),
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
simple_type_impl.append("")
|
||||
|
||||
"""
|
||||
external_definitions = (
|
||||
[("extern entity* %s_%%s_type;" % schema_name_upper) % n for n in mapping.schema.entities.keys()]
|
||||
+ [
|
||||
("extern type_declaration* %s_%%s_type;" % schema_name_upper) % n
|
||||
for n in mapping.schema.simpletypes.keys()
|
||||
]
|
||||
+ [
|
||||
("extern enumeration_type* %s_%%s_type;" % schema_name_upper) % n
|
||||
for n in mapping.schema.enumerations.keys()
|
||||
]
|
||||
+ [
|
||||
("extern select_type* %s_%%s_type;" % schema_name_upper) % n
|
||||
for n in mapping.schema.selects.keys()
|
||||
]
|
||||
)
|
||||
"""
|
||||
external_definitions = ["extern declaration* %s_types[%d];" % (schema_name_upper, len(self.names))]
|
||||
|
||||
self.str = templates.implementation % {
|
||||
"schema_name_upper": schema_name_upper,
|
||||
"schema_name": schema_name,
|
||||
"max_id": max_id,
|
||||
"enumeration_functions": cat(enumeration_functions),
|
||||
"schema_entity_statements": catnl(schema_entity_statements),
|
||||
"type_name_strings": type_name_strings,
|
||||
"string_map_statements": catnl(string_map_statements),
|
||||
"simple_type_statement": simple_type_statements,
|
||||
"parent_type_statements": parent_type_statements,
|
||||
"entity_implementations": catnl(entity_implementations),
|
||||
"simple_type_impl": catnl(simple_type_impl),
|
||||
"external_definitions": catnl(external_definitions),
|
||||
}
|
||||
|
||||
self.schema_name = mapping.schema.name.capitalize()
|
||||
|
||||
self.file_name = "%s.cpp" % self.schema_name
|
||||
|
||||
def __repr__(self):
|
||||
return self.str
|
||||
|
||||
|
||||
Generator = Implementation
|
||||
Reference in New Issue
Block a user