Skip to content

Commit e4e8f05

Browse files
committed
Update IfcExpressParser to generate writable schema
1 parent b4e4202 commit e4e8f05

1 file changed

Lines changed: 63 additions & 6 deletions

File tree

src/ifcexpressparser/IfcExpressParser.py

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ def get():
9999
selectable_simple_types = set()
100100
argument_count = {}
101101
parent_relations = {}
102+
argument_names_and_types = {}
103+
entity_map = {}
102104

103105
#
104106
# 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
@@ -111,6 +113,15 @@ def argument_start(c):
111113
i += argument_count[c] if c in argument_count else 0
112114
if not (c in parent_relations): break
113115
return i
116+
117+
def parent_arguments(c):
118+
if c not in parent_relations: return []
119+
l = []
120+
while True:
121+
c = parent_relations[c]
122+
i += argument_count[c] if c in argument_count else 0
123+
if not (c in parent_relations): break
124+
return []
114125

115126
#
116127
# Several classes to generate code from Express types and entities
@@ -127,6 +138,7 @@ def __str__(self):
127138
return "SHARED_PTR< IfcTemplatedEntityList<IfcAbstractSelect> >"
128139
else:
129140
return "std::vector<%(type)s> /*[%(lower)s:%(upper)s]*/"%self.__dict__
141+
def is_shared_ptr(self): return self.type in entity_names or self.type in selections
130142
def type_enum(self):
131143
if self.type in simple_types:
132144
t = simple_types[self.type].type_enum()
@@ -199,12 +211,12 @@ def __init__(self,l):
199211
def __str__(self):
200212
global generator_mode
201213
if generator_mode == 'HEADER' and isinstance(self.type,EnumType):
202-
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__
214+
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__
203215
elif generator_mode == 'HEADER':
204216
return "%stypedef %s %s;"%(self.comment,self.type,self.name)
205217
elif generator_mode == 'SOURCE' and isinstance(self.type,EnumType):
206218
generator_mode = 'SOURCE_TO'
207-
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__
219+
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__
208220
generator_mode = 'SOURCE_FROM'
209221
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__
210222
generator_mode = 'SOURCE'
@@ -214,6 +226,12 @@ def type_enum(self):
214226
class Argument(object):
215227
def __init__(self,l):
216228
self.name, self.optional, self.type = l
229+
def is_enum(self): return str(self.type) in enumerations
230+
def type_str(self):
231+
if str(self.type) in entity_names:
232+
return "%(type)s*"%self.__dict__
233+
else:
234+
return "%(type)s::%(type)s"%self.__dict__ if self.is_enum() else self.type
217235
class ArgumentList:
218236
def __init__(self,l):
219237
self.l = [Argument(a) for a in l]
@@ -224,11 +242,12 @@ def __str__(self):
224242
argv = self.argstart
225243
for a in self.l:
226244
class_name = indent = comment = optional_comment = ""
245+
is_array = isinstance(a.type,ArrayType) and a.type.is_shared_ptr()
227246
return_type = str(a.type)
228247
if generator_mode == 'SOURCE':
229248
class_name = "%(class_name)s::"
230249
if isinstance(a.type,BinaryType) or (isinstance(a.type,ArrayType) and isinstance(a.type.type,BinaryType)):
231-
function_body = " { throw; /* Not implemented argument 7 */ }"
250+
function_body = " { throw; /* Not implemented argument*/ }"
232251
elif isinstance(a.type,ArrayType) and str(a.type.type) in entity_names:
233252
function_body = " { RETURN_AS_LIST(%s,%d) }"%(a.type.type,argv)
234253
elif isinstance(a.type,ArrayType) and str(a.type.type) in selections:
@@ -240,9 +259,15 @@ def __str__(self):
240259
else:
241260
function_body = " { return *entity->getArgument(%d); }"%argv
242261
function_body2 = " { return !entity->getArgument(%d)->isNull(); }"%argv
262+
if isinstance(a.type,BinaryType) or (isinstance(a.type,ArrayType) and isinstance(a.type.type,BinaryType)):
263+
function_body3 = " { if ( ! entity->isWritable() ) { throw; } }"
264+
elif return_type in enumerations:
265+
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)
266+
else:
267+
function_body3 = " { if ( ! entity->isWritable() ) { entity = new IfcWritableEntity(entity); } ((IfcWritableEntity*)entity)->setArgument(%d,v%s); }"%(argv,"->generalize()" if is_array else "")
243268
else:
244269
indent = " "
245-
function_body = function_body2 = ";"
270+
function_body = function_body2 = function_body3 = ";"
246271
comment = IfcDocumentation.description((self.class_name,a.name))
247272
comment = comment+"\n" if comment else ''
248273
comment = comment.replace("///","%s///"%indent)
@@ -253,6 +278,7 @@ def __str__(self):
253278
elif ( str(a.type) in entity_names ):
254279
return_type = "%(type)s*"%a.__dict__
255280
s += "\n%s%s%s %s%s()%s"%(comment,indent,return_type,class_name,a.name,function_body)
281+
s += "\n%svoid %sset%s(%s v)%s"%(indent,class_name,a.name,return_type,function_body3)
256282
argv += 1
257283

