ExpressReader.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. #!/usr/bin/env python3
  2. # -*- Coding: UTF-8 -*-
  3. # ---------------------------------------------------------------------------
  4. # Open Asset Import Library (ASSIMP)
  5. # ---------------------------------------------------------------------------
  6. #
  7. # Copyright (c) 2006-2020, ASSIMP Development Team
  8. #
  9. # All rights reserved.
  10. #
  11. # Redistribution and use of this software in source and binary forms,
  12. # with or without modification, are permitted provided that the following
  13. # conditions are met:
  14. #
  15. # * Redistributions of source code must retain the above
  16. # copyright notice, this list of conditions and the
  17. # following disclaimer.
  18. #
  19. # * Redistributions in binary form must reproduce the above
  20. # copyright notice, this list of conditions and the
  21. # following disclaimer in the documentation and/or other
  22. # materials provided with the distribution.
  23. #
  24. # * Neither the name of the ASSIMP team, nor the names of its
  25. # contributors may be used to endorse or promote products
  26. # derived from this software without specific prior
  27. # written permission of the ASSIMP Development Team.
  28. #
  29. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  30. # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  31. # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  32. # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  33. # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  34. # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  35. # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  36. # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  37. # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  38. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  39. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  40. # ---------------------------------------------------------------------------
  41. """Parse an EXPRESS file and extract basic information on all
  42. entities and data types contained"""
  43. import sys
  44. import re
  45. from collections import OrderedDict
  46. re_match_entity = re.compile(r"""
  47. ENTITY\s+(\w+)\s* # 'ENTITY foo'
  48. .*? # skip SUPERTYPE-of
  49. (?:SUBTYPE\s+OF\s+\((\w+)\))?; # 'SUBTYPE OF (bar);' or simply ';'
  50. (.*?) # 'a : atype;' (0 or more lines like this)
  51. (?:(?:INVERSE|UNIQUE|WHERE)\s*$.*?)? # skip the INVERSE, UNIQUE, WHERE clauses and everything behind
  52. END_ENTITY;
  53. """,re.VERBOSE|re.DOTALL|re.MULTILINE)
  54. re_match_type = re.compile(r"""
  55. TYPE\s+(\w+?)\s*=\s*((?:LIST|SET)\s*\[\d+:[\d?]+\]\s*OF)?(?:\s*UNIQUE)?\s*(\w+) # TYPE foo = LIST[1:2] of blub
  56. (?:(?<=ENUMERATION)\s*OF\s*\((.*?)\))?
  57. .*? # skip the WHERE clause
  58. END_TYPE;
  59. """,re.VERBOSE|re.DOTALL)
  60. re_match_field = re.compile(r"""
  61. \s+(\w+?)\s*:\s*(OPTIONAL)?\s*((?:LIST|SET)\s*\[\d+:[\d?]+\]\s*OF)?(?:\s*UNIQUE)?\s*(\w+?);
  62. """,re.VERBOSE|re.DOTALL)
  63. class Schema:
  64. def __init__(self):
  65. self.entities = OrderedDict()
  66. self.types = OrderedDict()
  67. class Entity:
  68. def __init__(self,name,parent,members):
  69. self.name = name
  70. self.parent = parent
  71. self.members = members
  72. class Field:
  73. def __init__(self,name,type,optional,collection):
  74. self.name = name
  75. self.type = type
  76. self.optional = optional
  77. self.collection = collection
  78. self.fullspec = (self.collection+' ' if self.collection else '') + self.type
  79. class Type:
  80. def __init__(self,name,aggregate,equals,enums):
  81. self.name = name
  82. self.aggregate = aggregate
  83. self.equals = equals
  84. self.enums = enums
  85. def read(filename, silent=False):
  86. schema = Schema()
  87. print( "Try to read EXPRESS schema file" + filename)
  88. with open(filename,'rt') as inp:
  89. contents = inp.read()
  90. types = re.findall(re_match_type,contents)
  91. for name,aggregate,equals,enums in types:
  92. schema.types[name] = Type(name,aggregate,equals,enums)
  93. entities = re.findall(re_match_entity,contents)
  94. for name,parent,fields_raw in entities:
  95. print('process entity {0}, parent is {1}'.format(name,parent)) if not silent else None
  96. fields = re.findall(re_match_field,fields_raw)
  97. members = [Field(name,type,opt,coll) for name, opt, coll, type in fields]
  98. print(' got {0} fields'.format(len(members))) if not silent else None
  99. schema.entities[name] = Entity(name,parent,members)
  100. return schema
  101. if __name__ == "__main__":
  102. sys.exit(read(sys.argv[1] if len(sys.argv)>1 else 'schema.exp'))