Skip to content

Commit 191c029

Browse files
committed
Correctly allow rule labels to be optional
1 parent 9bcfe2f commit 191c029

File tree

2 files changed

+23
-15
lines changed

2 files changed

+23
-15
lines changed

src/ifcexpressparser/bootstrap.py

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,14 @@
1919

2020
import sys
2121
import string
22+
import operator
23+
import itertools
24+
2225
from pyparsing import *
2326

27+
try: from functools import reduce
28+
except: pass
29+
2430
class Expression:
2531
def __init__(self, contents):
2632
self.contents = contents[0]
@@ -56,12 +62,12 @@ def __repr__(self):
5662
class Terminal:
5763
def __init__(self, contents):
5864
self.contents = contents[0]
59-
def __repr__(self):
6065
s = self.contents
61-
is_keyword = len(s) >= 4 and s[0::len(s)-1] == '""' and \
66+
self.is_keyword = len(s) >= 4 and s[0::len(s)-1] == '""' and \
6267
all(c in alphanums+"_" for c in s[1:-1])
63-
ty = "CaselessKeyword" if is_keyword else "CaselessLiteral"
64-
return "%s(%s)" % (ty, s)
68+
def __repr__(self):
69+
ty = "CaselessKeyword" if self.is_keyword else "CaselessLiteral"
70+
return "%s(%s)" % (ty, self.contents)
6571

6672

6773
LPAREN = Suppress("(")
@@ -94,16 +100,16 @@ def __repr__(self):
94100

95101
express = grammar.parseFile(sys.argv[1])
96102

97-
def find_keywords(expr, li = None):
103+
def find_bytype(expr, ty, li = None):
98104
if li is None: li = []
99105
if isinstance(expr, Term):
100106
expr = expr.contents
101-
if isinstance(expr, Keyword):
102-
li.append(repr(expr))
103-
return li
107+
if isinstance(expr, ty):
108+
li.append(expr)
109+
return set(li)
104110
elif isinstance(expr, Expression):
105111
for term in expr:
106-
find_keywords(term, li)
112+
find_bytype(term, ty, li)
107113
return set(li)
108114

109115
actions = {
@@ -131,18 +137,22 @@ def find_keywords(expr, li = None):
131137
to_combine = set(["simple_id"])
132138
to_ignore = set(["where_clause", "supertype_constraint", "unique_clause"])
133139
statements = []
140+
141+
terminals = reduce(lambda x,y: x | y, (find_bytype(e, Terminal) for id, e in express))
142+
keywords = list(filter(operator.attrgetter('is_keyword'), terminals))
143+
negated_keywords = map(lambda s: "~%s" % s, keywords)
134144

135145
while True:
136146
emitted_in_loop = set()
137147
for id, expr in express:
138-
kws = find_keywords(expr)
148+
kws = map(repr, find_bytype(expr, Keyword))
139149
found = [k in emitted for k in kws]
140150
if id in to_emit and all(found):
141151
emitted_in_loop.add(id)
142152
emitted.add(id)
143153
stmt = "(%s)" % expr
144154
if id in to_combine:
145-
stmt = "originalTextFor(Combine%s)" % stmt
155+
stmt = " + ".join(itertools.chain(negated_keywords, ("originalTextFor(Combine%s)" % stmt,)))
146156
if id in actions:
147157
stmt = "%s.setParseAction(%s)" % (stmt, actions[id])
148158
statements.append("%s = %s" % (id, stmt))

src/ifcexpressparser/express.bnf

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
# Taken from http://sourceforge.net/p/exp-engine/expresso/ci/master/tree/docs/iso-10303-11--2004.bnf
2-
31
ABS = "abs" .
42
ABSTRACT = "abstract" .
53
ACOS = "acos" .
@@ -202,7 +200,7 @@ constructed_types = enumeration_type | select_type .
202200
declaration = entity_decl | function_decl | procedure_decl | subtype_constraint_decl | type_decl .
203201
derived_attr = attribute_decl ":" parameter_type ":=" expression ";" .
204202
derive_clause = DERIVE derived_attr { derived_attr } .
205-
domain_rule = rule_label_id ":" expression .
203+
domain_rule = [ rule_label_id ":" ] expression .
206204
element = expression [ ":" repetition ] .
207205
entity_body = { explicit_attr } [ derive_clause ] [ inverse_clause ] [ unique_clause ] [ where_clause ] .
208206
entity_constructor = entity_ref "(" [ expression { "," expression } ] ")" .
@@ -334,7 +332,7 @@ type_label_id = simple_id .
334332
unary_op = "+" | "-" | NOT .
335333
underlying_type = constructed_types | concrete_types .
336334
unique_clause = UNIQUE unique_rule ";" { unique_rule ";" } .
337-
unique_rule = rule_label_id ":" referenced_attribute { "," referenced_attribute } .
335+
unique_rule = [ rule_label_id ":" ] referenced_attribute { "," referenced_attribute } .
338336
until_control = UNTIL logical_expression .
339337
use_clause = USE FROM schema_ref [ "(" named_type_or_rename { "," named_type_or_rename } ")" ] ";" .
340338
variable_id = simple_id .

0 commit comments

Comments
 (0)