From db81b925d776103326128bf629cbdda576a223e7 Mon Sep 17 00:00:00 2001 From: sanine Date: Sat, 16 Apr 2022 11:55:09 -0500 Subject: move 3rd-party librarys into libs/ and add built-in honeysuckle --- libs/assimp/scripts/StepImporter/CppGenerator.py | 304 +++++++++++++++++++++++ 1 file changed, 304 insertions(+) create mode 100644 libs/assimp/scripts/StepImporter/CppGenerator.py (limited to 'libs/assimp/scripts/StepImporter/CppGenerator.py') diff --git a/libs/assimp/scripts/StepImporter/CppGenerator.py b/libs/assimp/scripts/StepImporter/CppGenerator.py new file mode 100644 index 0000000..b6c8ed5 --- /dev/null +++ b/libs/assimp/scripts/StepImporter/CppGenerator.py @@ -0,0 +1,304 @@ +#!/usr/bin/env python3 +# -*- Coding: UTF-8 -*- + +# --------------------------------------------------------------------------- +# Open Asset Import Library (ASSIMP) +# --------------------------------------------------------------------------- +# +# Copyright (c) 2006-2020, 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 + +if sys.version_info < (3, 0): + print("must use python 3.0 or greater") + sys.exit(-2) + +use_ifc_template = False + +input_step_template_h = 'StepReaderGen.h.template' +input_step_template_cpp = 'StepReaderGen.cpp.template' +input_ifc_template_h = 'IFCReaderGen.h.template' +input_ifc_template_cpp = 'IFCReaderGen.cpp.template' + +cpp_keywords = "class" + +output_file_h = "" +output_file_cpp = "" +if (use_ifc_template ): + input_template_h = input_ifc_template_h + input_template_cpp = input_ifc_template_cpp + output_file_h = os.path.join('..','..','code','IFCReaderGen.h') + output_file_cpp = os.path.join('..','..','code','IFCReaderGen.cpp') +else: + input_template_h = input_step_template_h + input_template_cpp = input_step_template_cpp + output_file_h = os.path.join('..','..','code/Importer/StepFile','StepReaderGen.h') + output_file_cpp = os.path.join('..','..','code/Importer/StepFile','StepReaderGen.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}",nullptr )\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 + std::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_omitted = '// 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='?'): + name = field.name + return template_convert_single.format(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_omitted+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 = '','',[],'','','' + + entitylist = 'ifc_entitylist.txt' + if not use_ifc_template: + entitylist = 'step_entitylist.txt' + whitelist = [] + with open(entitylist, '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 + + # Generate list with reserved keywords from c++ + cpp_types = cpp_keywords.split(',') + + # 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 cpp_types ): + entity.name = entity.name + "_t" + print( "renaming " + entity.name) + 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)) + + # Finished without error, so return 0 + return 0 + +if __name__ == "__main__": + sys.exit(work(sys.argv[1] if len(sys.argv)>1 else 'schema.exp')) -- cgit v1.2.1