mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
Update express parser to retain AST parse tree
This commit is contained in:
@@ -113,35 +113,35 @@ def find_bytype(expr, ty, li = None):
|
||||
return set(li)
|
||||
|
||||
actions = {
|
||||
'type_decl' : "lambda t: TypeDeclaration(t)",
|
||||
'entity_decl' : "lambda t: EntityDeclaration(t)",
|
||||
'underlying_type' : "lambda t: UnderlyingType(t)",
|
||||
'enumeration_type' : "lambda t: EnumerationType(t)",
|
||||
'aggregation_types' : "lambda t: AggregationType(t)",
|
||||
'general_aggregation_types' : "lambda t: AggregationType(t)",
|
||||
'select_type' : "lambda t: SelectType(t)",
|
||||
'binary_type' : "lambda t: BinaryType(t)",
|
||||
'subtype_declaration' : "lambda t: SubTypeExpression(t)",
|
||||
'supertype_constraint' : "lambda t: SuperTypeExpression(t)",
|
||||
'derive_clause' : "lambda t: AttributeList('derive', t)",
|
||||
'derived_attr' : "lambda t: DerivedAttribute(t)",
|
||||
'inverse_clause' : "lambda t: AttributeList('inverse', t)",
|
||||
'inverse_attr' : "lambda t: InverseAttribute(t)",
|
||||
'bound_spec' : "lambda t: BoundSpecification(t)",
|
||||
'explicit_attr' : "lambda t: ExplicitAttribute(t)",
|
||||
'width_spec' : "lambda t: WidthSpec(t)",
|
||||
'string_type' : "lambda t: StringType(t)",
|
||||
'type_decl' : "TypeDeclaration",
|
||||
'entity_decl' : "EntityDeclaration",
|
||||
'enumeration_type' : "EnumerationType",
|
||||
'aggregation_types' : "AggregationType",
|
||||
'general_aggregation_types' : "AggregationType",
|
||||
'select_type' : "SelectType",
|
||||
'binary_type' : "BinaryType",
|
||||
'subtype_declaration' : "SubTypeExpression",
|
||||
'supertype_constraint' : "SuperTypeExpression",
|
||||
'derive_clause' : "AttributeList",
|
||||
'inverse_clause' : "AttributeList",
|
||||
'inverse_attr' : "InverseAttribute",
|
||||
'bound_spec' : "BoundSpecification",
|
||||
'explicit_attr' : "ExplicitAttribute",
|
||||
'width_spec' : "WidthSpec",
|
||||
'string_type' : "StringType",
|
||||
'named_types' : "NamedType",
|
||||
'simple_types' : "SimpleType",
|
||||
}
|
||||
|
||||
to_emit = set(id for id, expr in express)
|
||||
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)
|
||||
no_action = {"letter", "digit", "digits", "real_literal", "integer_literal"}
|
||||
|
||||
while True:
|
||||
emitted_in_loop = set()
|
||||
@@ -154,54 +154,65 @@ while True:
|
||||
stmt = "(%s)" % expr
|
||||
if id in to_combine:
|
||||
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))
|
||||
if id not in no_action and not isinstance(expr.contents, Keyword) and not id in to_combine:
|
||||
node_type = "ListNode" if "ZeroOrMore" in stmt else "Node"
|
||||
action = actions.get(id, "lambda s, loc, t: %s(s, loc, t, rule=\"%s\")" % (node_type, id))
|
||||
stmt = "%s.setParseAction(%s)" % (stmt, action)
|
||||
statements.append("%s = %s(\"%s\")" % (id, stmt, id))
|
||||
to_emit -= emitted_in_loop
|
||||
if not emitted_in_loop: break
|
||||
|
||||
for id in to_emit:
|
||||
action = ".setParseAction(%s)" % actions[id] if id in actions else ""
|
||||
statements.append("%s = Forward()%s" % (id, action))
|
||||
statements.append("%s = Forward()(\"%s\")" % (id, id))
|
||||
|
||||
for id in to_emit:
|
||||
expr = [e for k, e in express if k == id][0]
|
||||
stmt = "(%s)" % expr
|
||||
if id in to_combine:
|
||||
stmt = "Suppress%s" % stmt
|
||||
if id not in no_action and not isinstance(expr.contents, Keyword):
|
||||
node_type = "ListNode" if "ZeroOrMore" in stmt else "Node"
|
||||
action = ".setParseAction(%s)" % (actions[id] if id in actions else "lambda s, loc, t: %s(s, loc, t, rule=\"%s\")" % (node_type, id))
|
||||
stmt = "(%s)%s" % (stmt, action)
|
||||
statements.append("%s << %s" % (id, stmt))
|
||||
|
||||
print ("""import os
|
||||
print ("""
|
||||
# This file is generated by IfcOpenShell ifcexpressparser bootstrap.py
|
||||
|
||||
import os
|
||||
import os
|
||||
import sys
|
||||
import pickle
|
||||
|
||||
cache_file = sys.argv[1] + ".cache.dat"
|
||||
if os.path.exists(cache_file):
|
||||
with open(cache_file, "rb") as f:
|
||||
mapping = pickle.load(f)
|
||||
schema = mapping.schema
|
||||
else:
|
||||
from pyparsing import *
|
||||
from nodes import *
|
||||
|
||||
import schema
|
||||
import mapping
|
||||
|
||||
%s
|
||||
import schema
|
||||
import mapping
|
||||
|
||||
syntax.ignore("--" + restOfLine)
|
||||
syntax.ignore(Regex(r"\((?:\*(?:[^*]*\*+)+?\))"))
|
||||
ast = syntax.parseFile(sys.argv[1])
|
||||
schema = schema.Schema(ast)
|
||||
mapping = mapping.Mapping(schema)
|
||||
from pyparsing import *
|
||||
from nodes import *
|
||||
|
||||
with open(cache_file, "wb") as f:
|
||||
pickle.dump(mapping, f, protocol=0)
|
||||
def parse(fn):
|
||||
cache_file = fn + ".cache.dat"
|
||||
if os.path.exists(cache_file):
|
||||
with open(cache_file, "rb") as f:
|
||||
m = pickle.load(f)
|
||||
else:
|
||||
%s
|
||||
|
||||
import importlib
|
||||
for output in sys.argv[2:]:
|
||||
mdl = importlib.import_module(output)
|
||||
mdl.Generator(mapping).emit()
|
||||
syntax.ignore("--" + restOfLine)
|
||||
syntax.ignore(Regex(r"\((?:\*(?:[^*]*\*+)+?\))"))
|
||||
ast = syntax.parseFile(fn)
|
||||
s = schema.Schema(ast)
|
||||
m = mapping.Mapping(s)
|
||||
|
||||
sys.stdout.write(schema.name)
|
||||
"""%('\n '.join(statements)))
|
||||
with open(cache_file, "wb") as f:
|
||||
pickle.dump(m, f, protocol=0)
|
||||
return m
|
||||
|
||||
if __name__ == "__main__":
|
||||
m = parse(sys.argv[1])
|
||||
import importlib
|
||||
for output in sys.argv[2:]:
|
||||
mdl = importlib.import_module(output)
|
||||
mdl.Generator(m).emit()
|
||||
sys.stdout.write(m.schema.name)
|
||||
"""%('\n '.join(statements)))
|
||||
|
||||
@@ -39,7 +39,7 @@ class Definitions(codegen.Base):
|
||||
statements.append("#define SCHEMA_%(name)s_HAS_%(attr)s" % locals())
|
||||
if is_optional:
|
||||
statements.append("#define SCHEMA_%(name)s_%(attr)s_IS_OPTIONAL" % locals())
|
||||
inverse_attribute_names = list(map(operator.attrgetter('name'), type.inverse.elements)) if type.inverse else []
|
||||
inverse_attribute_names = list(map(operator.attrgetter('name'), type.inverse))
|
||||
for attr in inverse_attribute_names:
|
||||
statements.append("#define SCHEMA_%(name)s_HAS_%(attr)s" % locals())
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ class Header(codegen.Base):
|
||||
inv_lines.append(templates.inverse_attr%{'name':attr.name, 'entity':attr.entity, 'attribute':attr.attribute})
|
||||
|
||||
if type.inverse:
|
||||
[write_inverse(attr) for attr in type.inverse.elements]
|
||||
[write_inverse(attr) for attr in type.inverse]
|
||||
|
||||
attributes = "\n".join(["%s%s"%(' '*4, a) for a in attr_lines])
|
||||
if len(attributes): attributes += '\n'
|
||||
|
||||
@@ -55,7 +55,7 @@ class Implementation(codegen.Base):
|
||||
|
||||
write = lambda str, **kwargs: entity_implementations.append(str%kwargs)
|
||||
|
||||
for name, type in mapping.schema.entities.items():
|
||||
for name, type in mapping.schema.entities.items():
|
||||
parent_type_test = "" if not type.supertypes or len(type.supertypes) != 1 \
|
||||
else templates.parent_type_test%(type.supertypes[0])
|
||||
|
||||
@@ -154,7 +154,7 @@ class Implementation(codegen.Base):
|
||||
'arguments' : '',
|
||||
'return_type' : '::%s::%s::list::ptr' % (schema_name, i.entity),
|
||||
'body' : templates.get_inverse % {'type': i.entity, 'index':get_attribute_index(i.entity, i.attribute), 'schema_name' : schema_name, 'schema_name_upper': schema_name_upper}
|
||||
} for i in (type.inverse.elements if type.inverse else [])]
|
||||
} for i in type.inverse]
|
||||
|
||||
superclass = "%s((IfcEntityInstanceData*)0)" % type.supertypes[0] if len(type.supertypes) == 1 else 'IfcUtil::IfcBaseEntity()'
|
||||
|
||||
|
||||
@@ -45,21 +45,28 @@ class Mapping:
|
||||
self.schema = schema
|
||||
|
||||
def flatten_type_string(self, type):
|
||||
return self.flatten_type_string(self.schema.types[type].type.type) if self.schema.is_simpletype(type) else type
|
||||
return self.flatten_type_string(self.schema.types[type].type) if self.schema.is_simpletype(type) else type
|
||||
|
||||
def flatten_type(self, type):
|
||||
res = self.flatten_type(self.schema.types[type].type.type) if self.schema.is_simpletype(type) else type
|
||||
res = self.flatten_type(self.schema.types[type].type) if self.schema.is_simpletype(type) else type
|
||||
return res
|
||||
|
||||
def simple_type_parent(self, type):
|
||||
parent = self.schema.types[type].type.type
|
||||
if isinstance(parent, nodes.AggregationType): parent = None
|
||||
return None if str(parent) in self.express_to_cpp_typemapping else parent
|
||||
parent = self.schema.types[type].type
|
||||
if isinstance(parent, (nodes.AggregationType, nodes.StringType)) or (isinstance(parent, nodes.SimpleType) and isinstance(parent.type, nodes.StringType)):
|
||||
return None
|
||||
if str(parent) in self.express_to_cpp_typemapping:
|
||||
return None
|
||||
return str(parent)
|
||||
|
||||
def make_type_string(self, type):
|
||||
if isinstance(type, (str, nodes.BinaryType, nodes.StringType)):
|
||||
if isinstance(type, nodes.StringType) or (isinstance(type, nodes.SimpleType) and isinstance(type.type, nodes.StringType)):
|
||||
type = "string"
|
||||
if isinstance(type, (str, nodes.BinaryType, nodes.SimpleType, nodes.NamedType)):
|
||||
return self.express_to_cpp_typemapping.get(str(type), "::%s::%s" % (self.schema.name.capitalize(), type))
|
||||
else:
|
||||
if type.bounds is None:
|
||||
import pdb; pdb.set_trace()
|
||||
is_list = self.schema.is_entity(type.type)
|
||||
is_nested_list = isinstance(type.type, nodes.AggregationType)
|
||||
tmpl = templates.list_list_type if is_nested_list else templates.list_type if is_list else templates.array_type
|
||||
@@ -73,7 +80,7 @@ class Mapping:
|
||||
if isinstance(type, nodes.AggregationType):
|
||||
return True
|
||||
elif isinstance(type, str) and self.schema.is_type(type):
|
||||
return self.is_array(self.schema.types[type].type.type)
|
||||
return self.is_array(self.schema.types[type].type)
|
||||
else:
|
||||
return False
|
||||
|
||||
@@ -85,6 +92,8 @@ class Mapping:
|
||||
|
||||
def make_argument_type(self, attr):
|
||||
def _make_argument_type(type):
|
||||
if isinstance(type, nodes.SimpleType):
|
||||
type = type.type
|
||||
if self.schema.is_entity(type) or isinstance(type, nodes.SelectType):
|
||||
return "ENTITY_INSTANCE"
|
||||
elif isinstance(type, nodes.BinaryType):
|
||||
@@ -100,7 +109,7 @@ class Mapping:
|
||||
elif str(type) in self.express_to_cpp_typemapping:
|
||||
return self.express_to_cpp_typemapping.get(str(type), type).split('::')[-1].upper()
|
||||
elif self.schema.is_type(type):
|
||||
return _make_argument_type(self.schema.types[type].type.type)
|
||||
return _make_argument_type(self.schema.types[type].type)
|
||||
else:
|
||||
raise ValueError("Unable to map type %r for attribute %r" % (type, attr))
|
||||
ty = _make_argument_type(attr.type if hasattr(attr, 'type') else attr)
|
||||
@@ -117,7 +126,11 @@ class Mapping:
|
||||
|
||||
def get_parameter_type(self, attr, allow_optional, allow_entities, allow_pointer = True):
|
||||
attr_type = self.flatten_type(attr.type)
|
||||
type_str = self.express_to_cpp_typemapping.get(str(attr_type), attr_type)
|
||||
|
||||
if (isinstance(attr_type, nodes.SimpleType) and isinstance(attr_type.type, nodes.StringType)) or isinstance(attr_type, nodes.StringType):
|
||||
type_str = self.express_to_cpp_typemapping["string"]
|
||||
else:
|
||||
type_str = self.express_to_cpp_typemapping.get(str(attr_type), attr_type)
|
||||
|
||||
is_ptr = False
|
||||
|
||||
@@ -163,13 +176,16 @@ class Mapping:
|
||||
|
||||
def derived_in_supertype(self, t):
|
||||
c = sum([self.derived_in_supertype(self.schema.entities[s]) for s in t.supertypes], [])
|
||||
return c + ([str(s) for s in t.derive.elements] if t.derive else [])
|
||||
derived = c + t.derive
|
||||
return [d[0][1] for d in derived if isinstance(d[0], tuple)]
|
||||
|
||||
def list_instance_type(self, attr):
|
||||
attr_type = attr.type if isinstance(attr, nodes.ExplicitAttribute) else attr
|
||||
if isinstance(attr_type, str): return None
|
||||
def f(v):
|
||||
v = self.flatten_type(v)
|
||||
if isinstance(v, (nodes.AggregationType, nodes.StringType)) or (isinstance(v, nodes.SimpleType) and isinstance(v.type, nodes.StringType)):
|
||||
return "string"
|
||||
if self.schema.is_select(v):
|
||||
return 'IfcUtil::IfcBaseClass'
|
||||
elif str(v) in self.schema.types or str(v) in self.schema.entities:
|
||||
|
||||
+254
-137
@@ -24,45 +24,149 @@ import string
|
||||
import collections
|
||||
|
||||
class Node:
|
||||
def __init__(self, tokens = None):
|
||||
self.tokens = tokens or []
|
||||
self.init()
|
||||
def tokens_of_type(self, cls):
|
||||
return [t for t in self.tokens if isinstance(t, cls)]
|
||||
def single_token_of_type(self, cls, k = None, v = None):
|
||||
ts = [t for t in self.tokens if isinstance(t, cls) and (k is None or getattr(t, k) == v)]
|
||||
return ts[0] if len(ts) == 1 else None
|
||||
def __init__(self, s, loc, tokens, rule=None):
|
||||
self.rule = rule or (type(self).__name__)
|
||||
self.tokens = tokens.asDict()
|
||||
self.flat = sum([getattr(t, 'flat', [t]) for t in tokens.asList()], [])
|
||||
if rule is None:
|
||||
self.init()
|
||||
def __repr__(self):
|
||||
return "%s(%s)" % (self.rule, ",".join("%s:%s" % i for i in self.tokens.items()))
|
||||
def __getattr__(self, k):
|
||||
return self.tokens.get(k)
|
||||
def __getstate__(self): return self.__dict__
|
||||
def __setstate__(self, d): self.__dict__.update(d)
|
||||
def init(self): pass
|
||||
def any(self):
|
||||
return next(iter(self.tokens.values()))
|
||||
|
||||
class ListNode:
|
||||
def __init__(self, s, loc, tokens, rule=None):
|
||||
self.rule = rule or (type(self).__name__)
|
||||
self.tokens = tokens.asList()
|
||||
self.flat = sum([getattr(t, 'flat', [t]) for t in self.tokens], [])
|
||||
def __repr__(self):
|
||||
return "%s[%s]" % (self.rule, ",".join("%s" % i for i in self.tokens))
|
||||
def __iter__(self):
|
||||
return iter(self.tokens)
|
||||
def __getitem__(self, i):
|
||||
return self.tokens[i]
|
||||
def init(self): pass
|
||||
|
||||
|
||||
class SimpleType(Node):
|
||||
|
||||
def get_type(self):
|
||||
t = self.any()
|
||||
if (type(t) == Node):
|
||||
return t.any()
|
||||
else:
|
||||
t = t[0]
|
||||
if (type(t) == Node):
|
||||
return t.any().any()
|
||||
else:
|
||||
return t
|
||||
|
||||
type = property(get_type)
|
||||
|
||||
def __repr__(self):
|
||||
return str(self.type)
|
||||
|
||||
|
||||
def format_clause(exp):
|
||||
def whitespace(t):
|
||||
if t in {'=', '|', '<*', 'or', 'in', '<>', 'and'}:
|
||||
return ' %s ' % t
|
||||
return t
|
||||
return "".join(whitespace(term) for term in exp.flat)
|
||||
|
||||
|
||||
class TypeDeclaration(Node):
|
||||
name = property(lambda self: self.tokens[1])
|
||||
type = property(lambda self: self.tokens[3])
|
||||
def init(self):
|
||||
assert self.tokens[0] == 'type'
|
||||
assert isinstance(self.type, UnderlyingType)
|
||||
name = property(lambda self: self.type_id[0])
|
||||
type = property(lambda self: self.underlying_type.any().any())
|
||||
def init(self):
|
||||
|
||||
assert hasattr(self, "TYPE")
|
||||
|
||||
self.where = []
|
||||
clause = self.where_clause
|
||||
if clause:
|
||||
clause = clause[0]
|
||||
|
||||
self.where = [(r.simple_id, format_clause(r.expression[0])) for r in clause[1::2]]
|
||||
|
||||
def __repr__(self):
|
||||
return "%s = TypeDeclaration(%s)" % (self.name, self.type)
|
||||
s = "TYPE %s = %s;\n" % (self.name, self.type)
|
||||
if self.where:
|
||||
s += " WHERE\n"
|
||||
for nm_exp in self.where:
|
||||
s += " %s : %s;\n" % nm_exp
|
||||
s += "END_TYPE;"
|
||||
return s
|
||||
|
||||
|
||||
class EntityDeclaration(Node):
|
||||
name = property(lambda self: self.tokens[1])
|
||||
attributes = property(lambda self: self.tokens_of_type(ExplicitAttribute))
|
||||
abstract = property(lambda self: self.single_token_of_type(SuperTypeExpression) is not None and \
|
||||
self.single_token_of_type(SuperTypeExpression).abstract)
|
||||
name = property(lambda self: self.entity_head[0].entity_id[0])
|
||||
supertype = property(lambda self: self.entity_head[0].subsuper[0].supertype_constraint)
|
||||
subtype = property(lambda self: self.entity_head[0].subsuper[0].subtype_declaration)
|
||||
supertypes = property(lambda self: [self.subtype.super_type] if self.subtype else [])
|
||||
|
||||
def get_abstract(self):
|
||||
if self.entity_head[0].subsuper[0].supertype_constraint:
|
||||
return self.entity_head[0].subsuper[0].supertype_constraint.abstract
|
||||
else:
|
||||
return False
|
||||
|
||||
abstract = property(get_abstract)
|
||||
|
||||
def init(self):
|
||||
assert self.tokens[0] == 'entity'
|
||||
s = self.single_token_of_type(SubTypeExpression)
|
||||
self.inverse = self.single_token_of_type(AttributeList, 'type', 'inverse')
|
||||
self.derive = self.single_token_of_type(AttributeList, 'type', 'derive')
|
||||
self.supertypes = s.types if s else []
|
||||
|
||||
def redeclared_attribute(a):
|
||||
try:
|
||||
return (
|
||||
a.attribute_decl.redeclared_attribute.qualified_attribute.group_qualifier.simple_id,
|
||||
a.attribute_decl.redeclared_attribute.qualified_attribute.attribute_qualifier.simple_id
|
||||
)
|
||||
except:
|
||||
return a.attribute_decl.simple_id
|
||||
|
||||
assert self.flat[0] == 'entity'
|
||||
|
||||
self.attributes = [a for a in self.entity_body[0] if isinstance(a, ExplicitAttribute)]
|
||||
self.inverse = []
|
||||
alist = [x for x in self.entity_body[0] if isinstance(x, AttributeList) and x.type == 'inverse']
|
||||
if alist:
|
||||
self.inverse = alist[0]
|
||||
|
||||
self.derive = []
|
||||
alist = [x for x in self.entity_body[0] if isinstance(x, AttributeList) and x.type == 'derive']
|
||||
if alist:
|
||||
alist = alist[0]
|
||||
self.derive = [(redeclared_attribute(a), format_clause(a.expression[0])) for a in alist]
|
||||
|
||||
self.where = []
|
||||
clause = [r for r in self.entity_body[0] if r.rule == "where_clause"]
|
||||
if clause:
|
||||
clause = clause[0]
|
||||
|
||||
self.where = [(r.simple_id, format_clause(r.expression[0])) for r in clause[1::2]]
|
||||
|
||||
self.unique = []
|
||||
clause = [r for r in self.entity_body[0] if r.rule == "unique_clause"]
|
||||
if clause:
|
||||
clause = clause[0]
|
||||
self.unique = [(r[0], r[2].simple_id) for r in clause[1::2]]
|
||||
|
||||
def __repr__(self):
|
||||
strm = io.StringIO()
|
||||
|
||||
print("ENTITY %s" % self.name, file=strm)
|
||||
for x in (SuperTypeExpression, SubTypeExpression):
|
||||
tk = self.single_token_of_type(x)
|
||||
if tk is not None:
|
||||
print("", tk, file=strm)
|
||||
|
||||
if self.supertype:
|
||||
print("", self.supertype, file=strm)
|
||||
if self.subtype:
|
||||
print("", self.subtype, file=strm)
|
||||
|
||||
strm.seek(strm.tell() - 1)
|
||||
print(";", file=strm)
|
||||
|
||||
@@ -71,171 +175,184 @@ class EntityDeclaration(Node):
|
||||
|
||||
if self.derive:
|
||||
print(" DERIVE", file=strm)
|
||||
print(self.derive, file=strm)
|
||||
for nm, exp in self.derive:
|
||||
if isinstance(nm, tuple):
|
||||
nm = "SELF\\%s.%s" % nm
|
||||
print(" %s : %s;" % (nm, exp), file=strm)
|
||||
|
||||
if self.inverse:
|
||||
print(" INVERSE", file=strm)
|
||||
print(self.inverse, file=strm)
|
||||
|
||||
tks = self.tokens.asList()
|
||||
try:
|
||||
whr = tks.index('where')
|
||||
if self.where:
|
||||
print(" WHERE", file=strm)
|
||||
tks = tks[whr:-2]
|
||||
tk_pairs = zip(tks[1:], tks)
|
||||
def fmt(ss):
|
||||
# import pdb; pdb.set_trace()
|
||||
is_narrow = lambda s: s != ':' and len(s) == 1
|
||||
narrow = any(map(is_narrow, ss))
|
||||
lbreak = ss[0] == ';'
|
||||
indent = ss[1] == 'where' or ss[1] == ';'
|
||||
return "".join(((' ', '')[narrow or indent], ('', ' ')[indent], ss[0], ('', '\n')[lbreak]))
|
||||
print(*map(fmt, tk_pairs), sep='', file=strm)
|
||||
strm.seek(strm.tell() - 1)
|
||||
except ValueError as e:
|
||||
pass
|
||||
for nm_exp in self.where:
|
||||
print(" %s : %s;" % nm_exp, file=strm)
|
||||
|
||||
if self.unique:
|
||||
print(" UNIQUE", file=strm)
|
||||
for nm_exp in self.unique:
|
||||
print(" %s : %s;" % nm_exp, file=strm)
|
||||
|
||||
print("END_ENTITY;", file=strm)
|
||||
return strm.getvalue()
|
||||
|
||||
|
||||
class UnderlyingType(Node):
|
||||
type = property(lambda self: self.tokens[0])
|
||||
def init(self):
|
||||
pass
|
||||
def __repr__(self):
|
||||
return repr(self.type)
|
||||
|
||||
|
||||
class EnumerationType(Node):
|
||||
type = property(lambda self: self.tokens[0])
|
||||
values = property(lambda self: self.tokens[3::2])
|
||||
def init(self):
|
||||
assert self.type == 'enumeration'
|
||||
values = property(lambda self: self.enumeration_type[2][1::2])
|
||||
def __repr__(self):
|
||||
return "ENUMERATION OF (" + ",".join(self.values) + ")"
|
||||
return "ENUMERATION OF (" + ",".join(self.values) + ")"
|
||||
|
||||
|
||||
class NamedType(Node):
|
||||
type = property(lambda self: self.simple_id)
|
||||
def __repr__(self):
|
||||
return self.type
|
||||
|
||||
|
||||
class AggregationType(Node):
|
||||
aggregate_type = property(lambda self: self.tokens[0])
|
||||
bounds = property(lambda self: None if self.tokens[1] == 'of' else self.tokens[1])
|
||||
type = property(lambda self: self.tokens[-1])
|
||||
aggregate_type = property(lambda self: self.flat[0])
|
||||
bounds = property(lambda self: (list(self.tokens.values())[0][0].bound_spec or [None])[0])
|
||||
unique = property(lambda self: list(self.tokens.values())[0][0].UNIQUE is not None)
|
||||
|
||||
def get_type(self):
|
||||
v = list(self.tokens.values())[0][0]
|
||||
if v.instantiable_type:
|
||||
try:
|
||||
return v.instantiable_type.concrete_types.simple_id or v.instantiable_type.concrete_types.simple_types
|
||||
except:
|
||||
return v.instantiable_type
|
||||
elif v.parameter_type.simple_types:
|
||||
return v.parameter_type.simple_types
|
||||
elif v.parameter_type.named_types:
|
||||
return v.parameter_type.named_types
|
||||
elif v.parameter_type.generalized_types.general_aggregation_types:
|
||||
return v.parameter_type.generalized_types.general_aggregation_types
|
||||
else:
|
||||
import pdb; pdb.set_trace()
|
||||
raise ValueError()
|
||||
|
||||
type = property(get_type)
|
||||
|
||||
def init(self):
|
||||
assert self.bounds is None or isinstance(self.bounds, BoundSpecification)
|
||||
|
||||
def __repr__(self):
|
||||
return "%s%s of %s"%(self.aggregate_type, self.bounds, self.type)
|
||||
return "%s%s of %s%s"%(self.aggregate_type, self.bounds, "unique " if self.unique else "", self.type)
|
||||
|
||||
|
||||
class SelectType(Node):
|
||||
type = property(lambda self: self.tokens[0])
|
||||
values = property(lambda self: self.tokens[2::2])
|
||||
def init(self):
|
||||
assert self.type == 'select'
|
||||
values = property(lambda self: self.select_type[1][1::2])
|
||||
def __repr__(self):
|
||||
return "SELECT (" + ",".join(self.values) + ")"
|
||||
return "SELECT (" + ",".join(map(str, self.values)) + ")"
|
||||
|
||||
|
||||
class SubSuperTypeExpression(Node):
|
||||
type = property(lambda self: self.tokens[0])
|
||||
types = property(lambda self: self.tokens[3::2])
|
||||
abstract = False
|
||||
def init(self):
|
||||
if self.tokens[0] == 'abstract':
|
||||
self.tokens = self.tokens[1:]
|
||||
self.abstract = True
|
||||
assert self.type == self.type_relationship
|
||||
|
||||
def __repr__(self):
|
||||
terminals = {"abstract","subtype", "supertype", "of", "oneof"}
|
||||
tks = [s.upper() if s in terminals else s for s in self.tokens]
|
||||
class SuperTypeExpression(Node):
|
||||
abstract = property(lambda self: self.abstract_supertype_declaration is not None)
|
||||
def get_sub_types(self):
|
||||
if self.abstract:
|
||||
tks.insert(0, "ABSTRACT")
|
||||
return " ".join(tks)
|
||||
constraint = self.abstract_supertype_declaration[0]
|
||||
else:
|
||||
constraint = self.supertype_rule[0]
|
||||
return [s[0][0].simple_id for s in constraint.subtype_constraint[0].supertype_expression[0][0][0].one_of[0][2::2]]
|
||||
|
||||
|
||||
class SubTypeExpression(SubSuperTypeExpression):
|
||||
type_relationship = 'subtype'
|
||||
|
||||
|
||||
class SuperTypeExpression(SubSuperTypeExpression):
|
||||
type_relationship = 'supertype'
|
||||
|
||||
|
||||
class AttributeList(Node):
|
||||
elements = property(lambda self: self.tokens[1:])
|
||||
def __init__(self, ty, toks):
|
||||
self.type = ty
|
||||
Node.__init__(self, toks)
|
||||
def init(self):
|
||||
assert self.type == self.tokens[0]
|
||||
sub_types = property(get_sub_types)
|
||||
|
||||
def __repr__(self):
|
||||
return "\n".join([" %s;"%s for s in self.elements])
|
||||
return "%sSUPERTYPE OF(ONEOF(%s))" % ("ABSTRACT " if self.abstract else "",",".join(self.sub_types))
|
||||
|
||||
|
||||
class SubTypeExpression(Node):
|
||||
super_type = property(lambda self: self.entity_ref[0])
|
||||
|
||||
def __repr__(self):
|
||||
return "SUBTYPE OF(%s)" % self.super_type
|
||||
|
||||
class AttributeList(ListNode):
|
||||
type = property(lambda self: self.flat[0] if self.flat[0] in {'inverse', 'derive'} else 'explicit')
|
||||
def __repr__(self):
|
||||
return "\n".join([" %s;"%s for s in self.tokens[1:]])
|
||||
def __iter__(self):
|
||||
return iter(self.elements)
|
||||
return iter(self.tokens[1:])
|
||||
def __len__(self):
|
||||
return len(self.tokens[1:])
|
||||
|
||||
|
||||
class InverseAttribute(Node):
|
||||
name = property(lambda self: self.tokens[0])
|
||||
type = property(lambda self: self.tokens[2] if self.tokens[2] != self.tokens[-4] else None)
|
||||
bounds = property(lambda self: None if len(self.tokens) != 9 else self.tokens[3])
|
||||
entity = property(lambda self: self.tokens[-4])
|
||||
attribute = property(lambda self: self.tokens[-2])
|
||||
def init(self):
|
||||
assert self.bounds is None or isinstance(self.bounds, BoundSpecification)
|
||||
name = property(lambda self: self.attribute_decl.simple_id)
|
||||
type = property(lambda self: self.flat[2] if self.flat[2] != self.flat[-4] else None)
|
||||
bounds = property(lambda self: self.bound_spec[0] if self.bound_spec else None)
|
||||
entity = property(lambda self: self.entity_ref[0])
|
||||
attribute = property(lambda self: self.attribute_ref[0])
|
||||
def __repr__(self):
|
||||
return "%s : %s %s OF %s FOR %s" % (self.name, (self.type or "").upper(), self.bounds or "", self.entity, self.attribute)
|
||||
|
||||
def _():
|
||||
yield self.name
|
||||
yield ":"
|
||||
if self.type:
|
||||
yield self.type.upper()
|
||||
yield "OF"
|
||||
if self.bounds:
|
||||
yield self.bounds
|
||||
yield self.entity
|
||||
yield "FOR"
|
||||
yield self.attribute
|
||||
return " ".join(map(str, _()))
|
||||
|
||||
"""
|
||||
class DerivedAttribute(Node):
|
||||
def init(self):
|
||||
return
|
||||
name_index = list(self.tokens).index(':') - 1
|
||||
self.name = self.tokens[name_index]
|
||||
def __repr__(self):
|
||||
return str(self.name)
|
||||
|
||||
"""
|
||||
|
||||
class BinaryType(Node):
|
||||
def init(self):
|
||||
pass
|
||||
def __repr__(self):
|
||||
return "binary"
|
||||
|
||||
|
||||
class BoundSpecification(Node):
|
||||
lower = property(lambda self: self.tokens[1])
|
||||
upper = property(lambda self: self.tokens[3])
|
||||
def init(self):
|
||||
# assert self.lower in string.digits or self.lower == '?'
|
||||
# assert self.upper in string.digits or self.upper == '?'
|
||||
pass
|
||||
lower = property(lambda self: self.flat[1])
|
||||
upper = property(lambda self: self.flat[3])
|
||||
|
||||
def __repr__(self):
|
||||
return "[%s:%s]"%(self.lower, self.upper)
|
||||
|
||||
|
||||
class ExplicitAttribute(Node):
|
||||
name = property(lambda self: self.tokens[0])
|
||||
type = property(lambda self: self.tokens[-2])
|
||||
optional = property(lambda self: len(self.tokens) == 5 and self.tokens[-3] == 'optional')
|
||||
def init(self):
|
||||
# NB: This assumes a single name per attribute
|
||||
# definition, which is not necessarily the case.
|
||||
if self.tokens[0] == "self":
|
||||
i = list(self.tokens).index(":")
|
||||
self.tokens = self.tokens[i-1:]
|
||||
assert self.tokens[1] == ':'
|
||||
name = property(lambda self: self.attribute_decl.simple_id)
|
||||
optional = property(lambda self: self.OPTIONAL is not None)
|
||||
|
||||
def get_type(self):
|
||||
v = next(iter(self.parameter_type.tokens.values()))
|
||||
if v.general_aggregation_types:
|
||||
return v.general_aggregation_types
|
||||
else:
|
||||
return v
|
||||
|
||||
type = property(get_type)
|
||||
|
||||
def __repr__(self):
|
||||
return "%s : %s%s" % (self.name, "OPTIONAL " if self.optional else "", self.type)
|
||||
return "%s : %s%s" % (self.name, "optional " if self.optional else "", self.type)
|
||||
|
||||
|
||||
class WidthSpec(Node):
|
||||
fixed = property(lambda self: self.FIXED is not None)
|
||||
|
||||
def init(self):
|
||||
if self.tokens[-1] == "fixed":
|
||||
self.tokens[-1:] = []
|
||||
assert (self.tokens[0], self.tokens[-1]) == ("(", ")")
|
||||
self.width = int("".join(self.tokens[1:-1]))
|
||||
|
||||
class StringType(Node):
|
||||
def init(self):
|
||||
pass
|
||||
self.width = int(''.join(self.width[0].flat))
|
||||
|
||||
def __repr__(self):
|
||||
return "string"
|
||||
return "(%d)%s" % (self.width, " fixed" if self.fixed else "")
|
||||
|
||||
|
||||
class StringType(Node):
|
||||
width = property(lambda self: self.width_spec[0] if self.width_spec else None)
|
||||
|
||||
def __repr__(self):
|
||||
s = "string"
|
||||
if self.width:
|
||||
s += " " + repr(self.width)
|
||||
return s
|
||||
|
||||
@@ -70,18 +70,22 @@ class Schema:
|
||||
def __getitem__(self, key):
|
||||
return self.types_entities[key]
|
||||
def __init__(self, parsetree):
|
||||
self.name = parsetree[1]
|
||||
|
||||
self.name = parsetree.syntax[0][0].simple_id
|
||||
|
||||
sort = lambda d: OrderedCaseInsensitiveDict(sorted(d))
|
||||
|
||||
declarations = [d.any()[0] for d in parsetree.syntax[0][0].schema_body[0] if d.rule == 'declaration' and d.any()[0].rule != 'function_decl']
|
||||
|
||||
self.types = sort([(t.name,t) for t in parsetree if isinstance(t, nodes.TypeDeclaration)])
|
||||
self.entities = sort([(t.name,t) for t in parsetree if isinstance(t, nodes.EntityDeclaration)])
|
||||
self.types = sort([(t.name,t) for t in declarations if isinstance(t, nodes.TypeDeclaration)])
|
||||
self.entities = sort([(t.name,t) for t in declarations if isinstance(t, nodes.EntityDeclaration)])
|
||||
|
||||
self.keys = list(self.types.keys()) + list(self.entities.keys())
|
||||
self.types_entities = {k: v for d in (self.types, self.entities) for k, v in d.items()}
|
||||
|
||||
of_type = lambda *types: sort([(a, b.type.type) for a,b in self.types.items() if any(isinstance(b.type.type, ty) for ty in types)])
|
||||
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)])
|
||||
|
||||
self.enumerations = of_type(nodes.EnumerationType)
|
||||
self.selects = of_type(nodes.SelectType)
|
||||
self.simpletypes = of_type(str, nodes.AggregationType, nodes.BinaryType, nodes.StringType)
|
||||
self.simpletypes = of_type(str, nodes.AggregationType, nodes.BinaryType, nodes.StringType, nodes.SimpleType, nodes.NamedType)
|
||||
|
||||
assert len(self.enumerations) + len(self.selects) + len(self.simpletypes) == len(self.types)
|
||||
|
||||
@@ -36,6 +36,11 @@ class SchemaClass(codegen.Base):
|
||||
declared_types = []
|
||||
|
||||
def get_declared_type(type, emitted_names=None):
|
||||
if isinstance(type, nodes.SimpleType):
|
||||
type = type.type
|
||||
if isinstance(type, nodes.NamedType):
|
||||
type = str(type)
|
||||
|
||||
if isinstance(type, nodes.AggregationType):
|
||||
aggr_type = type.aggregate_type
|
||||
make_bound = lambda b: -1 if b == '?' else int(b)
|
||||
@@ -54,6 +59,8 @@ class SchemaClass(codegen.Base):
|
||||
raise UnmetDependenciesException(type)
|
||||
else:
|
||||
return "new simple_type(simple_type::%s_type)" % type
|
||||
else:
|
||||
raise ValueError("No mapping for '%s'" % type)
|
||||
|
||||
def find_inverse_name_and_index(entity_name, attribute_name):
|
||||
attributes_per_subtype = []
|
||||
@@ -132,10 +139,10 @@ __attribute__((optnone))
|
||||
else: return False
|
||||
|
||||
def write_select(schema_name, name, type):
|
||||
if set(map(lambda s: s.lower(),type.values)) < emitted:
|
||||
if set(map(lambda s: str(s).lower(), type.values)) < emitted:
|
||||
statements.append(' {')
|
||||
statements.append(' std::vector<const declaration*> items; items.reserve(%d);' % len(type.values))
|
||||
statements.extend(map(lambda v: ' items.push_back(%s_%s_type);' % (schema_name, v), sorted(type.values)))
|
||||
statements.extend(map(lambda v: ' items.push_back(%s_%s_type);' % (schema_name, v), sorted(map(str, type.values))))
|
||||
statements.append(' %(schema_name)s_%(name)s_type = new select_type("%(name)s", %%(index_in_schema_%(name)s)d, items);' % locals())
|
||||
statements.append(' }')
|
||||
else: return False
|
||||
@@ -152,7 +159,7 @@ __attribute__((optnone))
|
||||
|
||||
decl = mapping.schema[name]
|
||||
if isinstance(decl, nodes.TypeDeclaration):
|
||||
decl = decl.type.type
|
||||
decl = decl.type
|
||||
return fn(schema_name, name, decl) is not False
|
||||
|
||||
while len(emitted) < len_to_emit:
|
||||
@@ -183,8 +190,8 @@ __attribute__((optnone))
|
||||
for name, type in mapping.schema.entities.items():
|
||||
if type.inverse:
|
||||
statements.append(' {')
|
||||
statements.append(' std::vector<const inverse_attribute*> attributes; attributes.reserve(%d);' % len(type.inverse.elements))
|
||||
for attr in type.inverse.elements:
|
||||
statements.append(' std::vector<const inverse_attribute*> attributes; attributes.reserve(%d);' % len(type.inverse))
|
||||
for attr in type.inverse:
|
||||
if attr.bounds:
|
||||
make_bound = lambda b: -1 if b == '?' else int(b)
|
||||
bound1, bound2 = map(make_bound, (attr.bounds.lower, attr.bounds.upper))
|
||||
|
||||
Reference in New Issue
Block a user