Work on more readable ast for express schema parser

This commit is contained in:
Thomas Krijnen
2022-07-10 21:51:25 +02:00
parent 443af3f7e7
commit bab6313313
4 changed files with 375 additions and 1339 deletions
@@ -161,7 +161,7 @@ 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)
no_action = {"letter", "digit", "digits", "real_literal", "integer_literal"}
no_action = {"letter", "digit", "digits", "real_literal", "integer_literal", "string_literal", "simple_string_literal", "letter", "not_quote", "not_paren_star_quote_special"}
while True:
emitted_in_loop = set()
@@ -199,8 +199,8 @@ for id in to_emit:
stmt = "(%s)%s" % (stmt, action)
statements.append("%s << %s" % (id, stmt))
print(
"""
if __name__ == "__main__":
print("""
# This file is generated by IfcOpenShell ifcexpressparser bootstrap.py
import os
@@ -238,6 +238,5 @@ if __name__ == "__main__":
mdl = importlib.import_module(output)
mdl.Generator(m).emit()
sys.stdout.write(m.schema.name)
"""
% ("\n ".join(statements))
)
""" % ("\n ".join(statements))
)
File diff suppressed because it is too large Load Diff
@@ -21,6 +21,7 @@ from __future__ import print_function
import io
import string
import operator
import collections
@@ -55,6 +56,11 @@ class ListNode:
def __init__(self, s, loc, tokens, rule=None):
self.rule = rule or (type(self).__name__)
self.tokens = tokens.asList()
self.dict_tokens = collections.defaultdict(list)
for t in self.tokens:
r = getattr(t, 'rule', None)
if r:
self.dict_tokens[r].append(t)
self.flat = sum([getattr(t, "flat", [t]) for t in self.tokens], [])
def __repr__(self):
@@ -97,7 +103,7 @@ def format_clause(exp):
return "".join(whitespace(term) for term in exp.flat)
class TypeDeclaration(Node):
class TypeDeclaration(Node):
name = property(lambda self: self.type_id[0])
utype = property(lambda self: self.underlying_type.any().any())
type = property(lambda self: self.utype[0] if isinstance(self.utype, list) else self.utype)
@@ -229,6 +235,41 @@ class NamedType(Node):
return self.type
def do_try(fn):
try:
return fn()
except: pass
def to_tree(x, key=None):
def get_rule_id(x):
from bootstrap import actions
ty = type(x).__name__
matches = [k for k, v in actions.items() if v == ty]
if matches:
return matches[0]
def prune(di):
import bootstrap
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])))) \
for k, v in bootstrap.express
}
subrules = list(filter(str.islower, rule_dependencies[key]))
return {k: v for k, v in di.items() if k in subrules}
if isinstance(x, ListNode):
return to_tree(x.dict_tokens, key=get_rule_id(x) or key)
if isinstance(x, Node,):
return to_tree(x.tokens, key=get_rule_id(x) or key)
elif isinstance(x, dict):
return prune({k: to_tree(v, key=k) for k, v in x.items()})
elif isinstance(x, list):
return [to_tree(v, key=key) for v in x]
else:
return x
class AggregationType(Node):
aggregate_type = property(lambda self: self.flat[0])
bounds = property(lambda self: (list(self.tokens.values())[0][0].bound_spec or [None])[0])
@@ -247,6 +288,8 @@ class AggregationType(Node):
return v.parameter_type.named_types
elif v.parameter_type.generalized_types.general_aggregation_types:
return v.parameter_type.generalized_types.general_aggregation_types
elif do_try(lambda: v.parameter_type.generalized_types.generic_type.generic_type[0].GENERIC):
return do_try(lambda: v.parameter_type.generalized_types.generic_type.generic_type[0].GENERIC)
else:
import pdb
@@ -84,6 +84,7 @@ class Schema:
return self.types_entities[key]
def __init__(self, parsetree):
self.tree = parsetree
self.name = parsetree.syntax[0][0].simple_id
sort = lambda d: OrderedCaseInsensitiveDict(sorted(d))