Run black on express/

This commit is contained in:
Thomas Krijnen
2026-02-26 12:36:01 +01:00
parent 18527a78e1
commit 077a0c3755
11 changed files with 239 additions and 222 deletions
@@ -163,7 +163,18 @@ statements = []
terminals = reduce(lambda x, y: x | y, (find_bytype(e, Terminal) for id, e in express)) terminals = reduce(lambda x, y: x | y, (find_bytype(e, Terminal) for id, e in express))
keywords = list(filter(operator.attrgetter("is_keyword"), terminals)) keywords = list(filter(operator.attrgetter("is_keyword"), terminals))
negated_keywords = map(lambda s: "~%s" % s, keywords) negated_keywords = map(lambda s: "~%s" % s, keywords)
no_action = {"letter", "digit", "digits", "real_literal", "integer_literal", "string_literal", "simple_string_literal", "letter", "not_quote", "not_paren_star_quote_special"} no_action = {
"letter",
"digit",
"digits",
"real_literal",
"integer_literal",
"string_literal",
"simple_string_literal",
"letter",
"not_quote",
"not_paren_star_quote_special",
}
while True: while True:
emitted_in_loop = set() emitted_in_loop = set()
@@ -194,7 +205,9 @@ for id in to_emit:
if id in to_combine: if id in to_combine:
stmt = "Suppress%s" % stmt stmt = "Suppress%s" % stmt
if id not in no_action and not isinstance(expr.contents, Keyword): if id not in no_action and not isinstance(expr.contents, Keyword):
children = list(map(operator.attrgetter('contents'), reduce(lambda x, y: x | y, (find_bytype(e, Keyword) for e in [expr])))) children = list(
map(operator.attrgetter("contents"), reduce(lambda x, y: x | y, (find_bytype(e, Keyword) for e in [expr])))
)
has_duplicates = len(children) > len(set(children)) has_duplicates = len(children) > len(set(children))
node_type = "ListNode" if ("ZeroOrMore" in stmt or has_duplicates) else "Node" node_type = "ListNode" if ("ZeroOrMore" in stmt or has_duplicates) else "Node"
action = ".setParseAction(%s)" % ( action = ".setParseAction(%s)" % (
@@ -243,5 +256,4 @@ if __name__ == "__main__":
mdl = importlib.import_module(output) mdl = importlib.import_module(output)
mdl.Generator(m).emit() mdl.Generator(m).emit()
sys.stdout.write(m.schema.name) sys.stdout.write(m.schema.name)
""" % ("\n ".join(statements)) """ % ("\n ".join(statements)))
)
@@ -1,15 +1,16 @@
import sys, fileinput import sys, fileinput
if sys.platform == "win32" and not hasattr(sys.stdout, 'buffer'): if sys.platform == "win32" and not hasattr(sys.stdout, "buffer"):
import os, msvcrt import os, msvcrt
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
files = sys.argv[1:] files = sys.argv[1:]
if files[0] == '-o': if files[0] == "-o":
b = open(files[1], 'wb') b = open(files[1], "wb")
files = files[2:] files = files[2:]
else: else:
b = getattr(sys.stdout, 'buffer', sys.stdout) b = getattr(sys.stdout, "buffer", sys.stdout)
for line in fileinput.input(files=files, mode='rb'): for line in fileinput.input(files=files, mode="rb"):
b.write(line) b.write(line)
@@ -26,7 +26,7 @@ def indent(n, s):
else: else:
strs = s strs = s
splitted = itertools.chain.from_iterable(map(functools.partial(str.split, sep="\n"), map(str, strs))) splitted = itertools.chain.from_iterable(map(functools.partial(str.split, sep="\n"), map(str, strs)))
return "\n".join(" "*n + l for l in splitted) return "\n".join(" " * n + l for l in splitted)
class Base: class Base:
@@ -28,6 +28,7 @@ from collections import defaultdict
USE_VIRTUAL_INHERITANCE = True USE_VIRTUAL_INHERITANCE = True
class Header(codegen.Base): class Header(codegen.Base):
def __init__(self, mapping): def __init__(self, mapping):
declarations = [] declarations = []
@@ -118,10 +118,7 @@ class Implementation(codegen.Base):
null_check = "" null_check = ""
if arg["is_optional"]: if arg["is_optional"]:
attr_check = ( attr_check = "if(get_attribute_value(%d).isNull()) { return %%s; }" % (arg["index"] - 1,)
"if(get_attribute_value(%d).isNull()) { return %%s; }"
% (arg["index"] - 1,)
)
if "boost::optional" in arg["full_type"]: if "boost::optional" in arg["full_type"]:
null_check = attr_check % "boost::none" null_check = attr_check % "boost::none"
else: else:
@@ -157,7 +154,7 @@ class Implementation(codegen.Base):
return templates.set_attr_stmt_enum return templates.set_attr_stmt_enum
elif arg["is_templated_list"] and not (select or simple or express): elif arg["is_templated_list"] and not (select or simple or express):
return templates.set_attr_stmt_array return templates.set_attr_stmt_array
elif arg["full_type"].endswith('*'): elif arg["full_type"].endswith("*"):
return templates.set_attr_instance return templates.set_attr_instance
else: else:
return templates.set_attr_stmt return templates.set_attr_stmt
@@ -178,7 +175,9 @@ class Implementation(codegen.Base):
"non_optional_type": arg["non_optional_type"].replace("::Value", ""), "non_optional_type": arg["non_optional_type"].replace("::Value", ""),
"star_if_optional": "*" if "boost::optional" in arg["full_type"] else "", "star_if_optional": "*" if "boost::optional" in arg["full_type"] else "",
"check_optional_set_begin": "if (v) {" if "boost::optional" in arg["full_type"] else "", "check_optional_set_begin": "if (v) {" if "boost::optional" in arg["full_type"] else "",
"check_optional_set_else": "} else {" if "boost::optional" in arg["full_type"] else "if constexpr (false)", "check_optional_set_else": (
"} else {" if "boost::optional" in arg["full_type"] else "if constexpr (false)"
),
"check_optional_set_end": "}" if "boost::optional" in arg["full_type"] else "", "check_optional_set_end": "}" if "boost::optional" in arg["full_type"] else "",
}, },
) )
@@ -193,11 +192,15 @@ class Implementation(codegen.Base):
tmpl = ( tmpl = (
templates.constructor_stmt_array templates.constructor_stmt_array
if arg["is_templated_list"] if arg["is_templated_list"]
else templates.constructor_stmt_enum else (
if arg["is_enum"] templates.constructor_stmt_enum
else templates.constructor_stmt_instance if arg["is_enum"]
if arg["full_type"].endswith('*') else (
else templates.constructor_stmt templates.constructor_stmt_instance
if arg["full_type"].endswith("*")
else templates.constructor_stmt
)
)
) )
impl = tmpl % { impl = tmpl % {
"name": deref_name, "name": deref_name,
@@ -321,7 +324,7 @@ class Implementation(codegen.Base):
else templates.simpletype_impl_is_without_supertype else templates.simpletype_impl_is_without_supertype
) )
constructor = templates.constructor_single_initlist# if superclass else templates.constructor constructor = templates.constructor_single_initlist # if superclass else templates.constructor
simpletype_impl_cast = ( simpletype_impl_cast = (
templates.simpletype_impl_cast_templated templates.simpletype_impl_cast_templated
@@ -374,8 +377,21 @@ class Implementation(codegen.Base):
("IfcEntityInstanceData&& e",), ("IfcEntityInstanceData&& e",),
"", "",
), ),
("", "", constructor, "", ("%s v" % type_str,), ("set_attribute_value(0, v%s);" % ("->generalize()" if mapping.is_templated_list(type) else ""))) if mapping.simple_type_parent(class_name) is None else \ (
("v", "", constructor, "", ("%s v" % type_str,), ""), (
"",
"",
constructor,
"",
("%s v" % type_str,),
(
"set_attribute_value(0, v%s);"
% ("->generalize()" if mapping.is_templated_list(type) else "")
),
)
if mapping.simple_type_parent(class_name) is None
else ("v", "", constructor, "", ("%s v" % type_str,), "")
),
("", "", templates.cast_function, type_str, (), simpletype_impl_cast), ("", "", templates.cast_function, type_str, (), simpletype_impl_cast),
), ),
), ),
@@ -25,6 +25,7 @@ import schema
from header import USE_VIRTUAL_INHERITANCE from header import USE_VIRTUAL_INHERITANCE
class Mapping: class Mapping:
express_to_cpp_typemapping = { express_to_cpp_typemapping = {
@@ -23,6 +23,7 @@ import operator
import collections import collections
import bootstrap import bootstrap
class Node: class Node:
def __init__(self, s, loc, tokens, rule=None): def __init__(self, s, loc, tokens, rule=None):
self.rule = rule or (type(self).__name__) self.rule = rule or (type(self).__name__)
@@ -58,7 +59,7 @@ class ListNode:
rules_as_list = set() rules_as_list = set()
for t in self.tokens: for t in self.tokens:
r = getattr(t, 'rule', None) r = getattr(t, "rule", None)
if r: if r:
rules_as_list.add(r) rules_as_list.add(r)
self.dict_tokens[r].append(t) self.dict_tokens[r].append(t)
@@ -245,7 +246,8 @@ class NamedType(Node):
def do_try(fn): def do_try(fn):
try: try:
return fn() return fn()
except: pass except:
pass
def get_rule_id(x): def get_rule_id(x):
@@ -255,8 +257,14 @@ def get_rule_id(x):
if matches: if matches:
return matches[0] return matches[0]
rule_dependencies = { rule_dependencies = {
k: list(map(operator.attrgetter('contents'), bootstrap.reduce(lambda x, y: x | y, (bootstrap.find_bytype(e, bootstrap.Keyword) for e in [v])))) \ k: list(
map(
operator.attrgetter("contents"),
bootstrap.reduce(lambda x, y: x | y, (bootstrap.find_bytype(e, bootstrap.Keyword) for e in [v])),
)
)
for k, v in bootstrap.express for k, v in bootstrap.express
} }
@@ -264,6 +272,7 @@ all_rules = [k for k, e in bootstrap.express]
rule_definitions = {k: v for k, v in bootstrap.express} rule_definitions = {k: v for k, v in bootstrap.express}
def to_tree(x, key=None): def to_tree(x, key=None):
def prune(di): def prune(di):
@@ -273,7 +282,7 @@ def to_tree(x, key=None):
def replace_synonyms(x): def replace_synonyms(x):
for y in x: for y in x:
yield y yield y
if False: # y in di: if False: # y in di:
# production element from grammar is found in parsed data, # production element from grammar is found in parsed data,
# return that. # return that.
@@ -299,12 +308,14 @@ def to_tree(x, key=None):
# but should probably also work on # but should probably also work on
# - a = b { b } # - a = b { b }
# in which case the second Concat would be eliminated # in which case the second Concat would be eliminated
elif isinstance(rule, bootstrap.Concat) and \ elif (
len(rule.contents) == 2 and \ isinstance(rule, bootstrap.Concat)
is_synonym(rule.contents[0]) and \ and len(rule.contents) == 2
isinstance(rule.contents[1].contents, bootstrap.Repeated) and \ and is_synonym(rule.contents[0])
isinstance(rule.contents[1].contents.contents[0], bootstrap.Concat) and \ and isinstance(rule.contents[1].contents, bootstrap.Repeated)
str(rule.contents[1].contents.contents[0].contents[1]) == str(rule.contents[0]): and isinstance(rule.contents[1].contents.contents[0], bootstrap.Concat)
and str(rule.contents[1].contents.contents[0].contents[1]) == str(rule.contents[0])
):
S = is_synonym(rule.contents[0]) S = is_synonym(rule.contents[0])
yield S yield S
# Do this recursively # Do this recursively
@@ -347,7 +358,7 @@ def to_tree(x, key=None):
if isinstance(x, ListNode): if isinstance(x, ListNode):
d = to_tree(x.dict_tokens, key=get_rule_id(x) or key) d = to_tree(x.dict_tokens, key=get_rule_id(x) or key)
if key == 'if_stmt': if key == "if_stmt":
# The definition of if statement if (roughy): # The definition of if statement if (roughy):
# 'if' expr 'then' stmt+ 'else' stmt+ # 'if' expr 'then' stmt+ 'else' stmt+
# this causes stmt to be joined under the same # this causes stmt to be joined under the same
@@ -355,39 +366,41 @@ def to_tree(x, key=None):
# `else_stmt` that collects the second group # `else_stmt` that collects the second group
# of stmts. # of stmts.
statements = x.dict_tokens['stmt'] statements = x.dict_tokens["stmt"]
else_index = None else_index = None
if_nesting = 0 if_nesting = 0
for i, tk in enumerate(x.flat): for i, tk in enumerate(x.flat):
if tk == 'if': if_nesting += 1 if tk == "if":
if tk == 'end_if': if_nesting -= 1 if_nesting += 1
if tk == 'else' and if_nesting == 1: if tk == "end_if":
if_nesting -= 1
if tk == "else" and if_nesting == 1:
else_index = i else_index = i
if else_index: if else_index:
indices = [] indices = []
for s in statements: for s in statements:
for i in range(max(indices, default=0), len(x.flat)): for i in range(max(indices, default=0), len(x.flat)):
if x.flat[i:i+len(s.flat)] == s.flat: if x.flat[i : i + len(s.flat)] == s.flat:
indices.append(i) indices.append(i)
break break
assert len(indices) == len(statements) assert len(indices) == len(statements)
before_else = [i < else_index for i in indices] before_else = [i < else_index for i in indices]
else_stmt = [st for b, st in zip(before_else, d['stmt']) if not b] else_stmt = [st for b, st in zip(before_else, d["stmt"]) if not b]
d['stmt'] = [st for b, st in zip(before_else, d['stmt']) if b] d["stmt"] = [st for b, st in zip(before_else, d["stmt"]) if b]
if else_stmt: if else_stmt:
d['else_stmt'] = else_stmt d["else_stmt"] = else_stmt
if key == 'formal_parameter': if key == "formal_parameter":
# Not so pretty hack to fix the overwriting of simple_id-like # Not so pretty hack to fix the overwriting of simple_id-like
# ast nodes. The full solution would probably to register parse # ast nodes. The full solution would probably to register parse
# actions. And directly reassign. # actions. And directly reassign.
pid = d['parameter_id'][0][0] pid = d["parameter_id"][0][0]
d['parameter_id'][0] = x.flat[:x.flat.index(pid)+1:2] d["parameter_id"][0] = x.flat[: x.flat.index(pid) + 1 : 2]
if key is None: if key is None:
return {get_rule_id(x): d} return {get_rule_id(x): d}
@@ -400,7 +413,10 @@ def to_tree(x, key=None):
elif isinstance(x, dict): elif isinstance(x, dict):
# d = {k: to_tree(v, key=k) for k, v in x.items()} # d = {k: to_tree(v, key=k) for k, v in x.items()}
# not fully understood, but when finding specific node Types and production rules, prioritize the former # not fully understood, but when finding specific node Types and production rules, prioritize the former
d = {get_rule_id(k) or k: to_tree(v, key=k) for k, v in sorted(x.items(), key=lambda p: get_rule_id(p[0]) is not None)} d = {
get_rule_id(k) or k: to_tree(v, key=k)
for k, v in sorted(x.items(), key=lambda p: get_rule_id(p[0]) is not None)
}
return simplify(prune(d)) return simplify(prune(d))
elif isinstance(x, list): elif isinstance(x, list):
return [to_tree(v, key=key) for v in x] return [to_tree(v, key=key) for v in x]
@@ -459,7 +475,8 @@ class SuperTypeExpression(Node):
else: else:
constraint = self.supertype_rule[0] constraint = self.supertype_rule[0]
return [ return [
list(list(s)[0])[0].simple_id for s in list(list(list(constraint.subtype_constraint[0].supertype_expression[0])[0])[0].one_of[0])[2::2] list(list(s)[0])[0].simple_id
for s in list(list(list(constraint.subtype_constraint[0].supertype_expression[0])[0])[0].one_of[0])[2::2]
] ]
sub_types = property(get_sub_types) sub_types = property(get_sub_types)
@@ -581,5 +598,6 @@ class ProcedureDeclaration(ListNode):
class FunctionDeclaration(ProcedureDeclaration): class FunctionDeclaration(ProcedureDeclaration):
pass pass
class RuleDeclaration(ProcedureDeclaration): class RuleDeclaration(ProcedureDeclaration):
pass pass
@@ -48,11 +48,7 @@ def to_graph(tree):
# bootstrap.py that result in an intermediate list index node in to_tree() # bootstrap.py that result in an intermediate list index node in to_tree()
# Start with the intermediate nodes and filter out root (needs to have predecessors) # Start with the intermediate nodes and filter out root (needs to have predecessors)
intermediate = [ intermediate = [n for n in g.nodes if g.nodes[n].get("label") is None and list(g.predecessors(n))]
n
for n in g.nodes
if g.nodes[n].get("label") is None and list(g.predecessors(n))
]
for n in intermediate: for n in intermediate:
pr = list(g.predecessors(n)) pr = list(g.predecessors(n))
@@ -82,8 +78,7 @@ def to_graph(tree):
for n in g.nodes: for n in g.nodes:
if ( if (
len(list(g.successors(n))) == 0 len(list(g.successors(n))) == 0
and g.nodes[n].get("label") and g.nodes[n].get("label") not in ifcopenshell.express.express_parser.all_rules
not in ifcopenshell.express.express_parser.all_rules
): ):
g.nodes[n]["is_terminal"] = True g.nodes[n]["is_terminal"] = True
@@ -105,8 +100,7 @@ def write_dot(fn, g):
def format(di): def format(di):
Q = '"' Q = '"'
inner = ",".join( inner = ",".join(
f"{k}={'' if v.startswith('<') else Q}{v}{'' if v.startswith('<') else Q}" f"{k}={'' if v.startswith('<') else Q}{v}{'' if v.startswith('<') else Q}" for k, v in di.items()
for k, v in di.items()
) )
if inner: if inner:
inner = f"[{inner}]" inner = f"[{inner}]"
@@ -179,9 +173,7 @@ class context:
def has_inverse(self, a): def has_inverse(self, a):
for r in self.rules: for r in self.rules:
if a in map( if a in map(lambda n: self.graph.nodes[n].get("label"), self.graph.predecessors(r)):
lambda n: self.graph.nodes[n].get("label"), self.graph.predecessors(r)
):
return True return True
return False return False
@@ -190,10 +182,7 @@ class context:
yield context(self.graph, [r]) yield context(self.graph, [r])
def descendants(self): def descendants(self):
return [ return [b.rules[0][len(self.rules[0]) + 1 :] for b in self.branches(allow_multiple=True)]
b.rules[0][len(self.rules[0]) + 1 :]
for b in self.branches(allow_multiple=True)
]
def __repr__(self): def __repr__(self):
try: try:
@@ -206,14 +195,11 @@ class context:
assert len(self.rules) == 1 assert len(self.rules) == 1
nodes = itertools.chain( nodes = itertools.chain(
self.rules, self.rules,
itertools.chain.from_iterable( itertools.chain.from_iterable(dict(nx.bfs_successors(self.graph, self.rules[0])).values()),
dict(nx.bfs_successors(self.graph, self.rules[0])).values()
),
) )
terminals_or_values = list( terminals_or_values = list(
filter( filter(
lambda n: self.graph.nodes[n].get("is_terminal") lambda n: self.graph.nodes[n].get("is_terminal") or self.graph.nodes[n].get("value"),
or self.graph.nodes[n].get("value"),
nodes, nodes,
) )
) )
@@ -375,9 +361,7 @@ def calc_{class_name}_{str(derived_attr.attribute_decl.redeclared_attribute.qual
""" """
if context.entity_body.derive_clause: if context.entity_body.derive_clause:
statements.extend( statements.extend(map(format_derived, context.entity_body.derive_clause.branches()))
map(format_derived, context.entity_body.derive_clause.branches())
)
return "\n\n".join(statements) return "\n\n".join(statements)
@@ -420,10 +404,12 @@ def process_expression(context):
exclude=[context.rel_op_extended], exclude=[context.rel_op_extended],
) )
else: else:
if len(context.simple_expression.branches()) == 2 and str(context.rel_op_extended) == 'in': if len(context.simple_expression.branches()) == 2 and str(context.rel_op_extended) == "in":
# IfcBlobTexture # IfcBlobTexture
try: try:
is_literal_str_list = set(map(type, ast.literal_eval(str(context.simple_expression.branches()[1])))) == {str} is_literal_str_list = set(
map(type, ast.literal_eval(str(context.simple_expression.branches()[1])))
) == {str}
except: except:
is_literal_str_list = False is_literal_str_list = False
if is_literal_str_list: if is_literal_str_list:
@@ -567,9 +553,7 @@ def process_function_decl(context):
str.lower, str.lower,
map( map(
str, str,
context.function_head.formal_parameter.parameter_id.branches( context.function_head.formal_parameter.parameter_id.branches(allow_multiple=True),
allow_multiple=True
),
), ),
) )
return f"def {context.function_head.function_id}({', '.join(arguments)}):\n{indent(4, context.algorithm_head.local_decl)}\n{indent(4, context.stmt.branches())}" return f"def {context.function_head.function_id}({', '.join(arguments)}):\n{indent(4, context.algorithm_head.local_decl)}\n{indent(4, context.stmt.branches())}"
@@ -582,9 +566,7 @@ def process_query(context):
def process_local_variable(context): def process_local_variable(context):
if context.expression: if context.expression:
expr = str(context.expression) expr = str(context.expression)
if ( if context.parameter_type.generalized_types.general_aggregation_types.general_set_type:
context.parameter_type.generalized_types.general_aggregation_types.general_set_type
):
expr = re.sub(r"(\[[^\]]*\])", "express_set(\\1)", expr) expr = re.sub(r"(\[[^\]]*\])", "express_set(\\1)", expr)
return "%s = %s" % (str(context.variable_id).lower(), expr) return "%s = %s" % (str(context.variable_id).lower(), expr)
@@ -623,9 +605,7 @@ def process_assignment(context):
if m := re.match(r"^([^\[]+)\[([^\[]+)\]$", lhs): if m := re.match(r"^([^\[]+)\[([^\[]+)\]$", lhs):
# @todo ugly regex hack # @todo ugly regex hack
aggr, index = m.groups() aggr, index = m.groups()
return ( return f"temp = list({aggr})\ntemp[{index}] = {context.expression}\n{aggr} = temp"
f"temp = list({aggr})\ntemp[{index}] = {context.expression}\n{aggr} = temp"
)
else: else:
return "%s = %s" % (lhs, context.expression) return "%s = %s" % (lhs, context.expression)
@@ -643,11 +623,7 @@ def process_case_action(context):
def process_case_statement(context): def process_case_statement(context):
branches = context.branches( branches = context.branches(
exclude=[ exclude=[getattr(context, v) for v in context.descendants() if not v.startswith("case_action")]
getattr(context, v)
for v in context.descendants()
if not v.startswith("case_action")
]
) )
if context.stmt and context.stmt.branches(): if context.stmt and context.stmt.branches():
branches += [f"else:\n{indent(4, context.stmt)}"] branches += [f"else:\n{indent(4, context.stmt)}"]
@@ -658,9 +634,7 @@ def process_aggregate_initializer(context):
if context.element.repetition: if context.element.repetition:
return "([%s] * %s)" % (context.element.expression, context.element.repetition) return "([%s] * %s)" % (context.element.expression, context.element.repetition)
else: else:
return "[%s]" % ",".join( return "[%s]" % ",".join(map(str, context.element.branches() if context.element else ()))
map(str, context.element.branches() if context.element else ())
)
def process_index(context): def process_index(context):
@@ -676,9 +650,7 @@ def process_index(context):
codegen_rule("function_call", process_function_call) codegen_rule("function_call", process_function_call)
codegen_rule( codegen_rule(
"actual_parameter_list", "actual_parameter_list",
lambda context: ",".join( lambda context: ",".join(map(str, context.expression.branches() if context.expression else [])),
map(str, context.expression.branches() if context.expression else [])
),
) )
codegen_rule("entity_decl", functools.partial(process_type_decl, "entity")) codegen_rule("entity_decl", functools.partial(process_type_decl, "entity"))
codegen_rule("rule_decl", process_rule_decl) codegen_rule("rule_decl", process_rule_decl)
@@ -696,9 +668,7 @@ codegen_rule("simple_factor", simple_concat)
codegen_rule("primary", simple_concat) codegen_rule("primary", simple_concat)
codegen_rule("qualifier", simple_concat) codegen_rule("qualifier", simple_concat)
codegen_rule("return_stmt", lambda context: "return %s" % context) codegen_rule("return_stmt", lambda context: "return %s" % context)
codegen_rule( codegen_rule("compound_stmt", lambda context: "\n".join(map(str, context.stmt.branches())))
"compound_stmt", lambda context: "\n".join(map(str, context.stmt.branches()))
)
codegen_rule("if_stmt", process_if_stmt) codegen_rule("if_stmt", process_if_stmt)
codegen_rule("repeat_stmt", process_repeat_stmt) codegen_rule("repeat_stmt", process_repeat_stmt)
# codegen_rule("index", lambda context: '**express_index(%s)' % context) # codegen_rule("index", lambda context: '**express_index(%s)' % context)
@@ -707,19 +677,14 @@ codegen_rule("index_qualifier", process_index)
codegen_rule("group_qualifier", lambda context: empty()) codegen_rule("group_qualifier", lambda context: empty())
codegen_rule("attribute_qualifier", lambda context: ".%s" % context) codegen_rule("attribute_qualifier", lambda context: ".%s" % context)
codegen_rule("rel_op", process_rel_op) codegen_rule("rel_op", process_rel_op)
codegen_rule( codegen_rule("built_in_constant", lambda context: "None" if str(context) == "?" else str(context))
"built_in_constant", lambda context: "None" if str(context) == "?" else str(context)
)
codegen_rule("assignment_stmt", process_assignment) codegen_rule("assignment_stmt", process_assignment)
codegen_rule("local_variable", process_local_variable) codegen_rule("local_variable", process_local_variable)
codegen_rule("local_decl", lambda context: "\n".join(map(str, context.branches()))) codegen_rule("local_decl", lambda context: "\n".join(map(str, context.branches())))
codegen_rule("general_ref/parameter_ref", make_lowercase) codegen_rule("general_ref/parameter_ref", make_lowercase)
codegen_rule( codegen_rule(
"qualifiable_factor/attribute_ref", "qualifiable_factor/attribute_ref",
make_lowercase_if( make_lowercase_if(lambda context: str(context) not in set(map(str, schema.all_declarations.keys()))),
lambda context: str(context)
not in set(map(str, schema.all_declarations.keys()))
),
) )
codegen_rule("case_action", process_case_action) codegen_rule("case_action", process_case_action)
codegen_rule("case_stmt", process_case_statement) codegen_rule("case_stmt", process_case_statement)
@@ -1056,13 +1021,13 @@ INDETERMINATE = indeterminate_type()
if isinstance(v, str): if isinstance(v, str):
nl = "\n" nl = "\n"
es = "\\n" es = "\\n"
n[ n["label"] = (
"label" f'<<table cellborder="0" cellpadding="0"><tr><td><b>{n.get("label")}</b></td></tr><tr><td align="left" balign="left">{v.replace("<", "&lt;").replace(">", "&gt;").replace(nl, "<br/>")}</td></tr></table>>'
] = f'<<table cellborder="0" cellpadding="0"><tr><td><b>{n.get("label")}</b></td></tr><tr><td align="left" balign="left">{v.replace("<", "&lt;").replace(">", "&gt;").replace(nl, "<br/>")}</td></tr></table>>' )
elif isinstance(v, empty): elif isinstance(v, empty):
n[ n["label"] = (
"label" f'<<table cellborder="0" cellpadding="0"><tr><td><b>{n.get("label")}</b></td></tr><tr><td align="left" balign="left">---</td></tr></table>>'
] = f'<<table cellborder="0" cellpadding="0"><tr><td><b>{n.get("label")}</b></td></tr><tr><td align="left" balign="left">---</td></tr></table>>' )
fn = f"{nm}.dot" fn = f"{nm}.dot"
write_dot(fn, G) write_dot(fn, G)
@@ -27,6 +27,7 @@ if tuple(map(int, platform.python_version_tuple())) < (2, 7):
collections.OrderedDict = ordereddict.OrderedDict collections.OrderedDict = ordereddict.OrderedDict
# According to ISO 10303-11 7.1.2: Letters: "... The case of # According to ISO 10303-11 7.1.2: Letters: "... The case of
# letters is significant only within explicit string literals." # letters is significant only within explicit string literals."
class OrderedCaseInsensitiveDict_KeyObject(str): class OrderedCaseInsensitiveDict_KeyObject(str):
@@ -92,14 +93,8 @@ class Schema:
sort = lambda d: OrderedCaseInsensitiveDict(sorted(d)) sort = lambda d: OrderedCaseInsensitiveDict(sorted(d))
declarations = [ declarations = [d.any()[0] for d in schema_declarations if d.rule == "declaration"] + [
d.any()[0] d for d in schema_declarations if d.rule == "RuleDeclaration"
for d in schema_declarations
if d.rule == "declaration"
] + [
d
for d in schema_declarations
if d.rule == "RuleDeclaration"
] ]
self.types = sort([(t.name, t) for t in declarations if isinstance(t, nodes.TypeDeclaration)]) self.types = sort([(t.name, t) for t in declarations if isinstance(t, nodes.TypeDeclaration)])
@@ -107,8 +102,12 @@ class Schema:
self.rules = sort([(t.name, t) for t in declarations if isinstance(t, nodes.RuleDeclaration)]) self.rules = sort([(t.name, t) for t in declarations if isinstance(t, nodes.RuleDeclaration)])
self.functions = sort([(t.name, t) for t in declarations if isinstance(t, nodes.FunctionDeclaration)]) self.functions = sort([(t.name, t) for t in declarations if isinstance(t, nodes.FunctionDeclaration)])
self.keys = list(self.types.keys()) + list(self.entities.keys()) + list(self.rules.keys()) + list(self.functions.keys()) self.keys = (
self.all_declarations = {k: v for d in (self.types, self.entities, self.rules, self.functions) for k, v in d.items()} list(self.types.keys()) + list(self.entities.keys()) + list(self.rules.keys()) + list(self.functions.keys())
)
self.all_declarations = {
k: v for d in (self.types, self.entities, self.rules, self.functions) for k, v in d.items()
}
of_type = lambda *types: sort( of_type = lambda *types: sort(
[(a, b.type) for a, b in self.types.items() if any(isinstance(b.type, ty) for ty in types)] [(a, b.type) for a, b in self.types.items() if any(isinstance(b.type, ty) for ty in types)]
@@ -123,6 +123,7 @@ class string_pool:
def __init__(self, fn): def __init__(self, fn):
self.di = {} self.di = {}
self.fn = fn self.fn = fn
def append(self, v): def append(self, v):
def _(): def _():
if i := self.di.get(v): if i := self.di.get(v):
@@ -131,7 +132,9 @@ class string_pool:
i = len(self.di) i = len(self.di)
self.di[v] = i self.di[v] = i
return i return i
return self.fn(_()) return self.fn(_())
def __iter__(self): def __iter__(self):
return iter(self.di.keys()) return iter(self.di.keys())
@@ -146,9 +149,9 @@ class EarlyBoundCodeWriter:
"", "",
'#include "../ifcparse/IfcSchema.h"', '#include "../ifcparse/IfcSchema.h"',
'#include "../ifcparse/%(schema_name_title)s.h"' % self.__dict__, '#include "../ifcparse/%(schema_name_title)s.h"' % self.__dict__,
'#include <string>', "#include <string>",
"", "",
'using namespace std::string_literals;', "using namespace std::string_literals;",
"using namespace IfcParse;", "using namespace IfcParse;",
"", "",
] ]
@@ -180,18 +183,18 @@ class EarlyBoundCodeWriter:
self.statements.append("{factory_placeholder}") self.statements.append("{factory_placeholder}")
# self.statements.append( # self.statements.append(
# """ # """
# #if defined(__clang__) # #if defined(__clang__)
# __attribute__((optnone)) # __attribute__((optnone))
# #elif defined(__GNUC__) || defined(__GNUG__) # #elif defined(__GNUC__) || defined(__GNUG__)
# #pragma GCC push_options # #pragma GCC push_options
# #pragma GCC optimize ("O0") # #pragma GCC optimize ("O0")
# #elif defined(_MSC_VER) # #elif defined(_MSC_VER)
# #pragma optimize("", off) # #pragma optimize("", off)
# #endif # #endif
# """ # """
# ) # )
self.statements.append("IfcParse::schema_definition* %s_populate_schema() {" % self.schema_name.upper()) self.statements.append("IfcParse::schema_definition* %s_populate_schema() {" % self.schema_name.upper())
self.statements.append("{string_pool_placeholder}") self.statements.append("{string_pool_placeholder}")
@@ -200,7 +203,7 @@ class EarlyBoundCodeWriter:
index_in_schema = self.names.index(name) index_in_schema = self.names.index(name)
ref = self.strings.append(name) ref = self.strings.append(name)
self.statements.append( self.statements.append(
' %(schema_name)s_types[%(index_in_schema)d] = new type_declaration(%(ref)s, %(index_in_schema)d, %(declared_type)s);' " %(schema_name)s_types[%(index_in_schema)d] = new type_declaration(%(ref)s, %(index_in_schema)d, %(declared_type)s);"
% locals() % locals()
) )
@@ -210,7 +213,7 @@ class EarlyBoundCodeWriter:
ref = self.strings.append(name) ref = self.strings.append(name)
items = ",".join(self.strings.append(v) for v in enum.values) items = ",".join(self.strings.append(v) for v in enum.values)
self.statements.append( self.statements.append(
' %(schema_name)s_types[%(index_in_schema)d] = new enumeration_type(%(ref)s, %(index_in_schema)d, {%(items)s});' " %(schema_name)s_types[%(index_in_schema)d] = new enumeration_type(%(ref)s, %(index_in_schema)d, {%(items)s});"
% locals() % locals()
) )
@@ -218,10 +221,14 @@ class EarlyBoundCodeWriter:
schema_name = self.schema_name.upper() schema_name = self.schema_name.upper()
index_in_schema = self.names.index(name) index_in_schema = self.names.index(name)
ref = self.strings.append(name) ref = self.strings.append(name)
supertype = "0" if len(type.supertypes) == 0 else "%s_types[%d]" % (self.schema_name, self.names.index(type.supertypes[0])) supertype = (
"0"
if len(type.supertypes) == 0
else "%s_types[%d]" % (self.schema_name, self.names.index(type.supertypes[0]))
)
is_abstract = "true" if type.abstract else "false" is_abstract = "true" if type.abstract else "false"
self.statements.append( self.statements.append(
' %(schema_name)s_types[%(index_in_schema)d] = new entity(%(ref)s, %(is_abstract)s, %(index_in_schema)d, (entity*) %(supertype)s);' " %(schema_name)s_types[%(index_in_schema)d] = new entity(%(ref)s, %(is_abstract)s, %(index_in_schema)d, (entity*) %(supertype)s);"
% locals() % locals()
) )
@@ -233,73 +240,89 @@ class EarlyBoundCodeWriter:
map(lambda v: "%s_types[%d]" % (self.schema_name, self.names.index(v)), sorted(map(str, type.values))) map(lambda v: "%s_types[%d]" % (self.schema_name, self.names.index(v)), sorted(map(str, type.values)))
) )
self.statements.append( self.statements.append(
' %(schema_name)s_types[%(index_in_schema)d] = new select_type(%(ref)s, %(index_in_schema)d, {%(items)s});' " %(schema_name)s_types[%(index_in_schema)d] = new select_type(%(ref)s, %(index_in_schema)d, {%(items)s});"
% locals() % locals()
) )
def entity_attributes(self, name, attribute_definitions, is_derived): def entity_attributes(self, name, attribute_definitions, is_derived):
schema_name = self.schema_name.upper() schema_name = self.schema_name.upper()
index_in_schema = self.names.index(name) index_in_schema = self.names.index(name)
def _(): def _():
index_in_schema = self.names.index(name) index_in_schema = self.names.index(name)
schema_name = self.schema_name schema_name = self.schema_name
for attr_name, decl_type, optional in attribute_definitions: for attr_name, decl_type, optional in attribute_definitions:
attr_name_ref = self.strings.append(attr_name) attr_name_ref = self.strings.append(attr_name)
optional_cpp = str(optional).lower() optional_cpp = str(optional).lower()
yield 'new attribute(%(attr_name_ref)s, %(decl_type)s, %(optional_cpp)s)' % locals() yield "new attribute(%(attr_name_ref)s, %(decl_type)s, %(optional_cpp)s)" % locals()
attributes = ",".join(_()) attributes = ",".join(_())
derived = ",".join(map(lambda b: str(b).lower(), is_derived)) derived = ",".join(map(lambda b: str(b).lower(), is_derived))
self.statements.append(" ((entity*)%(schema_name)s_types[%(index_in_schema)d])->set_attributes({%(attributes)s}, {%(derived)s});" % locals()) self.statements.append(
" ((entity*)%(schema_name)s_types[%(index_in_schema)d])->set_attributes({%(attributes)s}, {%(derived)s});"
% locals()
)
def inverse_attributes(self, name, inv_attrs): def inverse_attributes(self, name, inv_attrs):
schema_name = self.schema_name.upper() schema_name = self.schema_name.upper()
index_in_schema = self.names.index(name) index_in_schema = self.names.index(name)
def _(): def _():
schema_name = self.schema_name schema_name = self.schema_name
index_in_schema = self.names.index(name) index_in_schema = self.names.index(name)
for attr_name, aggr_type, bound1, bound2, entity_ref, attribute_entity, attribute_entity_index in inv_attrs: for attr_name, aggr_type, bound1, bound2, entity_ref, attribute_entity, attribute_entity_index in inv_attrs:
attr_name_ref = self.strings.append(attr_name) attr_name_ref = self.strings.append(attr_name)
opposite_index_in_schema = self.names.index(entity_ref) opposite_index_in_schema = self.names.index(entity_ref)
opposite1 = '%(schema_name)s_types[%(opposite_index_in_schema)d]' % locals() opposite1 = "%(schema_name)s_types[%(opposite_index_in_schema)d]" % locals()
opposite_index_in_schema = self.names.index(attribute_entity) opposite_index_in_schema = self.names.index(attribute_entity)
opposite2 = '%(schema_name)s_types[%(opposite_index_in_schema)d]' % locals() opposite2 = "%(schema_name)s_types[%(opposite_index_in_schema)d]" % locals()
yield 'new inverse_attribute(%(attr_name_ref)s, inverse_attribute::%(aggr_type)s_type, %(bound1)d, %(bound2)d, ((entity*) %(opposite1)s), ((entity*) %(opposite2)s)->attributes()[%(attribute_entity_index)d])' % locals() yield "new inverse_attribute(%(attr_name_ref)s, inverse_attribute::%(aggr_type)s_type, %(bound1)d, %(bound2)d, ((entity*) %(opposite1)s), ((entity*) %(opposite2)s)->attributes()[%(attribute_entity_index)d])" % locals()
attributes = ",".join(_()) attributes = ",".join(_())
self.statements.append(" ((entity*) %(schema_name)s_types[%(index_in_schema)d])->set_inverse_attributes({%(attributes)s});" % locals()) self.statements.append(
" ((entity*) %(schema_name)s_types[%(index_in_schema)d])->set_inverse_attributes({%(attributes)s});"
% locals()
)
def entity_subtypes(self, name, tys): def entity_subtypes(self, name, tys):
schema_name = self.schema_name.upper() schema_name = self.schema_name.upper()
index_in_schema = self.names.index(name) index_in_schema = self.names.index(name)
subtypes = ",".join(map(lambda t: ("((entity*) %%(schema_name)s_types[%d])" % self.names.index(t)), tys)) % locals() subtypes = (
self.statements.append(" ((entity*) %(schema_name)s_types[%(index_in_schema)d])->set_subtypes({%(subtypes)s});" % locals()) ",".join(map(lambda t: ("((entity*) %%(schema_name)s_types[%d])" % self.names.index(t)), tys)) % locals()
)
self.statements.append(
" ((entity*) %(schema_name)s_types[%(index_in_schema)d])->set_subtypes({%(subtypes)s});" % locals()
)
def finalize(self, can_be_instantiated_set): def finalize(self, can_be_instantiated_set):
schema_name = self.schema_name.upper() schema_name = self.schema_name.upper()
schema_name_title = self.schema_name.capitalize() schema_name_title = self.schema_name.capitalize()
def _(): def _():
schema_name = self.schema_name.upper() schema_name = self.schema_name.upper()
schema_name_title = self.schema_name.capitalize() schema_name_title = self.schema_name.capitalize()
for type_name in self.names: for type_name in self.names:
index_in_schema = self.names.index(type_name) index_in_schema = self.names.index(type_name)
yield "%(schema_name)s_types[%(index_in_schema)d]" % locals() yield "%(schema_name)s_types[%(index_in_schema)d]" % locals()
declarations = ",".join(_()) declarations = ",".join(_())
schema_name_ref = self.strings.append(schema_name) schema_name_ref = self.strings.append(schema_name)
self.statements.append( self.statements.append(
' return new schema_definition(%(schema_name_ref)s, {%(declarations)s}, new %(schema_name)s_instance_factory());' " return new schema_definition(%(schema_name_ref)s, {%(declarations)s}, new %(schema_name)s_instance_factory());"
% locals() % locals()
) )
self.statements.append("}"); self.statements.append("}")
# self.statements.append( # self.statements.append(
# """ # """
# #if defined(__clang__) # #if defined(__clang__)
# #elif defined(__GNUC__) || defined(__GNUG__) # #elif defined(__GNUC__) || defined(__GNUG__)
# #pragma GCC pop_options # #pragma GCC pop_options
# #elif defined(_MSC_VER) # #elif defined(_MSC_VER)
# #pragma optimize("", on) # #pragma optimize("", on)
# #endif # #endif
# """ # """
# ) # )
self.statements.extend( self.statements.extend(
( (
@@ -340,24 +363,18 @@ class EarlyBoundCodeWriter:
) )
) )
self.statements[self.statements.index("{factory_placeholder}")] = ( self.statements[self.statements.index("{factory_placeholder}")] = """
"""
class %(schema_name)s_instance_factory : public IfcParse::instance_factory { class %(schema_name)s_instance_factory : public IfcParse::instance_factory {
virtual IfcUtil::IfcBaseClass* operator()(const IfcParse::declaration* decl, IfcEntityInstanceData&& data) const { virtual IfcUtil::IfcBaseClass* operator()(const IfcParse::declaration* decl, IfcEntityInstanceData&& data) const {
%(instance_mapping)s %(instance_mapping)s
} }
}; };
""" """ % locals()
% locals()
)
"" ""
self.statements[self.statements.index("{string_pool_placeholder}")] = ( self.statements[self.statements.index("{string_pool_placeholder}")] = """
"""
const std::string strings[] = {%s}; const std::string strings[] = {%s};
""" """ % ",".join(map(lambda s: '"%s"s' % s, self.strings))
% ",".join(map(lambda s: '"%s"s' % s, self.strings))
)
def __str__(self): def __str__(self):
return "\n".join(self.statements) return "\n".join(self.statements)
@@ -379,16 +396,19 @@ class SchemaClass(codegen.Base):
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
schema_name_upper = mapping.schema.name.upper() schema_name_upper = mapping.schema.name.upper()
declared_type = fn(*args, **kwargs) declared_type = fn(*args, **kwargs)
if 'simple_type' in declared_type: if "simple_type" in declared_type:
pass pass
else: else:
match = re.search(r'\((\w+?_[\w+]+?_\w+?)\)', declared_type) match = re.search(r"\((\w+?_[\w+]+?_\w+?)\)", declared_type)
if match: if match:
old_decl = match.group(1) old_decl = match.group(1)
name = old_decl.lower().replace(schema_name.lower() + '_', '').replace('_type', '') name = old_decl.lower().replace(schema_name.lower() + "_", "").replace("_type", "")
idx = [n.lower() for n in x.names].index(name) idx = [n.lower() for n in x.names].index(name)
declared_type = declared_type.replace(old_decl, '%(schema_name_upper)s_types[%(idx)d]' % locals()) declared_type = declared_type.replace(
old_decl, "%(schema_name_upper)s_types[%(idx)d]" % locals()
)
return declared_type return declared_type
return wrapper if code == EarlyBoundCodeWriter else fn return wrapper if code == EarlyBoundCodeWriter else fn
@transform_to_indexed @transform_to_indexed
@@ -255,32 +255,16 @@ get_attr_stmt_nested_array = "%(null_check)s aggregate_of_aggregate_of_instance:
get_inverse = "if (!file_) { return nullptr; } return file_->getInverse(id_, %(schema_name_upper)s_types[%(type_index)d], %(index)d)->as<%(type)s>();" get_inverse = "if (!file_) { return nullptr; } return file_->getInverse(id_, %(schema_name_upper)s_types[%(type_index)d], %(index)d)->as<%(type)s>();"
set_attr_stmt = ( set_attr_stmt = "%(check_optional_set_begin)sset_attribute_value(%(index)d, %(star_if_optional)sv);%(check_optional_set_else)sunset_attribute_value(%(index)d);%(check_optional_set_end)s"
"%(check_optional_set_begin)sset_attribute_value(%(index)d, %(star_if_optional)sv);%(check_optional_set_else)sunset_attribute_value(%(index)d);%(check_optional_set_end)s" set_attr_instance = "%(check_optional_set_begin)sset_attribute_value(%(index)d, v->as<IfcUtil::IfcBaseClass>());%(check_optional_set_else)sunset_attribute_value(%(index)d);%(check_optional_set_end)s"
) set_attr_stmt_enum = "%(check_optional_set_begin)sset_attribute_value(%(index)d, EnumerationReference(&%(non_optional_type)s::Class(), (size_t) %(star_if_optional)sv));%(check_optional_set_else)sunset_attribute_value(%(index)d);%(check_optional_set_end)s"
set_attr_instance = ( set_attr_stmt_array = "%(check_optional_set_begin)sset_attribute_value(%(index)d, (%(star_if_optional)sv)->generalize());%(check_optional_set_else)sunset_attribute_value(%(index)d);%(check_optional_set_end)s"
"%(check_optional_set_begin)sset_attribute_value(%(index)d, v->as<IfcUtil::IfcBaseClass>());%(check_optional_set_else)sunset_attribute_value(%(index)d);%(check_optional_set_end)s"
)
set_attr_stmt_enum = "%(check_optional_set_begin)sset_attribute_value(%(index)d, EnumerationReference(&%(non_optional_type)s::Class(), (size_t) %(star_if_optional)sv));%(check_optional_set_else)sunset_attribute_value(%(index)d);%(check_optional_set_end)s"
set_attr_stmt_array = (
"%(check_optional_set_begin)sset_attribute_value(%(index)d, (%(star_if_optional)sv)->generalize());%(check_optional_set_else)sunset_attribute_value(%(index)d);%(check_optional_set_end)s"
)
constructor_stmt = ( constructor_stmt = "set_attribute_value(%(index)d, (%(name)s));"
"set_attribute_value(%(index)d, (%(name)s));" constructor_stmt_enum = "set_attribute_value(%(index)d, (EnumerationReference(&%(type)s::Class(),(size_t)%(name)s)));"
) constructor_stmt_array = "set_attribute_value(%(index)d, (%(name)s)->generalize());"
constructor_stmt_enum = ( constructor_stmt_derived = ""
"set_attribute_value(%(index)d, (EnumerationReference(&%(type)s::Class(),(size_t)%(name)s)));" constructor_stmt_instance = "set_attribute_value(%(index)d, %(name)s ? %(name)s->as<IfcUtil::IfcBaseClass>() : (IfcUtil::IfcBaseClass*) nullptr);"
)
constructor_stmt_array = (
"set_attribute_value(%(index)d, (%(name)s)->generalize());"
)
constructor_stmt_derived = (
""
)
constructor_stmt_instance = (
"set_attribute_value(%(index)d, %(name)s ? %(name)s->as<IfcUtil::IfcBaseClass>() : (IfcUtil::IfcBaseClass*) nullptr);"
)
constructor_stmt_optional = " if (%(name)s) {%(stmt)s }" constructor_stmt_optional = " if (%(name)s) {%(stmt)s }"