import lark class Selector(): def parse(self, ifc_file, query): self.file = ifc_file l = lark.Lark('''start: query (lfunction query)* query: selector | group group: "(" query (lfunction query)* ")" selector: (inverse_relationship)? guid_selector | (inverse_relationship)? class_selector guid_selector: "#" /[0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$]{22}/ class_selector: "." WORD filter ? filter: "[" filter_key (comparison filter_value)? "]" filter_key: WORD | pset_or_qto filter_value: ESCAPED_STRING pset_or_qto: /[A-Za-z0-9_]+/ "." /[A-Za-z0-9_]+/ lfunction: and | or inverse_relationship: types | contains_elements types: "*" contains_elements: "@" and: "&" or: "|" comparison: contains | morethanequalto | lessthanequalto | equal | morethan | lessthan contains: "*=" morethanequalto: ">=" lessthanequalto: "<" equal: "=" morethan: ">" lessthan: "<" // Embed common.lark for packaging DIGIT: "0".."9" HEXDIGIT: "a".."f"|"A".."F"|DIGIT INT: DIGIT+ SIGNED_INT: ["+"|"-"] INT DECIMAL: INT "." INT? | "." INT _EXP: ("e"|"E") SIGNED_INT FLOAT: INT _EXP | DECIMAL _EXP? SIGNED_FLOAT: ["+"|"-"] FLOAT NUMBER: FLOAT | INT SIGNED_NUMBER: ["+"|"-"] NUMBER _STRING_INNER: /.*?/ _STRING_ESC_INNER: _STRING_INNER /(? 1 \ and class_selector.children[1].data == 'filter': return self.filter_elements(elements, class_selector.children[1]) return elements def filter_elements(self, elements, filter_rule): results = [] key = filter_rule.children[0].children[0] if not isinstance(key, str): key = key.children[0] + '.' + key.children[1] comparison = value = None if len(filter_rule.children) > 1: comparison = filter_rule.children[1].children[0].data value = filter_rule.children[2].children[0][1:-1] for element in elements: element_value = IfcAttributeExtractor.get_element_key(element, key) if not element_value: continue if not comparison \ or self.filter_element(element, element_value, comparison, value): results.append(element) return results def filter_element(self, element, element_value, comparison, value): if comparison == 'equal': return str(element_value) == value elif comparison == 'contains': return value in str(element_value) elif comparison == 'morethan': return element_value > float(value) elif comparison == 'lessthan': return element_value < float(value) elif comparison == 'morethanequalto': return element_value >= float(value) elif comparison == 'lessthanequalto': return element_value <= float(value) return False def get_guid_selector(self, guid_selector): return [self.file.by_id(guid_selector.children[0])]