258284
if generator_mode == 'HEADER':
@@ -304,8 +330,27 @@ def __init__(self,l):
304330
entity_names.add(self.class_name)
305331
parent_relations[self.class_name] = self.parent_class
306332
argument_count[self.class_name] = len(self.arguments)
333+
entity_map[self.class_name] = self
334+
def get_constructor_args(self):
335+
s = entity_map[self.parent_class].get_constructor_args() if self.parent_class else []
336+
i = len(s) + 1
337+
s += ["%s v%d_%s"%(a.type_str(),b+i,a.name) for a,b in zip(self.arguments.l,range(len(self.arguments)))]
338+
return s
339+
def get_constructor_implementation(self):
340+
s = entity_map[self.parent_class].get_constructor_implementation() if self.parent_class else []
341+
i = len(s) + 1
342+
b = 0
343+
for a in self.arguments.l:
344+
generalize = "->generalize()" if (isinstance(a.type,ArrayType) and a.type.is_shared_ptr()) else ""
345+
if isinstance(a.type,BinaryType) or (isinstance(a.type,ArrayType) and isinstance(a.type.type,BinaryType)):
346+
continue
347+
s.append("e->setArgument(%d,v%d_%s%s)"%(b+i-1,b+i,a.name,generalize))
348+
b += 1
349+
return s#"; ".join(s)
307350
def __str__(self):
308-
if generator_mode == 'HEADER':
351+
self.constructor_args_list = self.get_constructor_args()
352+
self.constructor_args = ", ".join(self.constructor_args_list)
353+
if generator_mode == 'HEADER':
309354
comment = IfcDocumentation.description(self.class_name)
310355
comment = comment+"\n" if comment else ''
311356
return "%sclass %s : public %s {\npublic:%s%s%s\n};" % (comment,self.class_name,
@@ -316,18 +361,22 @@ def __str__(self):
316361
"\n Type::Enum type() const;"+
317362
"\n static Type::Enum Class();"+
318363
"\n %(class_name)s (IfcAbstractEntityPtr e = IfcAbstractEntityPtr());"+
364+
("\n %(class_name)s (%(constructor_args)s);" if len(self.constructor_args_list) else "")+
319365
"\n typedef %(class_name)s* ptr;"+
320366
"\n typedef SHARED_PTR< IfcTemplatedEntityList<%(class_name)s> > list;"+
321367
"\n typedef IfcTemplatedEntityList<%(class_name)s>::it it;")%self.__dict__
322368
)
323369
elif generator_mode == 'SOURCE':
324370
self.arguments.argstart = argument_start(self.class_name)
371+
self.constructor_implementation = "; ".join(self.get_constructor_implementation())
325372
return (("\n// Function implementations for %(class_name)s"+str(self.arguments)+str(self.inverse)+
326373
("\nbool %(class_name)s::is(Type::Enum v) const { return v == Type::%(class_name)s; }" if self.parent_class is None else
327374
"\nbool %(class_name)s::is(Type::Enum v) const { return v == Type::%(class_name)s || %(parent_class)s::is(v); }")+
328375
"\nType::Enum %(class_name)s::type() const { return Type::%(class_name)s; }"+
329376
"\nType::Enum %(class_name)s::Class() { return Type::%(class_name)s; }"+
330-
"\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__
377+
"\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; }"+
378+
("\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 "")
379+
)%self.__dict__)%self.__dict__
331380

332381

333382
from funcparserlib.parser import a, skip, many, maybe, some
@@ -462,6 +511,7 @@ def __str__(self):
462511
Enum Parent(Enum v);
463512
Enum FromString(const std::string& s);
464513
std::string ToString(Enum v);
514+
bool IsSimple(Enum v);
465515
}
466516
467517
}
@@ -505,9 +555,12 @@ def __str__(self):
505555

506556
print >>cpp_file, """#include "%(schema)s.h"
507557
#include "IfcException.h"
558+
#include "IfcWrite.h"
559+
#include "IfcWritableEntity.h"
508560
509561
using namespace %(schema)s;
510562
using namespace IfcParse;
563+
using namespace IfcWrite;
511564
512565
IfcSchemaEntity %(schema)s::SchemaEntity(IfcAbstractEntityPtr e) {
513566
switch(e->type()){"""%{'schema':schema_version}
@@ -552,6 +605,10 @@ def __str__(self):
552605
print >>cpp_file, " return (Enum)-1;"
553606
print >>cpp_file, "}"
554607

608+
print >>cpp_file, "bool Type::IsSimple(Enum v){"
609+
print >>cpp_file, " return v == Type::%s;"%" || v == Type::".join(simple_enumerations)
610+
print >>cpp_file, "}"
611+
555612
for t in [T for T in types if isinstance(T.type,EnumType)]:
556613
print >>cpp_file, t
557614
for e in entities: print >>cpp_file, e,

0 commit comments

Comments
 (0)