From 00be2f920b3ef8bee4ad5fabf8fe739aa2dab81d Mon Sep 17 00:00:00 2001 From: aramis_acg Date: Sun, 17 Jul 2011 01:14:13 +0000 Subject: [PATCH] - ff=unix for all Python scripts in ./scripts to avoid shebang trouble under *nix. git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@1048 67173fc5-114c-0410-ac8e-9d2fd5bffc1f --- scripts/BlenderImporter/genblenddna.py | 470 ++++++++++---------- scripts/IFCImporter/CppGenerator.py | 566 ++++++++++++------------- scripts/IFCImporter/ExpressReader.py | 240 +++++------ 3 files changed, 638 insertions(+), 638 deletions(-) diff --git a/scripts/BlenderImporter/genblenddna.py b/scripts/BlenderImporter/genblenddna.py index df276f002..d0c622f31 100644 --- a/scripts/BlenderImporter/genblenddna.py +++ b/scripts/BlenderImporter/genblenddna.py @@ -1,235 +1,235 @@ -#!/usr/bin/env python3 -# -*- Coding: UTF-8 -*- - -# --------------------------------------------------------------------------- -# Open Asset Import Library (ASSIMP) -# --------------------------------------------------------------------------- -# -# Copyright (c) 2006-2010, ASSIMP Development Team -# -# All rights reserved. -# -# Redistribution and use of this software in source and binary forms, -# with or without modification, are permitted provided that the following -# conditions are met: -# -# * Redistributions of source code must retain the above -# copyright notice, this list of conditions and the -# following disclaimer. -# -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the -# following disclaimer in the documentation and/or other -# materials provided with the distribution. -# -# * Neither the name of the ASSIMP team, nor the names of its -# contributors may be used to endorse or promote products -# derived from this software without specific prior -# written permission of the ASSIMP Development Team. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# --------------------------------------------------------------------------- - -"""Generate BlenderSceneGen.h and BlenderScene.cpp from the -data structures in BlenderScene.h to map from *any* DNA to -*our* DNA""" - -import sys -import os -import re - -inputfile = os.path.join("..","..","code","BlenderScene.h") -outputfile_gen = os.path.join("..","..","code","BlenderSceneGen.h") -outputfile_src = os.path.join("..","..","code","BlenderScene.cpp") - -template_gen = "BlenderSceneGen.h.template" -template_src = "BlenderScene.cpp.template" - - -Structure_Convert_decl = """ -template <> void Structure :: Convert<{a}> ( - {a}& dest, - const FileDatabase& db - ) const -""" - - -Structure_Convert_ptrdecl = """ - ReadFieldPtr<{policy}>({destcast}dest.{name_canonical},"{name_dna}",db);""" - -Structure_Convert_arraydecl = """ - ReadFieldArray<{policy}>({destcast}dest.{name_canonical},"{name_dna}",db);""" - -Structure_Convert_arraydecl2d = """ - ReadFieldArray2<{policy}>({destcast}dest.{name_canonical},"{name_dna}",db);""" - -Structure_Convert_normal = """ - ReadField<{policy}>({destcast}dest.{name_canonical},"{name_dna}",db);""" - - -DNA_RegisterConverters_decl = """ -void DNA::RegisterConverters() """ - -DNA_RegisterConverters_add = """ - converters["{a}"] = DNA::FactoryPair( &Structure::Allocate<{a}>, &Structure::Convert<{a}> );""" - - -map_policy = { - "" : "ErrorPolicy_Igno" - ,"IGNO" : "ErrorPolicy_Igno" - ,"WARN" : "ErrorPolicy_Warn" - ,"FAIL" : "ErrorPolicy_Fail" -} - -# -def main(): - - # ----------------------------------------------------------------------- - # Parse structure definitions from BlenderScene.h - input = open(inputfile,"rt").read() - - flags = re.ASCII|re.DOTALL|re.MULTILINE - #stripcoms = re.compile(r"/\*(.*?)*\/",flags) - getstruct = re.compile(r"struct\s+(\w+?)\s*(:\s*ElemBase)?\s*\{(.*?)^\}\s*;",flags) - getsmartx = re.compile(r"(std\s*::\s*)?(vector)\s*<\s*(boost\s*::\s*)?shared_(ptr)\s*<\s*(\w+)\s*>\s*>\s*",flags) - getsmartp = re.compile(r"(boost\s*::\s*)?shared_(ptr)\s*<\s*(\w+)\s*>\s*",flags) - getsmarta = re.compile(r"(std\s*::\s*)?(vector)\s*<\s*(\w+)\s*>\s*",flags) - getpolicy = re.compile(r"\s*(WARN|FAIL|IGNO)",flags) - stripenum = re.compile(r"enum\s+(\w+)\s*{.*?\}\s*;",flags) - - assert getsmartx and getsmartp and getsmarta and getpolicy and stripenum - - enums = set() - #re.sub(stripcoms," ",input) - #print(input) - - hits = {} - while 1: - match = re.search(getstruct,input) - if match is None: - break - - tmp = match.groups()[2] - while 1: - match2 = re.search(stripenum,tmp) - if match2 is None: - break - tmp = tmp[match2.end():] - enums.add(match2.groups()[0]) - - hits[match.groups()[0]] = list( - filter(lambda x:x[:2] != "//" and len(x), - map(str.strip, - re.sub(stripenum," ",match.groups()[2]).split(";") - ))) - - input = input[match.end():] - - [print ("Enum: "+e) for e in enums] - for k,v in hits.items(): - out = [] - for line in v: - - policy = "IGNO" - py = re.search(getpolicy,line) - if not py is None: - policy = py.groups()[0] - line = re.sub(getpolicy,"",line) - - ty = re.match(getsmartx,line) or re.match(getsmartp,line) or re.match(getsmarta,line) - if ty is None: - ty = line.split(None,1)[0] - else: - if ty.groups()[1] == "ptr": - ty = ty.groups()[2] + "*" - elif ty.groups()[1] == "vector": - ty = ty.groups()[-1] + ("*" if len(ty.groups()) == 3 else "**") - - #print(line) - sp = line.split(',') - out.append((ty,sp[0].split(None)[-1].strip(),policy)) - for m in sp[1:]: - out.append((ty,m.strip(),policy)) - - v[:] = out - print("Structure {0}".format(k)) - [print("\t"+"\t".join(elem)) for elem in out] - print("") - - - output = open(outputfile_gen,"wt") - templt = open(template_gen,"rt").read() - s = "" - - # ----------------------------------------------------------------------- - # Structure::Convert declarations for all supported structures - for k,v in hits.items(): - s += Structure_Convert_decl.format(a=k)+";\n"; - output.write(templt.replace("",s)) - - output = open(outputfile_src,"wt") - templt = open(template_src,"rt").read() - s = "" - - # ----------------------------------------------------------------------- - # Structure::Convert definitions for all supported structures - for k,v in hits.items(): - s += "//" + "-"*80 + Structure_Convert_decl.format(a=k)+ "{ \n"; - - for type, name, policy in v: - splits = name.split("[",1) - name_canonical = splits[0] - #array_part = "" if len(splits)==1 else "["+splits[1] - ptr_decl = "*"*type.count("*") - name_dna = ptr_decl+name_canonical #+array_part - - #required = "false" - policy = map_policy[policy] - destcast = "(int&)" if type in enums else "" - - # POINTER - if ptr_decl: - s += Structure_Convert_ptrdecl.format(**locals()) - # ARRAY MEMBER - elif name.count('[')==1: - s += Structure_Convert_arraydecl.format(**locals()) - elif name.count('[')==2: - s += Structure_Convert_arraydecl2d.format(**locals()) - # NORMAL MEMBER - else: - s += Structure_Convert_normal.format(**locals()) - - s += "\n\n\tdb.reader->IncPtr(size);\n}\n\n" - - - # ----------------------------------------------------------------------- - # DNA::RegisterConverters - collect all available converter functions - # in a std::map - #s += "#if 0\n" - s += "//" + "-"*80 + DNA_RegisterConverters_decl + "{\n" - for k,v in hits.items(): - s += DNA_RegisterConverters_add.format(a=k) - - s += "\n}\n" - #s += "#endif\n" - - output.write(templt.replace("",s)) - - -if __name__ == "__main__": - sys.exit(main()) - - - - - +#!/usr/bin/env python3 +# -*- Coding: UTF-8 -*- + +# --------------------------------------------------------------------------- +# Open Asset Import Library (ASSIMP) +# --------------------------------------------------------------------------- +# +# Copyright (c) 2006-2010, ASSIMP Development Team +# +# All rights reserved. +# +# Redistribution and use of this software in source and binary forms, +# with or without modification, are permitted provided that the following +# conditions are met: +# +# * Redistributions of source code must retain the above +# copyright notice, this list of conditions and the +# following disclaimer. +# +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the +# following disclaimer in the documentation and/or other +# materials provided with the distribution. +# +# * Neither the name of the ASSIMP team, nor the names of its +# contributors may be used to endorse or promote products +# derived from this software without specific prior +# written permission of the ASSIMP Development Team. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# --------------------------------------------------------------------------- + +"""Generate BlenderSceneGen.h and BlenderScene.cpp from the +data structures in BlenderScene.h to map from *any* DNA to +*our* DNA""" + +import sys +import os +import re + +inputfile = os.path.join("..","..","code","BlenderScene.h") +outputfile_gen = os.path.join("..","..","code","BlenderSceneGen.h") +outputfile_src = os.path.join("..","..","code","BlenderScene.cpp") + +template_gen = "BlenderSceneGen.h.template" +template_src = "BlenderScene.cpp.template" + + +Structure_Convert_decl = """ +template <> void Structure :: Convert<{a}> ( + {a}& dest, + const FileDatabase& db + ) const +""" + + +Structure_Convert_ptrdecl = """ + ReadFieldPtr<{policy}>({destcast}dest.{name_canonical},"{name_dna}",db);""" + +Structure_Convert_arraydecl = """ + ReadFieldArray<{policy}>({destcast}dest.{name_canonical},"{name_dna}",db);""" + +Structure_Convert_arraydecl2d = """ + ReadFieldArray2<{policy}>({destcast}dest.{name_canonical},"{name_dna}",db);""" + +Structure_Convert_normal = """ + ReadField<{policy}>({destcast}dest.{name_canonical},"{name_dna}",db);""" + + +DNA_RegisterConverters_decl = """ +void DNA::RegisterConverters() """ + +DNA_RegisterConverters_add = """ + converters["{a}"] = DNA::FactoryPair( &Structure::Allocate<{a}>, &Structure::Convert<{a}> );""" + + +map_policy = { + "" : "ErrorPolicy_Igno" + ,"IGNO" : "ErrorPolicy_Igno" + ,"WARN" : "ErrorPolicy_Warn" + ,"FAIL" : "ErrorPolicy_Fail" +} + +# +def main(): + + # ----------------------------------------------------------------------- + # Parse structure definitions from BlenderScene.h + input = open(inputfile,"rt").read() + + flags = re.ASCII|re.DOTALL|re.MULTILINE + #stripcoms = re.compile(r"/\*(.*?)*\/",flags) + getstruct = re.compile(r"struct\s+(\w+?)\s*(:\s*ElemBase)?\s*\{(.*?)^\}\s*;",flags) + getsmartx = re.compile(r"(std\s*::\s*)?(vector)\s*<\s*(boost\s*::\s*)?shared_(ptr)\s*<\s*(\w+)\s*>\s*>\s*",flags) + getsmartp = re.compile(r"(boost\s*::\s*)?shared_(ptr)\s*<\s*(\w+)\s*>\s*",flags) + getsmarta = re.compile(r"(std\s*::\s*)?(vector)\s*<\s*(\w+)\s*>\s*",flags) + getpolicy = re.compile(r"\s*(WARN|FAIL|IGNO)",flags) + stripenum = re.compile(r"enum\s+(\w+)\s*{.*?\}\s*;",flags) + + assert getsmartx and getsmartp and getsmarta and getpolicy and stripenum + + enums = set() + #re.sub(stripcoms," ",input) + #print(input) + + hits = {} + while 1: + match = re.search(getstruct,input) + if match is None: + break + + tmp = match.groups()[2] + while 1: + match2 = re.search(stripenum,tmp) + if match2 is None: + break + tmp = tmp[match2.end():] + enums.add(match2.groups()[0]) + + hits[match.groups()[0]] = list( + filter(lambda x:x[:2] != "//" and len(x), + map(str.strip, + re.sub(stripenum," ",match.groups()[2]).split(";") + ))) + + input = input[match.end():] + + [print ("Enum: "+e) for e in enums] + for k,v in hits.items(): + out = [] + for line in v: + + policy = "IGNO" + py = re.search(getpolicy,line) + if not py is None: + policy = py.groups()[0] + line = re.sub(getpolicy,"",line) + + ty = re.match(getsmartx,line) or re.match(getsmartp,line) or re.match(getsmarta,line) + if ty is None: + ty = line.split(None,1)[0] + else: + if ty.groups()[1] == "ptr": + ty = ty.groups()[2] + "*" + elif ty.groups()[1] == "vector": + ty = ty.groups()[-1] + ("*" if len(ty.groups()) == 3 else "**") + + #print(line) + sp = line.split(',') + out.append((ty,sp[0].split(None)[-1].strip(),policy)) + for m in sp[1:]: + out.append((ty,m.strip(),policy)) + + v[:] = out + print("Structure {0}".format(k)) + [print("\t"+"\t".join(elem)) for elem in out] + print("") + + + output = open(outputfile_gen,"wt") + templt = open(template_gen,"rt").read() + s = "" + + # ----------------------------------------------------------------------- + # Structure::Convert declarations for all supported structures + for k,v in hits.items(): + s += Structure_Convert_decl.format(a=k)+";\n"; + output.write(templt.replace("",s)) + + output = open(outputfile_src,"wt") + templt = open(template_src,"rt").read() + s = "" + + # ----------------------------------------------------------------------- + # Structure::Convert definitions for all supported structures + for k,v in hits.items(): + s += "//" + "-"*80 + Structure_Convert_decl.format(a=k)+ "{ \n"; + + for type, name, policy in v: + splits = name.split("[",1) + name_canonical = splits[0] + #array_part = "" if len(splits)==1 else "["+splits[1] + ptr_decl = "*"*type.count("*") + name_dna = ptr_decl+name_canonical #+array_part + + #required = "false" + policy = map_policy[policy] + destcast = "(int&)" if type in enums else "" + + # POINTER + if ptr_decl: + s += Structure_Convert_ptrdecl.format(**locals()) + # ARRAY MEMBER + elif name.count('[')==1: + s += Structure_Convert_arraydecl.format(**locals()) + elif name.count('[')==2: + s += Structure_Convert_arraydecl2d.format(**locals()) + # NORMAL MEMBER + else: + s += Structure_Convert_normal.format(**locals()) + + s += "\n\n\tdb.reader->IncPtr(size);\n}\n\n" + + + # ----------------------------------------------------------------------- + # DNA::RegisterConverters - collect all available converter functions + # in a std::map + #s += "#if 0\n" + s += "//" + "-"*80 + DNA_RegisterConverters_decl + "{\n" + for k,v in hits.items(): + s += DNA_RegisterConverters_add.format(a=k) + + s += "\n}\n" + #s += "#endif\n" + + output.write(templt.replace("",s)) + + +if __name__ == "__main__": + sys.exit(main()) + + + + + diff --git a/scripts/IFCImporter/CppGenerator.py b/scripts/IFCImporter/CppGenerator.py index 87d9f4e80..3919496dd 100644 --- a/scripts/IFCImporter/CppGenerator.py +++ b/scripts/IFCImporter/CppGenerator.py @@ -1,283 +1,283 @@ -#!/usr/bin/env python3 -# -*- Coding: UTF-8 -*- - -# --------------------------------------------------------------------------- -# Open Asset Import Library (ASSIMP) -# --------------------------------------------------------------------------- -# -# Copyright (c) 2006-2010, ASSIMP Development Team -# -# All rights reserved. -# -# Redistribution and use of this software in source and binary forms, -# with or without modification, are permitted provided that the following -# conditions are met: -# -# * Redistributions of source code must retain the above -# copyright notice, this list of conditions and the -# following disclaimer. -# -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the -# following disclaimer in the documentation and/or other -# materials provided with the distribution. -# -# * Neither the name of the ASSIMP team, nor the names of its -# contributors may be used to endorse or promote products -# derived from this software without specific prior -# written permission of the ASSIMP Development Team. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# --------------------------------------------------------------------------- - -"""Generate the C++ glue code needed to map EXPRESS to C++""" - -import sys, os, re - -input_template_h = 'IFCReaderGen.h.template' -input_template_cpp = 'IFCReaderGen.cpp.template' - -output_file_h = os.path.join('..','..','code','IFCReaderGen.h') -output_file_cpp = os.path.join('..','..','code','IFCReaderGen.cpp') - -template_entity_predef = '\tstruct {entity};\n' -template_entity_predef_ni = '\ttypedef NotImplemented {entity}; // (not currently used by Assimp)\n' -template_entity = r""" - - // C++ wrapper for {entity} - struct {entity} : {parent} ObjectHelper<{entity},{argcnt}> {{ {entity}() : Object("{entity}") {{}} -{fields} - }};""" - -template_entity_ni = '' - -template_type = r""" - // C++ wrapper type for {type} - typedef {real_type} {type};""" - -template_stub_decl = '\tDECL_CONV_STUB({type});\n' -template_schema = '\t\tSchemaEntry("{normalized_name}",&STEP::ObjectHelper<{type},{argcnt}>::Construct )\n' -template_schema_type = '\t\tSchemaEntry("{normalized_name}",NULL )\n' -template_converter = r""" -// ----------------------------------------------------------------------------------------------------------- -template <> size_t GenericFill<{type}>(const DB& db, const LIST& params, {type}* in) -{{ -{contents} -}}""" - -template_converter_prologue_a = '\tsize_t base = GenericFill(db,params,static_cast<{parent}*>(in));\n' -template_converter_prologue_b = '\tsize_t base = 0;\n' -template_converter_check_argcnt = '\tif (params.GetSize() < {max_arg}) {{ throw STEP::TypeError("expected {max_arg} arguments to {name}"); }}' -template_converter_code_per_field = r""" do {{ // convert the '{fieldname}' argument - boost::shared_ptr arg = params[base++];{handle_unset}{convert} - }} while(0); -""" -template_allow_optional = r""" - if (dynamic_cast(&*arg)) break;""" -template_allow_derived = r""" - if (dynamic_cast(&*arg)) {{ in->ObjectHelper::aux_is_derived[{argnum}]=true; break; }}""" -template_convert_single = r""" - try {{ GenericConvert( in->{name}, arg, db ); break; }} - catch (const TypeError& t) {{ throw TypeError(t.what() + std::string(" - expected argument {argnum} to {classname} to be a `{full_type}`")); }}""" - -template_converter_ommitted = '// this data structure is not used yet, so there is no code generated to fill its members\n' -template_converter_epilogue = '\treturn base;' - -import ExpressReader - - -def get_list_bounds(collection_spec): - start,end = [(int(n) if n!='?' else 0) for n in re.findall(r'(\d+|\?)',collection_spec)] - return start,end - -def get_cpp_type(field,schema): - isobjref = field.type in schema.entities - base = field.type - if isobjref: - base = 'Lazy< '+(base if base in schema.whitelist else 'NotImplemented')+' >' - if field.collection: - start,end = get_list_bounds(field.collection) - base = 'ListOf< {0}, {1}, {2} >'.format(base,start,end) - if not isobjref: - base += '::Out' - if field.optional: - base = 'Maybe< '+base+' >' - - return base - -def generate_fields(entity,schema): - fields = [] - for e in entity.members: - fields.append('\t\t{type} {name};'.format(type=get_cpp_type(e,schema),name=e.name)) - return '\n'.join(fields) - -def handle_unset_args(field,entity,schema,argnum): - n = '' - # if someone derives from this class, check for derived fields. - if any(entity.name==e.parent for e in schema.entities.values()): - n += template_allow_derived.format(type=entity.name,argcnt=len(entity.members),argnum=argnum) - - if not field.optional: - return n+'' - return n+template_allow_optional.format() - -def get_single_conversion(field,schema,argnum=0,classname='?'): - typen = field.type - name = field.name - if field.collection: - typen = 'LIST' - return template_convert_single.format(type=typen,name=name,argnum=argnum,classname=classname,full_type=field.fullspec) - -def count_args_up(entity,schema): - return len(entity.members) + (count_args_up(schema.entities[entity.parent],schema) if entity.parent else 0) - -def resolve_base_type(base,schema): - if base in ('INTEGER','REAL','STRING','ENUMERATION','BOOLEAN','NUMBER', 'SELECT','LOGICAL'): - return base - if base in schema.types: - return resolve_base_type(schema.types[base].equals,schema) - print(base) - return None - -def gen_type_struct(typen,schema): - base = resolve_base_type(typen.equals,schema) - if not base: - return '' - - if typen.aggregate: - start,end = get_list_bounds(typen.aggregate) - base = 'ListOf< {0}, {1}, {2} >'.format(base,start,end) - - return template_type.format(type=typen.name,real_type=base) - -def gen_converter(entity,schema): - max_arg = count_args_up(entity,schema) - arg_idx = arg_idx_ofs = max_arg - len(entity.members) - - code = template_converter_prologue_a.format(parent=entity.parent) if entity.parent else template_converter_prologue_b - if entity.name in schema.blacklist_partial: - return code+template_converter_ommitted+template_converter_epilogue; - - if max_arg > 0: - code +=template_converter_check_argcnt.format(max_arg=max_arg,name=entity.name) - - for field in entity.members: - code += template_converter_code_per_field.format(fieldname=field.name, - handle_unset=handle_unset_args(field,entity,schema,arg_idx-arg_idx_ofs), - convert=get_single_conversion(field,schema,arg_idx,entity.name)) - - arg_idx += 1 - return code+template_converter_epilogue - -def get_base_classes(e,schema): - def addit(e,out): - if e.parent: - out.append(e.parent) - addit(schema.entities[e.parent],out) - res = [] - addit(e,res) - return list(reversed(res)) - -def get_derived(e,schema): - def get_deriv(e,out): # bit slow, but doesn't matter here - s = [ee for ee in schema.entities.values() if ee.parent == e.name] - for sel in s: - out.append(sel.name) - get_deriv(sel,out) - res = [] - get_deriv(e,res) - return res - -def get_hierarchy(e,schema): - return get_derived(e.schema)+[e.name]+get_base_classes(e,schema) - -def sort_entity_list(schema): - deps = [] - entities = schema.entities - for e in entities.values(): - deps += get_base_classes(e,schema)+[e.name] - - checked = [] - for e in deps: - if e not in checked: - checked.append(e) - return [entities[e] for e in checked] - -def work(filename): - schema = ExpressReader.read(filename,silent=True) - entities, stub_decls, schema_table, converters, typedefs, predefs = '','',[],'','','' - - - whitelist = [] - with open('entitylist.txt', 'rt') as inp: - whitelist = [n.strip() for n in inp.read().split('\n') if n[:1]!='#' and n.strip()] - - schema.whitelist = set() - schema.blacklist_partial = set() - for ename in whitelist: - try: - e = schema.entities[ename] - except KeyError: - # type, not entity - continue - for base in [e.name]+get_base_classes(e,schema): - schema.whitelist.add(base) - for base in get_derived(e,schema): - schema.blacklist_partial.add(base) - - schema.blacklist_partial -= schema.whitelist - schema.whitelist |= schema.blacklist_partial - - # uncomment this to disable automatic code reduction based on whitelisting all used entities - # (blacklisted entities are those who are in the whitelist and may be instanced, but will - # only be accessed through a pointer to a base-class. - #schema.whitelist = set(schema.entities.keys()) - #schema.blacklist_partial = set() - - for ntype in schema.types.values(): - typedefs += gen_type_struct(ntype,schema) - schema_table.append(template_schema_type.format(normalized_name=ntype.name.lower())) - - sorted_entities = sort_entity_list(schema) - for entity in sorted_entities: - parent = entity.parent+',' if entity.parent else '' - - if entity.name in schema.whitelist: - converters += template_converter.format(type=entity.name,contents=gen_converter(entity,schema)) - schema_table.append(template_schema.format(type=entity.name,normalized_name=entity.name.lower(),argcnt=len(entity.members))) - entities += template_entity.format(entity=entity.name,argcnt=len(entity.members),parent=parent,fields=generate_fields(entity,schema)) - predefs += template_entity_predef.format(entity=entity.name) - stub_decls += template_stub_decl.format(type=entity.name) - else: - entities += template_entity_ni.format(entity=entity.name) - predefs += template_entity_predef_ni.format(entity=entity.name) - schema_table.append(template_schema.format(type="NotImplemented",normalized_name=entity.name.lower(),argcnt=0)) - - schema_table = ','.join(schema_table) - - with open(input_template_h,'rt') as inp: - with open(output_file_h,'wt') as outp: - # can't use format() here since the C++ code templates contain single, unescaped curly brackets - outp.write(inp.read().replace('{predefs}',predefs).replace('{types}',typedefs).replace('{entities}',entities).replace('{converter-decl}',stub_decls)) - - with open(input_template_cpp,'rt') as inp: - with open(output_file_cpp,'wt') as outp: - outp.write(inp.read().replace('{schema-static-table}',schema_table).replace('{converter-impl}',converters)) - -if __name__ == "__main__": - sys.exit(work(sys.argv[1] if len(sys.argv)>1 else 'schema.exp')) - - - - - +#!/usr/bin/env python3 +# -*- Coding: UTF-8 -*- + +# --------------------------------------------------------------------------- +# Open Asset Import Library (ASSIMP) +# --------------------------------------------------------------------------- +# +# Copyright (c) 2006-2010, ASSIMP Development Team +# +# All rights reserved. +# +# Redistribution and use of this software in source and binary forms, +# with or without modification, are permitted provided that the following +# conditions are met: +# +# * Redistributions of source code must retain the above +# copyright notice, this list of conditions and the +# following disclaimer. +# +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the +# following disclaimer in the documentation and/or other +# materials provided with the distribution. +# +# * Neither the name of the ASSIMP team, nor the names of its +# contributors may be used to endorse or promote products +# derived from this software without specific prior +# written permission of the ASSIMP Development Team. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# --------------------------------------------------------------------------- + +"""Generate the C++ glue code needed to map EXPRESS to C++""" + +import sys, os, re + +input_template_h = 'IFCReaderGen.h.template' +input_template_cpp = 'IFCReaderGen.cpp.template' + +output_file_h = os.path.join('..','..','code','IFCReaderGen.h') +output_file_cpp = os.path.join('..','..','code','IFCReaderGen.cpp') + +template_entity_predef = '\tstruct {entity};\n' +template_entity_predef_ni = '\ttypedef NotImplemented {entity}; // (not currently used by Assimp)\n' +template_entity = r""" + + // C++ wrapper for {entity} + struct {entity} : {parent} ObjectHelper<{entity},{argcnt}> {{ {entity}() : Object("{entity}") {{}} +{fields} + }};""" + +template_entity_ni = '' + +template_type = r""" + // C++ wrapper type for {type} + typedef {real_type} {type};""" + +template_stub_decl = '\tDECL_CONV_STUB({type});\n' +template_schema = '\t\tSchemaEntry("{normalized_name}",&STEP::ObjectHelper<{type},{argcnt}>::Construct )\n' +template_schema_type = '\t\tSchemaEntry("{normalized_name}",NULL )\n' +template_converter = r""" +// ----------------------------------------------------------------------------------------------------------- +template <> size_t GenericFill<{type}>(const DB& db, const LIST& params, {type}* in) +{{ +{contents} +}}""" + +template_converter_prologue_a = '\tsize_t base = GenericFill(db,params,static_cast<{parent}*>(in));\n' +template_converter_prologue_b = '\tsize_t base = 0;\n' +template_converter_check_argcnt = '\tif (params.GetSize() < {max_arg}) {{ throw STEP::TypeError("expected {max_arg} arguments to {name}"); }}' +template_converter_code_per_field = r""" do {{ // convert the '{fieldname}' argument + boost::shared_ptr arg = params[base++];{handle_unset}{convert} + }} while(0); +""" +template_allow_optional = r""" + if (dynamic_cast(&*arg)) break;""" +template_allow_derived = r""" + if (dynamic_cast(&*arg)) {{ in->ObjectHelper::aux_is_derived[{argnum}]=true; break; }}""" +template_convert_single = r""" + try {{ GenericConvert( in->{name}, arg, db ); break; }} + catch (const TypeError& t) {{ throw TypeError(t.what() + std::string(" - expected argument {argnum} to {classname} to be a `{full_type}`")); }}""" + +template_converter_ommitted = '// this data structure is not used yet, so there is no code generated to fill its members\n' +template_converter_epilogue = '\treturn base;' + +import ExpressReader + + +def get_list_bounds(collection_spec): + start,end = [(int(n) if n!='?' else 0) for n in re.findall(r'(\d+|\?)',collection_spec)] + return start,end + +def get_cpp_type(field,schema): + isobjref = field.type in schema.entities + base = field.type + if isobjref: + base = 'Lazy< '+(base if base in schema.whitelist else 'NotImplemented')+' >' + if field.collection: + start,end = get_list_bounds(field.collection) + base = 'ListOf< {0}, {1}, {2} >'.format(base,start,end) + if not isobjref: + base += '::Out' + if field.optional: + base = 'Maybe< '+base+' >' + + return base + +def generate_fields(entity,schema): + fields = [] + for e in entity.members: + fields.append('\t\t{type} {name};'.format(type=get_cpp_type(e,schema),name=e.name)) + return '\n'.join(fields) + +def handle_unset_args(field,entity,schema,argnum): + n = '' + # if someone derives from this class, check for derived fields. + if any(entity.name==e.parent for e in schema.entities.values()): + n += template_allow_derived.format(type=entity.name,argcnt=len(entity.members),argnum=argnum) + + if not field.optional: + return n+'' + return n+template_allow_optional.format() + +def get_single_conversion(field,schema,argnum=0,classname='?'): + typen = field.type + name = field.name + if field.collection: + typen = 'LIST' + return template_convert_single.format(type=typen,name=name,argnum=argnum,classname=classname,full_type=field.fullspec) + +def count_args_up(entity,schema): + return len(entity.members) + (count_args_up(schema.entities[entity.parent],schema) if entity.parent else 0) + +def resolve_base_type(base,schema): + if base in ('INTEGER','REAL','STRING','ENUMERATION','BOOLEAN','NUMBER', 'SELECT','LOGICAL'): + return base + if base in schema.types: + return resolve_base_type(schema.types[base].equals,schema) + print(base) + return None + +def gen_type_struct(typen,schema): + base = resolve_base_type(typen.equals,schema) + if not base: + return '' + + if typen.aggregate: + start,end = get_list_bounds(typen.aggregate) + base = 'ListOf< {0}, {1}, {2} >'.format(base,start,end) + + return template_type.format(type=typen.name,real_type=base) + +def gen_converter(entity,schema): + max_arg = count_args_up(entity,schema) + arg_idx = arg_idx_ofs = max_arg - len(entity.members) + + code = template_converter_prologue_a.format(parent=entity.parent) if entity.parent else template_converter_prologue_b + if entity.name in schema.blacklist_partial: + return code+template_converter_ommitted+template_converter_epilogue; + + if max_arg > 0: + code +=template_converter_check_argcnt.format(max_arg=max_arg,name=entity.name) + + for field in entity.members: + code += template_converter_code_per_field.format(fieldname=field.name, + handle_unset=handle_unset_args(field,entity,schema,arg_idx-arg_idx_ofs), + convert=get_single_conversion(field,schema,arg_idx,entity.name)) + + arg_idx += 1 + return code+template_converter_epilogue + +def get_base_classes(e,schema): + def addit(e,out): + if e.parent: + out.append(e.parent) + addit(schema.entities[e.parent],out) + res = [] + addit(e,res) + return list(reversed(res)) + +def get_derived(e,schema): + def get_deriv(e,out): # bit slow, but doesn't matter here + s = [ee for ee in schema.entities.values() if ee.parent == e.name] + for sel in s: + out.append(sel.name) + get_deriv(sel,out) + res = [] + get_deriv(e,res) + return res + +def get_hierarchy(e,schema): + return get_derived(e.schema)+[e.name]+get_base_classes(e,schema) + +def sort_entity_list(schema): + deps = [] + entities = schema.entities + for e in entities.values(): + deps += get_base_classes(e,schema)+[e.name] + + checked = [] + for e in deps: + if e not in checked: + checked.append(e) + return [entities[e] for e in checked] + +def work(filename): + schema = ExpressReader.read(filename,silent=True) + entities, stub_decls, schema_table, converters, typedefs, predefs = '','',[],'','','' + + + whitelist = [] + with open('entitylist.txt', 'rt') as inp: + whitelist = [n.strip() for n in inp.read().split('\n') if n[:1]!='#' and n.strip()] + + schema.whitelist = set() + schema.blacklist_partial = set() + for ename in whitelist: + try: + e = schema.entities[ename] + except KeyError: + # type, not entity + continue + for base in [e.name]+get_base_classes(e,schema): + schema.whitelist.add(base) + for base in get_derived(e,schema): + schema.blacklist_partial.add(base) + + schema.blacklist_partial -= schema.whitelist + schema.whitelist |= schema.blacklist_partial + + # uncomment this to disable automatic code reduction based on whitelisting all used entities + # (blacklisted entities are those who are in the whitelist and may be instanced, but will + # only be accessed through a pointer to a base-class. + #schema.whitelist = set(schema.entities.keys()) + #schema.blacklist_partial = set() + + for ntype in schema.types.values(): + typedefs += gen_type_struct(ntype,schema) + schema_table.append(template_schema_type.format(normalized_name=ntype.name.lower())) + + sorted_entities = sort_entity_list(schema) + for entity in sorted_entities: + parent = entity.parent+',' if entity.parent else '' + + if entity.name in schema.whitelist: + converters += template_converter.format(type=entity.name,contents=gen_converter(entity,schema)) + schema_table.append(template_schema.format(type=entity.name,normalized_name=entity.name.lower(),argcnt=len(entity.members))) + entities += template_entity.format(entity=entity.name,argcnt=len(entity.members),parent=parent,fields=generate_fields(entity,schema)) + predefs += template_entity_predef.format(entity=entity.name) + stub_decls += template_stub_decl.format(type=entity.name) + else: + entities += template_entity_ni.format(entity=entity.name) + predefs += template_entity_predef_ni.format(entity=entity.name) + schema_table.append(template_schema.format(type="NotImplemented",normalized_name=entity.name.lower(),argcnt=0)) + + schema_table = ','.join(schema_table) + + with open(input_template_h,'rt') as inp: + with open(output_file_h,'wt') as outp: + # can't use format() here since the C++ code templates contain single, unescaped curly brackets + outp.write(inp.read().replace('{predefs}',predefs).replace('{types}',typedefs).replace('{entities}',entities).replace('{converter-decl}',stub_decls)) + + with open(input_template_cpp,'rt') as inp: + with open(output_file_cpp,'wt') as outp: + outp.write(inp.read().replace('{schema-static-table}',schema_table).replace('{converter-impl}',converters)) + +if __name__ == "__main__": + sys.exit(work(sys.argv[1] if len(sys.argv)>1 else 'schema.exp')) + + + + + diff --git a/scripts/IFCImporter/ExpressReader.py b/scripts/IFCImporter/ExpressReader.py index 8fe948c34..4318347cf 100644 --- a/scripts/IFCImporter/ExpressReader.py +++ b/scripts/IFCImporter/ExpressReader.py @@ -1,120 +1,120 @@ -#!/usr/bin/env python3 -# -*- Coding: UTF-8 -*- - -# --------------------------------------------------------------------------- -# Open Asset Import Library (ASSIMP) -# --------------------------------------------------------------------------- -# -# Copyright (c) 2006-2010, ASSIMP Development Team -# -# All rights reserved. -# -# Redistribution and use of this software in source and binary forms, -# with or without modification, are permitted provided that the following -# conditions are met: -# -# * Redistributions of source code must retain the above -# copyright notice, this list of conditions and the -# following disclaimer. -# -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the -# following disclaimer in the documentation and/or other -# materials provided with the distribution. -# -# * Neither the name of the ASSIMP team, nor the names of its -# contributors may be used to endorse or promote products -# derived from this software without specific prior -# written permission of the ASSIMP Development Team. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# --------------------------------------------------------------------------- - -"""Parse an EXPRESS file and extract basic information on all -entities and data types contained""" - -import sys, os, re - -re_match_entity = re.compile(r""" -ENTITY\s+(\w+)\s* # 'ENTITY foo' -.*? # skip SUPERTYPE-of -(?:SUBTYPE\s+OF\s+\((\w+)\))?; # 'SUBTYPE OF (bar);' or simply ';' -(.*?) # 'a : atype;' (0 or more lines like this) -(?:(?:INVERSE|UNIQUE|WHERE)\s*$.*?)? # skip the INVERSE, UNIQUE, WHERE clauses and everything behind -END_ENTITY; -""",re.VERBOSE|re.DOTALL|re.MULTILINE) - -re_match_type = re.compile(r""" -TYPE\s+(\w+?)\s*=\s*((?:LIST|SET)\s*\[\d+:[\d?]+\]\s*OF)?(?:\s*UNIQUE)?\s*(\w+) # TYPE foo = LIST[1:2] of blub -(?:(?<=ENUMERATION)\s*OF\s*\((.*?)\))? -.*? # skip the WHERE clause -END_TYPE; -""",re.VERBOSE|re.DOTALL) - -re_match_field = re.compile(r""" -\s+(\w+?)\s*:\s*(OPTIONAL)?\s*((?:LIST|SET)\s*\[\d+:[\d?]+\]\s*OF)?(?:\s*UNIQUE)?\s*(\w+?); -""",re.VERBOSE|re.DOTALL) - - -class Schema: - def __init__(self): - self.entities = {} - self.types = {} - -class Entity: - def __init__(self,name,parent,members): - self.name = name - self.parent = parent - self.members = members - -class Field: - def __init__(self,name,type,optional,collection): - self.name = name - self.type = type - self.optional = optional - self.collection = collection - self.fullspec = (self.collection+' ' if self.collection else '') + self.type - -class Type: - def __init__(self,name,aggregate,equals,enums): - self.name = name - self.aggregate = aggregate - self.equals = equals - self.enums = enums - - -def read(filename,silent=False): - schema = Schema() - with open(filename,'rt') as inp: - contents = inp.read() - types = re.findall(re_match_type,contents) - for name,aggregate,equals,enums in types: - schema.types[name] = Type(name,aggregate,equals,enums) - - entities = re.findall(re_match_entity,contents) - for name,parent,fields_raw in entities: - print('process entity {0}, parent is {1}'.format(name,parent)) if not silent else None - fields = re.findall(re_match_field,fields_raw) - members = [Field(name,type,opt,coll) for name, opt, coll, type in fields] - print(' got {0} fields'.format(len(members))) if not silent else None - - schema.entities[name] = Entity(name,parent,members) - return schema - -if __name__ == "__main__": - sys.exit(read(sys.argv[1] if len(sys.argv)>1 else 'schema.exp')) - - - - - +#!/usr/bin/env python3 +# -*- Coding: UTF-8 -*- + +# --------------------------------------------------------------------------- +# Open Asset Import Library (ASSIMP) +# --------------------------------------------------------------------------- +# +# Copyright (c) 2006-2010, ASSIMP Development Team +# +# All rights reserved. +# +# Redistribution and use of this software in source and binary forms, +# with or without modification, are permitted provided that the following +# conditions are met: +# +# * Redistributions of source code must retain the above +# copyright notice, this list of conditions and the +# following disclaimer. +# +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the +# following disclaimer in the documentation and/or other +# materials provided with the distribution. +# +# * Neither the name of the ASSIMP team, nor the names of its +# contributors may be used to endorse or promote products +# derived from this software without specific prior +# written permission of the ASSIMP Development Team. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# --------------------------------------------------------------------------- + +"""Parse an EXPRESS file and extract basic information on all +entities and data types contained""" + +import sys, os, re + +re_match_entity = re.compile(r""" +ENTITY\s+(\w+)\s* # 'ENTITY foo' +.*? # skip SUPERTYPE-of +(?:SUBTYPE\s+OF\s+\((\w+)\))?; # 'SUBTYPE OF (bar);' or simply ';' +(.*?) # 'a : atype;' (0 or more lines like this) +(?:(?:INVERSE|UNIQUE|WHERE)\s*$.*?)? # skip the INVERSE, UNIQUE, WHERE clauses and everything behind +END_ENTITY; +""",re.VERBOSE|re.DOTALL|re.MULTILINE) + +re_match_type = re.compile(r""" +TYPE\s+(\w+?)\s*=\s*((?:LIST|SET)\s*\[\d+:[\d?]+\]\s*OF)?(?:\s*UNIQUE)?\s*(\w+) # TYPE foo = LIST[1:2] of blub +(?:(?<=ENUMERATION)\s*OF\s*\((.*?)\))? +.*? # skip the WHERE clause +END_TYPE; +""",re.VERBOSE|re.DOTALL) + +re_match_field = re.compile(r""" +\s+(\w+?)\s*:\s*(OPTIONAL)?\s*((?:LIST|SET)\s*\[\d+:[\d?]+\]\s*OF)?(?:\s*UNIQUE)?\s*(\w+?); +""",re.VERBOSE|re.DOTALL) + + +class Schema: + def __init__(self): + self.entities = {} + self.types = {} + +class Entity: + def __init__(self,name,parent,members): + self.name = name + self.parent = parent + self.members = members + +class Field: + def __init__(self,name,type,optional,collection): + self.name = name + self.type = type + self.optional = optional + self.collection = collection + self.fullspec = (self.collection+' ' if self.collection else '') + self.type + +class Type: + def __init__(self,name,aggregate,equals,enums): + self.name = name + self.aggregate = aggregate + self.equals = equals + self.enums = enums + + +def read(filename,silent=False): + schema = Schema() + with open(filename,'rt') as inp: + contents = inp.read() + types = re.findall(re_match_type,contents) + for name,aggregate,equals,enums in types: + schema.types[name] = Type(name,aggregate,equals,enums) + + entities = re.findall(re_match_entity,contents) + for name,parent,fields_raw in entities: + print('process entity {0}, parent is {1}'.format(name,parent)) if not silent else None + fields = re.findall(re_match_field,fields_raw) + members = [Field(name,type,opt,coll) for name, opt, coll, type in fields] + print(' got {0} fields'.format(len(members))) if not silent else None + + schema.entities[name] = Entity(name,parent,members) + return schema + +if __name__ == "__main__": + sys.exit(read(sys.argv[1] if len(sys.argv)>1 else 'schema.exp')) + + + + +