mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-19 06:39:13 +00:00
Update IfcExpressParser to generate writable schema
This commit is contained in:
@@ -99,6 +99,8 @@ simple_types = {}
|
|||||||
selectable_simple_types = set()
|
selectable_simple_types = set()
|
||||||
argument_count = {}
|
argument_count = {}
|
||||||
parent_relations = {}
|
parent_relations = {}
|
||||||
|
argument_names_and_types = {}
|
||||||
|
entity_map = {}
|
||||||
|
|
||||||
#
|
#
|
||||||
# Since inherited arguments of Express entities are placed in sequence before the non-inherited once, we need to keep track of how many inherited arguments exist
|
# Since inherited arguments of Express entities are placed in sequence before the non-inherited once, we need to keep track of how many inherited arguments exist
|
||||||
@@ -112,6 +114,15 @@ def argument_start(c):
|
|||||||
if not (c in parent_relations): break
|
if not (c in parent_relations): break
|
||||||
return i
|
return i
|
||||||
|
|
||||||
|
def parent_arguments(c):
|
||||||
|
if c not in parent_relations: return []
|
||||||
|
l = []
|
||||||
|
while True:
|
||||||
|
c = parent_relations[c]
|
||||||
|
i += argument_count[c] if c in argument_count else 0
|
||||||
|
if not (c in parent_relations): break
|
||||||
|
return []
|
||||||
|
|
||||||
#
|
#
|
||||||
# Several classes to generate code from Express types and entities
|
# Several classes to generate code from Express types and entities
|
||||||
#
|
#
|
||||||
@@ -127,6 +138,7 @@ class ArrayType:
|
|||||||
return "SHARED_PTR< IfcTemplatedEntityList<IfcAbstractSelect> >"
|
return "SHARED_PTR< IfcTemplatedEntityList<IfcAbstractSelect> >"
|
||||||
else:
|
else:
|
||||||
return "std::vector<%(type)s> /*[%(lower)s:%(upper)s]*/"%self.__dict__
|
return "std::vector<%(type)s> /*[%(lower)s:%(upper)s]*/"%self.__dict__
|
||||||
|
def is_shared_ptr(self): return self.type in entity_names or self.type in selections
|
||||||
def type_enum(self):
|
def type_enum(self):
|
||||||
if self.type in simple_types:
|
if self.type in simple_types:
|
||||||
t = simple_types[self.type].type_enum()
|
t = simple_types[self.type].type_enum()
|
||||||
@@ -199,12 +211,12 @@ class Typedef:
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
global generator_mode
|
global generator_mode
|
||||||
if generator_mode == 'HEADER' and isinstance(self.type,EnumType):
|
if generator_mode == 'HEADER' and isinstance(self.type,EnumType):
|
||||||
return ("namespace %(name)s {\n%(comment)stypedef %(type)s %(name)s;\nstd::string ToString(%(name)s v);\n%(name)s FromString(const std::string& s);\n}"%self.__dict__)%self.__dict__
|
return ("namespace %(name)s {\n%(comment)stypedef %(type)s %(name)s;\nconst char* ToString(%(name)s v);\n%(name)s FromString(const std::string& s);\n}"%self.__dict__)%self.__dict__
|
||||||
elif generator_mode == 'HEADER':
|
elif generator_mode == 'HEADER':
|
||||||
return "%stypedef %s %s;"%(self.comment,self.type,self.name)
|
return "%stypedef %s %s;"%(self.comment,self.type,self.name)
|
||||||
elif generator_mode == 'SOURCE' and isinstance(self.type,EnumType):
|
elif generator_mode == 'SOURCE' and isinstance(self.type,EnumType):
|
||||||
generator_mode = 'SOURCE_TO'
|
generator_mode = 'SOURCE_TO'
|
||||||
s = "std::string %(name)s::ToString(%(name)s v) {\n if ( v < 0 || v >= %(len)d ) throw IfcException(\"Unable to find find keyword in schema\");\n const char* names[] = %(type)s;\n return names[v];\n}\n"%self.__dict__
|
s = "const char* %(name)s::ToString(%(name)s v) {\n if ( v < 0 || v >= %(len)d ) throw IfcException(\"Unable to find find keyword in schema\");\n const char* names[] = %(type)s;\n return names[v];\n}\n"%self.__dict__
|
||||||
generator_mode = 'SOURCE_FROM'
|
generator_mode = 'SOURCE_FROM'
|
||||||
s += ("%(name)s::%(name)s %(name)s::FromString(const std::string& s) {\n%(type)s throw IfcException(\"Unable to find find keyword in schema\");\n}"%self.__dict__)%self.__dict__
|
s += ("%(name)s::%(name)s %(name)s::FromString(const std::string& s) {\n%(type)s throw IfcException(\"Unable to find find keyword in schema\");\n}"%self.__dict__)%self.__dict__
|
||||||
generator_mode = 'SOURCE'
|
generator_mode = 'SOURCE'
|
||||||
@@ -214,6 +226,12 @@ class Typedef:
|
|||||||
class Argument(object):
|
class Argument(object):
|
||||||
def __init__(self,l):
|
def __init__(self,l):
|
||||||
self.name, self.optional, self.type = l
|
self.name, self.optional, self.type = l
|
||||||
|
def is_enum(self): return str(self.type) in enumerations
|
||||||
|
def type_str(self):
|
||||||
|
if str(self.type) in entity_names:
|
||||||
|
return "%(type)s*"%self.__dict__
|
||||||
|
else:
|
||||||
|
return "%(type)s::%(type)s"%self.__dict__ if self.is_enum() else self.type
|
||||||
class ArgumentList:
|
class ArgumentList:
|
||||||
def __init__(self,l):
|
def __init__(self,l):
|
||||||
self.l = [Argument(a) for a in l]
|
self.l = [Argument(a) for a in l]
|
||||||
@@ -224,11 +242,12 @@ class ArgumentList:
|
|||||||
argv = self.argstart
|
argv = self.argstart
|
||||||
for a in self.l:
|
for a in self.l:
|
||||||
class_name = indent = comment = optional_comment = ""
|
class_name = indent = comment = optional_comment = ""
|
||||||
|
is_array = isinstance(a.type,ArrayType) and a.type.is_shared_ptr()
|
||||||
return_type = str(a.type)
|
return_type = str(a.type)
|
||||||
if generator_mode == 'SOURCE':
|
if generator_mode == 'SOURCE':
|
||||||
class_name = "%(class_name)s::"
|
class_name = "%(class_name)s::"
|
||||||
if isinstance(a.type,BinaryType) or (isinstance(a.type,ArrayType) and isinstance(a.type.type,BinaryType)):
|
if isinstance(a.type,BinaryType) or (isinstance(a.type,ArrayType) and isinstance(a.type.type,BinaryType)):
|
||||||
function_body = " { throw; /* Not implemented argument 7 */ }"
|
function_body = " { throw; /* Not implemented argument*/ }"
|
||||||
elif isinstance(a.type,ArrayType) and str(a.type.type) in entity_names:
|
elif isinstance(a.type,ArrayType) and str(a.type.type) in entity_names:
|
||||||
function_body = " { RETURN_AS_LIST(%s,%d) }"%(a.type.type,argv)
|
function_body = " { RETURN_AS_LIST(%s,%d) }"%(a.type.type,argv)
|
||||||
elif isinstance(a.type,ArrayType) and str(a.type.type) in selections:
|
elif isinstance(a.type,ArrayType) and str(a.type.type) in selections:
|
||||||
@@ -240,9 +259,15 @@ class ArgumentList:
|
|||||||
else:
|
else:
|
||||||
function_body = " { return *entity->getArgument(%d); }"%argv
|
function_body = " { return *entity->getArgument(%d); }"%argv
|
||||||
function_body2 = " { return !entity->getArgument(%d)->isNull(); }"%argv
|
function_body2 = " { return !entity->getArgument(%d)->isNull(); }"%argv
|
||||||
|
if isinstance(a.type,BinaryType) or (isinstance(a.type,ArrayType) and isinstance(a.type.type,BinaryType)):
|
||||||
|
function_body3 = " { if ( ! entity->isWritable() ) { throw; } }"
|
||||||
|
elif return_type in enumerations:
|
||||||
|
function_body3 = " { if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%d,v%s,%s::ToString(v)); }"%(argv,"->generalize()" if is_array else "",return_type)
|
||||||
|
else:
|
||||||
|
function_body3 = " { if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%d,v%s); }"%(argv,"->generalize()" if is_array else "")
|
||||||
else:
|
else:
|
||||||
indent = " "
|
indent = " "
|
||||||
function_body = function_body2 = ";"
|
function_body = function_body2 = function_body3 = ";"
|
||||||
comment = IfcDocumentation.description((self.class_name,a.name))
|
comment = IfcDocumentation.description((self.class_name,a.name))
|
||||||
comment = comment+"\n" if comment else ''
|
comment = comment+"\n" if comment else ''
|
||||||
comment = comment.replace("///","%s///"%indent)
|
comment = comment.replace("///","%s///"%indent)
|
||||||
@@ -253,6 +278,7 @@ class ArgumentList:
|
|||||||
elif ( str(a.type) in entity_names ):
|
elif ( str(a.type) in entity_names ):
|
||||||
return_type = "%(type)s*"%a.__dict__
|
return_type = "%(type)s*"%a.__dict__
|
||||||
s += "\n%s%s%s %s%s()%s"%(comment,indent,return_type,class_name,a.name,function_body)
|
s += "\n%s%s%s %s%s()%s"%(comment,indent,return_type,class_name,a.name,function_body)
|
||||||
|
s += "\n%svoid %sset%s(%s v)%s"%(indent,class_name,a.name,return_type,function_body3)
|
||||||
argv += 1
|
argv += 1
|
||||||
|
|
||||||
if generator_mode == 'HEADER':
|
if generator_mode == 'HEADER':
|
||||||
@@ -304,7 +330,26 @@ class Classdef:
|
|||||||
entity_names.add(self.class_name)
|
entity_names.add(self.class_name)
|
||||||
parent_relations[self.class_name] = self.parent_class
|
parent_relations[self.class_name] = self.parent_class
|
||||||
argument_count[self.class_name] = len(self.arguments)
|
argument_count[self.class_name] = len(self.arguments)
|
||||||
|
entity_map[self.class_name] = self
|
||||||
|
def get_constructor_args(self):
|
||||||
|
s = entity_map[self.parent_class].get_constructor_args() if self.parent_class else []
|
||||||
|
i = len(s) + 1
|
||||||
|
s += ["%s v%d_%s"%(a.type_str(),b+i,a.name) for a,b in zip(self.arguments.l,range(len(self.arguments)))]
|
||||||
|
return s
|
||||||
|
def get_constructor_implementation(self):
|
||||||
|
s = entity_map[self.parent_class].get_constructor_implementation() if self.parent_class else []
|
||||||
|
i = len(s) + 1
|
||||||
|
b = 0
|
||||||
|
for a in self.arguments.l:
|
||||||
|
generalize = "->generalize()" if (isinstance(a.type,ArrayType) and a.type.is_shared_ptr()) else ""
|
||||||
|
if isinstance(a.type,BinaryType) or (isinstance(a.type,ArrayType) and isinstance(a.type.type,BinaryType)):
|
||||||
|
continue
|
||||||
|
s.append("e->setArgument(%d,v%d_%s%s)"%(b+i-1,b+i,a.name,generalize))
|
||||||
|
b += 1
|
||||||
|
return s#"; ".join(s)
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
self.constructor_args_list = self.get_constructor_args()
|
||||||
|
self.constructor_args = ", ".join(self.constructor_args_list)
|
||||||
if generator_mode == 'HEADER':
|
if generator_mode == 'HEADER':
|
||||||
comment = IfcDocumentation.description(self.class_name)
|
comment = IfcDocumentation.description(self.class_name)
|
||||||
comment = comment+"\n" if comment else ''
|
comment = comment+"\n" if comment else ''
|
||||||
@@ -316,18 +361,22 @@ class Classdef:
|
|||||||
"\n Type::Enum type() const;"+
|
"\n Type::Enum type() const;"+
|
||||||
"\n static Type::Enum Class();"+
|
"\n static Type::Enum Class();"+
|
||||||
"\n %(class_name)s (IfcAbstractEntityPtr e = IfcAbstractEntityPtr());"+
|
"\n %(class_name)s (IfcAbstractEntityPtr e = IfcAbstractEntityPtr());"+
|
||||||
|
("\n %(class_name)s (%(constructor_args)s);" if len(self.constructor_args_list) else "")+
|
||||||
"\n typedef %(class_name)s* ptr;"+
|
"\n typedef %(class_name)s* ptr;"+
|
||||||
"\n typedef SHARED_PTR< IfcTemplatedEntityList<%(class_name)s> > list;"+
|
"\n typedef SHARED_PTR< IfcTemplatedEntityList<%(class_name)s> > list;"+
|
||||||
"\n typedef IfcTemplatedEntityList<%(class_name)s>::it it;")%self.__dict__
|
"\n typedef IfcTemplatedEntityList<%(class_name)s>::it it;")%self.__dict__
|
||||||
)
|
)
|
||||||
elif generator_mode == 'SOURCE':
|
elif generator_mode == 'SOURCE':
|
||||||
self.arguments.argstart = argument_start(self.class_name)
|
self.arguments.argstart = argument_start(self.class_name)
|
||||||
|
self.constructor_implementation = "; ".join(self.get_constructor_implementation())
|
||||||
return (("\n// Function implementations for %(class_name)s"+str(self.arguments)+str(self.inverse)+
|
return (("\n// Function implementations for %(class_name)s"+str(self.arguments)+str(self.inverse)+
|
||||||
("\nbool %(class_name)s::is(Type::Enum v) const { return v == Type::%(class_name)s; }" if self.parent_class is None else
|
("\nbool %(class_name)s::is(Type::Enum v) const { return v == Type::%(class_name)s; }" if self.parent_class is None else
|
||||||
"\nbool %(class_name)s::is(Type::Enum v) const { return v == Type::%(class_name)s || %(parent_class)s::is(v); }")+
|
"\nbool %(class_name)s::is(Type::Enum v) const { return v == Type::%(class_name)s || %(parent_class)s::is(v); }")+
|
||||||
"\nType::Enum %(class_name)s::type() const { return Type::%(class_name)s; }"+
|
"\nType::Enum %(class_name)s::type() const { return Type::%(class_name)s; }"+
|
||||||
"\nType::Enum %(class_name)s::Class() { return Type::%(class_name)s; }"+
|
"\nType::Enum %(class_name)s::Class() { return Type::%(class_name)s; }"+
|
||||||
"\n%(class_name)s::%(class_name)s(IfcAbstractEntityPtr e) { if (!is(Type::%(class_name)s)) throw IfcException(\"Unable to find find keyword in schema\"); entity = e; }")%self.__dict__)%self.__dict__
|
"\n%(class_name)s::%(class_name)s(IfcAbstractEntityPtr e) { if (!is(Type::%(class_name)s)) throw IfcException(\"Unable to find find keyword in schema\"); entity = e; }"+
|
||||||
|
("\n%(class_name)s::%(class_name)s(%(constructor_args)s) { IfcWritableEntity* e = new IfcWritableEntity(Class()); %(constructor_implementation)s; entity = e; }" if len(self.constructor_args_list) else "")
|
||||||
|
)%self.__dict__)%self.__dict__
|
||||||
|
|
||||||
|
|
||||||
from funcparserlib.parser import a, skip, many, maybe, some
|
from funcparserlib.parser import a, skip, many, maybe, some
|
||||||
@@ -462,6 +511,7 @@ namespace Type {
|
|||||||
Enum Parent(Enum v);
|
Enum Parent(Enum v);
|
||||||
Enum FromString(const std::string& s);
|
Enum FromString(const std::string& s);
|
||||||
std::string ToString(Enum v);
|
std::string ToString(Enum v);
|
||||||
|
bool IsSimple(Enum v);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -505,9 +555,12 @@ generator_mode = 'SOURCE'
|
|||||||
|
|
||||||
print >>cpp_file, """#include "%(schema)s.h"
|
print >>cpp_file, """#include "%(schema)s.h"
|
||||||
#include "IfcException.h"
|
#include "IfcException.h"
|
||||||
|
#include "IfcWrite.h"
|
||||||
|
#include "IfcWritableEntity.h"
|
||||||
|
|
||||||
using namespace %(schema)s;
|
using namespace %(schema)s;
|
||||||
using namespace IfcParse;
|
using namespace IfcParse;
|
||||||
|
using namespace IfcWrite;
|
||||||
|
|
||||||
IfcSchemaEntity %(schema)s::SchemaEntity(IfcAbstractEntityPtr e) {
|
IfcSchemaEntity %(schema)s::SchemaEntity(IfcAbstractEntityPtr e) {
|
||||||
switch(e->type()){"""%{'schema':schema_version}
|
switch(e->type()){"""%{'schema':schema_version}
|
||||||
@@ -552,6 +605,10 @@ for e in entity_enumerations:
|
|||||||
print >>cpp_file, " return (Enum)-1;"
|
print >>cpp_file, " return (Enum)-1;"
|
||||||
print >>cpp_file, "}"
|
print >>cpp_file, "}"
|
||||||
|
|
||||||
|
print >>cpp_file, "bool Type::IsSimple(Enum v){"
|
||||||
|
print >>cpp_file, " return v == Type::%s;"%" || v == Type::".join(simple_enumerations)
|
||||||
|
print >>cpp_file, "}"
|
||||||
|
|
||||||
for t in [T for T in types if isinstance(T.type,EnumType)]:
|
for t in [T for T in types if isinstance(T.type,EnumType)]:
|
||||||
print >>cpp_file, t
|
print >>cpp_file, t
|
||||||
for e in entities: print >>cpp_file, e,
|
for e in entities: print >>cpp_file, e,
|
||||||
|
|||||||
Reference in New Issue
Block a user