diff --git a/src/ifcexpressparser/bootstrap.py b/src/ifcexpressparser/bootstrap.py index 00936c2f4b..77e7f7131e 100644 --- a/src/ifcexpressparser/bootstrap.py +++ b/src/ifcexpressparser/bootstrap.py @@ -19,8 +19,14 @@ import sys import string +import operator +import itertools + from pyparsing import * +try: from functools import reduce +except: pass + class Expression: def __init__(self, contents): self.contents = contents[0] @@ -56,12 +62,12 @@ class Keyword: class Terminal: def __init__(self, contents): self.contents = contents[0] - def __repr__(self): s = self.contents - is_keyword = len(s) >= 4 and s[0::len(s)-1] == '""' and \ + self.is_keyword = len(s) >= 4 and s[0::len(s)-1] == '""' and \ all(c in alphanums+"_" for c in s[1:-1]) - ty = "CaselessKeyword" if is_keyword else "CaselessLiteral" - return "%s(%s)" % (ty, s) + def __repr__(self): + ty = "CaselessKeyword" if self.is_keyword else "CaselessLiteral" + return "%s(%s)" % (ty, self.contents) LPAREN = Suppress("(") @@ -94,16 +100,16 @@ grammar.ignore(HASH + restOfLine) express = grammar.parseFile(sys.argv[1]) -def find_keywords(expr, li = None): +def find_bytype(expr, ty, li = None): if li is None: li = [] if isinstance(expr, Term): expr = expr.contents - if isinstance(expr, Keyword): - li.append(repr(expr)) - return li + if isinstance(expr, ty): + li.append(expr) + return set(li) elif isinstance(expr, Expression): for term in expr: - find_keywords(term, li) + find_bytype(term, ty, li) return set(li) actions = { @@ -131,18 +137,22 @@ emitted = set() to_combine = set(["simple_id"]) to_ignore = set(["where_clause", "supertype_constraint", "unique_clause"]) statements = [] + +terminals = reduce(lambda x,y: x | y, (find_bytype(e, Terminal) for id, e in express)) +keywords = list(filter(operator.attrgetter('is_keyword'), terminals)) +negated_keywords = map(lambda s: "~%s" % s, keywords) while True: emitted_in_loop = set() for id, expr in express: - kws = find_keywords(expr) + kws = map(repr, find_bytype(expr, Keyword)) found = [k in emitted for k in kws] if id in to_emit and all(found): emitted_in_loop.add(id) emitted.add(id) stmt = "(%s)" % expr if id in to_combine: - stmt = "originalTextFor(Combine%s)" % stmt + stmt = " + ".join(itertools.chain(negated_keywords, ("originalTextFor(Combine%s)" % stmt,))) if id in actions: stmt = "%s.setParseAction(%s)" % (stmt, actions[id]) statements.append("%s = %s" % (id, stmt)) diff --git a/src/ifcexpressparser/express.bnf b/src/ifcexpressparser/express.bnf index 89acfd4fff..de40bfaf23 100644 --- a/src/ifcexpressparser/express.bnf +++ b/src/ifcexpressparser/express.bnf @@ -1,5 +1,3 @@ -# Taken from http://sourceforge.net/p/exp-engine/expresso/ci/master/tree/docs/iso-10303-11--2004.bnf - ABS = "abs" . ABSTRACT = "abstract" . ACOS = "acos" . @@ -202,7 +200,7 @@ constructed_types = enumeration_type | select_type . declaration = entity_decl | function_decl | procedure_decl | subtype_constraint_decl | type_decl . derived_attr = attribute_decl ":" parameter_type ":=" expression ";" . derive_clause = DERIVE derived_attr { derived_attr } . -domain_rule = rule_label_id ":" expression . +domain_rule = [ rule_label_id ":" ] expression . element = expression [ ":" repetition ] . entity_body = { explicit_attr } [ derive_clause ] [ inverse_clause ] [ unique_clause ] [ where_clause ] . entity_constructor = entity_ref "(" [ expression { "," expression } ] ")" . @@ -334,7 +332,7 @@ type_label_id = simple_id . unary_op = "+" | "-" | NOT . underlying_type = constructed_types | concrete_types . unique_clause = UNIQUE unique_rule ";" { unique_rule ";" } . -unique_rule = rule_label_id ":" referenced_attribute { "," referenced_attribute } . +unique_rule = [ rule_label_id ":" ] referenced_attribute { "," referenced_attribute } . until_control = UNTIL logical_expression . use_clause = USE FROM schema_ref [ "(" named_type_or_rename { "," named_type_or_rename } ")" ] ";" . variable_id = simple_id .