Merge remote-tracking branch 'origin/v0.8.0' into ifcviewer-wgpu

This commit is contained in:
Thomas Krijnen
2026-07-09 13:21:39 +02:00
373 changed files with 22411 additions and 4242 deletions
@@ -100,6 +100,9 @@ del _patch_swig_comparisons
# End hacks!
from .sql import sqlite, sqlite_entity
get_log = ifcopenshell_wrapper.get_log
logger = getattr(ifcopenshell_wrapper, "logger", None)
# explicitly specify available imported symbols
# (it's a requirement for a typed library)
__all__ = [
@@ -150,10 +153,20 @@ class SchemaError(Error):
@overload
def open(
path: Union[os.PathLike, str], format: SupportedFormat = None, *, should_stream: Literal[False] = False
path: Union[os.PathLike, str],
format: SupportedFormat = None,
*,
should_stream: Literal[False] = False,
logger: Optional[logger] = None,
) -> Union[_file, sqlite]: ...
@overload
def open(path: Union[os.PathLike, str], format: SupportedFormat = None, *, should_stream: Literal[True]) -> _stream: ...
def open(
path: Union[os.PathLike, str],
format: SupportedFormat = None,
*,
should_stream: Literal[True],
logger: Optional[logger] = None,
) -> _stream: ...
@overload
def open(
path: Union[os.PathLike, str],
@@ -161,6 +174,7 @@ def open(
*,
should_stream: bool = False,
readonly: bool = False,
logger: Optional[logger] = None,
) -> Union[_file, sqlite, _stream]: ...
def open(
path: Union[os.PathLike, str],
@@ -169,11 +183,13 @@ def open(
readonly: bool = False,
mmap: bool = False,
bypass_types: Optional[Sequence[str]] = None,
logger: Optional[logger] = None,
) -> Union[_file, sqlite, _stream]:
"""Loads an IFC dataset from a filepath
:param should_stream: Whether to open the file in streaming mode. Could be useful
for reading large files.
:param logger: Logger that receives native parser messages.
You can specify a file format. If no format is given, it is guessed from
its extension.
@@ -198,8 +214,10 @@ def open(
raise FileNotFoundError(f"Path does not exist: '{path}'.")
if format is None:
format = guess_format(path)
if logger is None and (logger_type := getattr(ifcopenshell_wrapper, "logger", None)):
logger = logger_type.Root()
if format == ".ifcXML":
f = ifcopenshell_wrapper.parse_ifcxml(str(path.absolute()))
f = ifcopenshell_wrapper.parse_ifcxml(str(path.absolute()), *((logger,) if logger is not None else ()))
if f:
return file(f)
raise OSError(f"Failed to parse .ifcXML file from {path}")
@@ -208,7 +226,7 @@ def open(
with zipfile.ZipFile(path) as zf:
for name in zf.namelist():
if Path(name).suffix.lower() in (".ifc", ".ifcxml"):
return open(zf.extract(name, unzipped_path))
return open(zf.extract(name, unzipped_path), logger=logger)
else:
raise LookupError(f"No .ifc or .ifcXML file found in {path}")
if format == ".ifcSQLite":
@@ -216,9 +234,11 @@ def open(
if should_stream:
return stream(path)
if readonly: # Temporary conditional see #7131. Remove once newer builds don't segfault on Linux.
f = ifcopenshell_wrapper.open(str(path.absolute()), readonly=readonly)
f = ifcopenshell_wrapper.open(str(path.absolute()), readonly, *((logger,) if logger is not None else ()))
elif bypass_types:
f = ifcopenshell_wrapper.file(ifcopenshell_wrapper.uninitialized_tag())
f = ifcopenshell_wrapper.file(
ifcopenshell_wrapper.uninitialized_tag(), *((logger,) if logger is not None else ())
)
for ty in bypass_types:
f.bypass_type(ty)
if mmap:
@@ -228,9 +248,12 @@ def open(
f.initialize(str(path.absolute()))
elif mmap:
# mmap parameter is only available for builds with USE_MMAP, not used in our main builds
f = ifcopenshell_wrapper.open(str(path.absolute()), mmap=mmap) # ty: ignore[unknown-argument]
kwargs = {"mmap": mmap}
if logger is not None:
kwargs["logger"] = logger
f = ifcopenshell_wrapper.open(str(path.absolute()), **kwargs) # ty: ignore[unknown-argument]
else:
f = ifcopenshell_wrapper.open(str(path.absolute()))
f = ifcopenshell_wrapper.open(str(path.absolute()), False, *((logger,) if logger is not None else ()))
f.post_init()
@@ -416,4 +439,3 @@ def convert_path_to_rocksdb(
version_core = ifcopenshell_wrapper.version()
__version__ = version = "0.0.0"
get_log = ifcopenshell_wrapper.get_log
@@ -16,8 +16,6 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
import numpy as np
import ifcopenshell
import ifcopenshell.util.placement
from ifcopenshell import entity_instance
@@ -36,7 +34,7 @@ def update_fallback_position(file: ifcopenshell.file, lp: entity_instance):
if not lp.CartesianPosition:
lp.CartesianPosition = file.createIfcAxis2Placement3D(Location=file.createIfcCartesianPoint((0.0, 0.0, 0.0)))
p = np.array(ifcopenshell.util.placement.get_axis2placement(lp.RelativePlacement))
p = ifcopenshell.util.placement.get_local_placement(lp)
x = float(p[0, 3])
y = float(p[1, 3])
@@ -16,10 +16,15 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
import ifcopenshell.api.cost
import ifcopenshell.api.control
import ast
import operator
from typing import Any
import ifcopenshell.api.control
import ifcopenshell.api.cost
import ifcopenshell.util.element
def assign_cost_item_quantity(
@@ -27,6 +32,8 @@ def assign_cost_item_quantity(
cost_item: ifcopenshell.entity_instance,
products: list[ifcopenshell.entity_instance],
prop_name: str = "",
formula: str = "",
ifc_class: str = "IfcQuantityLength",
) -> None:
"""Adds a cost item quantity that is parametrically connected to a product
@@ -57,6 +64,12 @@ def assign_cost_item_quantity(
:param prop_name: The name of the quantity. If this is not specified,
then it is assumed that there is no calculated quantity, and the
number of objects are counted instead.
:param formula: The string that contains the formula
:param ifc_class: The quantity class of the calculated value if the formula is
specified. Can be ['IfcQuantityCount', 'IfcQuantityNumber',
'IfcQuantityLength', 'IfcQuantityArea', 'IfcQuantityVolume',
'IfcQuantityWeight', 'IfcQuantityTime']. Check
ifcopenshell.util.unit.QUANTITY_CLASS for more info.
:return: None
Example:
@@ -84,6 +97,18 @@ def assign_cost_item_quantity(
# item.
ifcopenshell.api.cost.assign_cost_item_quantity(model,
cost_item=item, products=[slab], prop_name="NetVolume")
# Now let's use the formula in order to calculate the quantity value.
# For example, let's say that a IfcWall has the reinfocement volume ratio
# stored in the Pset_ConcreteElementGeneral.ReinforcementVolumeRatio
# and of course it has also the gross volume stored in the
# Qto_WallBaseQuantities.GrossVolume. So we can add an IfcQuantity that stores the
# reinforcement volume calculated with reinfocement volume ratio * gross volume.
ifcopenshell.api.cost.assign_cost_item_quantity(model,
cost_item=item, products=[wall],
formula="Pset_ConcreteElementGeneral.ReinforcementVolumeRatio * NetVolume"
ifc_class="IfcQuantityVolume")
"""
usecase = Usecase()
usecase.file = file
@@ -91,6 +116,8 @@ def assign_cost_item_quantity(
"cost_item": cost_item,
"products": products or [],
"prop_name": prop_name,
"formula": formula,
"ifc_class" : ifc_class
}
return usecase.execute()
@@ -100,12 +127,50 @@ class Usecase:
settings: dict[str, Any]
def execute(self):
if self.settings["prop_name"]:
if self.settings["prop_name"] or self.settings["formula"]:
self.quantities = set(self.settings["cost_item"].CostQuantities or [])
for product in self.settings["products"]:
if product.is_a("IfcSpatialElement"):
continue
self.assign_cost_control(related_object=product, cost_item=self.settings["cost_item"])
if self.settings["formula"]:
tree = ast.parse(self.settings["formula"], mode = "eval")
collector = VariableExtractor()
collector.visit(tree)
variables = collector.variables
for variable in variables:
getter = self.get_value_from_pset if "." in variable else self.get_value_from_qset
value = getter(product, variable)
if value is None:
print(
f"WARNING: Variable '{variable}' in product '{product.Name}' "
f"is missing (None). Check Pset/Qset or property name."
)
elif value == 0:
print(
f"WARNING: Variable '{variable}' in product '{product.Name}' "
f"has value 0. Verify if this is correct."
)
evaluator = FormulaEvaluator(values)
result = evaluator.visit(tree.body)
new_quantity = None
for quantity in self.quantities:
if quantity.Formula == self.settings["formula"] and len(self.settings["products"]) == 1: #Todo improve it
new_quantity = quantity
self.settings["ifc_class"] = quantity.is_a()
continue
if new_quantity is None:
new_quantity = self.file.create_entity(self.settings["ifc_class"], Name="Unnamed")
new_quantity.Formula = self.settings["formula"]
self.quantities.add(new_quantity)
new_quantity[3] = result
continue
if self.settings["prop_name"]:
if (
self.settings["cost_item"].CostQuantities
@@ -113,11 +178,30 @@ class Usecase:
):
continue
self.add_quantity_from_related_object(product)
if self.settings["prop_name"]:
if self.settings["prop_name"] or self.settings["formula"]:
self.settings["cost_item"].CostQuantities = list(self.quantities)
else:
self.update_cost_item_count()
def get_value_from_pset(
self,
product:ifcopenshell.entity_instance,
v: str,
) -> float:
pset_name = v.split(".")[0]
pset = ifcopenshell.util.element.get_pset(product, pset_name)
pset_property_name = v.split(".")[1]
return (pset or {}).get(pset_property_name,None)
def get_value_from_qset(
self,
product:ifcopenshell.entity_instance,
v: str,
) -> float:
qtos = ifcopenshell.util.element.get_psets(product, qtos_only = True)
quantities = next(iter(qtos.values()), {})
return (quantities or {}).get(v,None)
def assign_cost_control(
self, related_object: ifcopenshell.entity_instance, cost_item: ifcopenshell.entity_instance
) -> ifcopenshell.entity_instance:
@@ -158,3 +242,55 @@ class Usecase:
if not obj.is_a("IfcConstructionResource"):
count += 1
quantity[3] = count
OPERATORS = {
ast.Add: operator.add,
ast.Sub: operator.sub,
ast.Mult: operator.mul,
ast.Div: operator.truediv,
ast.Pow: operator.pow,
ast.USub: operator.neg,
}
def build_full_name(node):
#used for variables with dots
parts = []
while isinstance(node, ast.Attribute):
parts.append(node.attr)
node = node.value
if isinstance(node, ast.Name):
parts.append(node.id)
return ".".join(reversed(parts))
class VariableExtractor(ast.NodeVisitor):
def __init__(self):
self.variables = set()
def visit_Name(self, node):
self.variables.add(node.id)
def visit_Attribute(self, node):
self.variables.add(build_full_name(node))
class FormulaEvaluator(ast.NodeVisitor):
def __init__(self, values):
self.values = values
def visit_BinOp(self, node):
left = self.visit(node.left)
right = self.visit(node.right)
return OPERATORS[type(node.op)](left, right)
def visit_Name(self, node):
return self.values[node.id]
def visit_Attribute(self, node):
return self.values[build_full_name(node)]
def visit_Constant(self, node):
return node.value
def generic_visit(self, node):
raise ValueError(f"Operation not permitted: {type(node).__name__}")
@@ -44,7 +44,7 @@ def regenerate_wall_representation(
length: float = 1.0,
height: float = 1.0,
angle: Optional[float] = None,
) -> ifcopenshell.entity_instance:
) -> Optional[ifcopenshell.entity_instance]:
"""
Regenerate the body representation of a wall taking into account connections.
@@ -94,7 +94,10 @@ def regenerate_wall_representation(
default height in SI units.
:param angle: If the wall doesn't already have a slope, this is the default
angle in radians. Left as none or 0 defines no slope.
:return: The newly generated body IfcShapeRepresentation
:return: The newly generated body IfcShapeRepresentation, or ``None`` if
the wall has no ``IfcMaterialLayerSet`` (the layer-set rebuild is the
only mode this function knows; without layers there is nothing to
regenerate and callers should leave the existing representation alone).
"""
return Regenerator(file).regenerate(wall, length=length, height=height, angle=angle)
@@ -24,6 +24,7 @@ import ifcopenshell.api.owner
import ifcopenshell.api.type
import ifcopenshell.guid
import ifcopenshell.util.element
import ifcopenshell.util.type
def assign_type(
@@ -189,6 +190,32 @@ class Usecase:
if not related_objects:
return
# The EXPRESS schema has no WHERE rule pairing RelatingType /
# RelatedObjects classes; the canonical class pairing per schema
# is a buildingSMART implementer agreement, enforced here.
allowed_occurrences = set(
ifcopenshell.util.type.get_applicable_entities(relating_type.is_a(), schema=self.file.schema)
)
# The implementer agreement map has no entry for the abstract
# IfcTypeProduct, which Bonsai uses for annotation types. The schema
# itself defines IfcTypeProduct.ApplicableOccurrence for exactly this
# purpose, so honor it when the leading class token is a valid entity.
if applicable_occurrence := getattr(relating_type, "ApplicableOccurrence", None):
occurrence_class = applicable_occurrence.split("/", 1)[0]
schema = ifcopenshell.schema_by_name(self.file.schema)
try:
schema.declaration_by_name(occurrence_class)
allowed_occurrences.add(occurrence_class)
except RuntimeError:
pass
mismatched_classes = sorted({o.is_a() for o in related_objects if o.is_a() not in allowed_occurrences})
if mismatched_classes:
raise TypeError(
f"{relating_type.is_a()} cannot type {', '.join(mismatched_classes)} "
f"in schema {self.file.schema} (allowed occurrence classes: "
f"{', '.join(sorted(allowed_occurrences)) or '<none>'})"
)
ifc2x3 = self.file.schema == "IFC2X3"
related_objects_set = set(related_objects)
if ifc2x3:
+5 -2
View File
@@ -104,7 +104,10 @@ def main(
iterators: Sequence[ifcopenshell.geom.iterator] = (),
merge_projection: bool = True,
progress_function: Callable = DO_NOTHING,
logger=None,
):
if logger is None and ifcopenshell.logger is not None:
logger = ifcopenshell.logger.Root()
def by_guid(g):
for f in files:
@@ -146,7 +149,7 @@ def main(
iterator_kwargs["include"] = list(
filter(has_selected_parent, sum((f.by_type(x) for x in iterator_kwargs["include"]), []))
)
return ifcopenshell.geom.iterator(geom_settings, f, **iterator_kwargs)
return ifcopenshell.geom.iterator(geom_settings, f, logger=logger, **iterator_kwargs)
# We have to keep the iterator in memory because otherwise
# the styles are cleared up.
@@ -448,7 +451,6 @@ def main(
g1.appendChild(g2)
if settings.arrange_spaces or settings.arrange_zones:
if settings.storey_filter:
# delete storey groups not selected by filter
# sometimes happens in case of elements protruding multiple stories
@@ -531,6 +533,7 @@ def main(
arranged = W.arrange_polygons(
*filter(None, (ARRANGE_POLYGON_SETTINGS,)),
polies, # ty: ignore[too-many-positional-arguments]
*((logger,) if logger is not None else ()),
)
svg_data_3 = W.polygons_to_svg(arranged, False)
dom3 = parseString(svg_data_3)
@@ -213,8 +213,11 @@ class entity_instance_mixin:
return value
def __eq__(self, other: entity_instance_mixin) -> bool:
if other is None or not isinstance(other, entity_instance_mixin):
return False
if not isinstance(other, entity_instance_mixin):
if not self.is_entity():
return self[0] == other
else:
return False
else:
raise NotImplementedError
@@ -305,7 +308,7 @@ class entity_instance_mixin:
)
)
def get_info(
def get_info_py(
self,
include_identifier: bool = True,
recursive: bool = False,
@@ -382,64 +385,22 @@ class entity_instance_mixin:
__dict__ = property(get_info)
def get_info_2(
def get_info(
self,
include_identifier: bool = True,
recursive: bool = False,
return_type: type[dict] = dict,
ignore: Sequence[str] = (),
) -> dict[str, Any]:
"""More perfomant version of `.get_info()` but with limited arguments values.\n
Method has exactly the same signature as `.get_info()` but it doesn't support getting information non-recursively.
Currently supported arguments values:
* recursive: `True` (will fail with default `False` value from `.get_info()`)
* return_type: `dict`
* ignore: `()` (empty tuple)
"""More perfomant version of `.get_info()`.\n
Method has exactly the same signature as `.get_info()`, but the fast C++
path only implements ``recursive=True``, ``return_type=dict`` and
``ignore=()``. Any other combination falls back to the pure Python
`.get_info()`, where no meaningful performance gain is possible anyway
as the cost is dominated by the recursive traversal.
"""
assert return_type is dict
assert len(ignore) == 0
return ifcopenshell_wrapper.get_info_cpp(self, recursive, include_identifier)
# Alias for backwards compatibility — external code imports this name.
entity_instance = entity_instance_mixin
# Monkey-patch SWIG's __eq__, __ne__, __lt__ on the generated entity_instance
# class to guard against None / non-entity arguments. SWIG generates these
# directly on the class (overriding the mixin), and they pass arguments straight
# to C++ which rejects null references.
# Deferred until after ifcopenshell_wrapper finishes loading to avoid circular import.
_swig_comparisons_patched = False
def _patch_swig_comparisons():
global _swig_comparisons_patched
if _swig_comparisons_patched:
return
_swig_cls = ifcopenshell_wrapper.entity_instance
_orig_eq = _swig_cls.__eq__
_orig_ne = _swig_cls.__ne__
_orig_lt = _swig_cls.__lt__
def _safe_eq(self, other):
if other is None or not isinstance(other, _swig_cls):
return NotImplemented
return _orig_eq(self, other)
def _safe_ne(self, other):
if other is None or not isinstance(other, _swig_cls):
return NotImplemented
return _orig_ne(self, other)
def _safe_lt(self, other):
if other is None or not isinstance(other, _swig_cls):
return NotImplemented
return _orig_lt(self, other)
_swig_cls.__eq__ = _safe_eq
_swig_cls.__ne__ = _safe_ne
_swig_cls.__lt__ = _safe_lt
_swig_comparisons_patched = True
if recursive and return_type is dict and not ignore:
return ifcopenshell_wrapper.get_info_cpp(self.wrapped_data, include_identifier)
return self.get_info_py(
include_identifier=include_identifier, recursive=recursive, return_type=return_type, ignore=ignore
)
@@ -18,8 +18,6 @@
import os
import sys
import string
import operator
import itertools
@@ -158,6 +156,7 @@ actions = {
to_emit = set(id for id, expr in express)
emitted = set()
to_combine = set(["simple_id"])
to_original_text = set(["simple_string_literal"])
statements = []
terminals = reduce(lambda x, y: x | y, (find_bytype(e, Terminal) for id, e in express))
@@ -176,6 +175,9 @@ while True:
stmt = "(%s)" % expr
if id in to_combine:
stmt = " + ".join(itertools.chain(negated_keywords, ("originalTextFor(Combine%s)" % stmt,)))
elif id in to_original_text:
# We use lower() because it better matches the previous default of the CaselessLiterals for individual lexemes and express dictates case-insensitive comparisons anyway
stmt = "(originalTextFor%s).addParseAction(tokenMap(str.lower))" % 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))
@@ -193,6 +195,8 @@ for id in to_emit:
stmt = "(%s)" % expr
if id in to_combine:
stmt = "Suppress%s" % stmt
elif id in to_original_text:
stmt = "(originalTextFor%s).addParseAction(tokenMap(str.lower))" % stmt
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]))))
has_duplicates = len(children) > len(set(children))
@@ -204,7 +208,8 @@ for id in to_emit:
statements.append("%s << %s" % (id, stmt))
if __name__ == "__main__":
print(r"""
print(
r"""
# This file is generated by IfcOpenShell ifcexpressparser bootstrap.py
from __future__ import annotations
@@ -243,5 +248,6 @@ if __name__ == "__main__":
mdl = importlib.import_module(output)
mdl.Generator(m).emit()
sys.stdout.write(m.schema.name)
""" % ("\n ".join(statements))
"""
% ("\n ".join(statements))
)
@@ -153,8 +153,8 @@ def parse(fn: str) -> mapping.Mapping:
special = ((not_paren_star_quote_special | CaselessLiteral("(") | CaselessLiteral(")") | CaselessLiteral("*") | CaselessLiteral("\"\""))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="special"))("special")
binary_literal = ((CaselessLiteral("%") + bit + ZeroOrMore(bit))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="binary_literal"))("binary_literal")
integer_literal = (digits)("integer_literal")
simple_id = ~CaselessKeyword("generic") + ~CaselessKeyword("value") + ~CaselessKeyword("case") + ~CaselessKeyword("for") + ~CaselessKeyword("sin") + ~CaselessKeyword("value_unique") + ~CaselessKeyword("extensible") + ~CaselessKeyword("tan") + ~CaselessKeyword("local") + ~CaselessKeyword("string") + ~CaselessKeyword("procedure") + ~CaselessKeyword("derive") + ~CaselessKeyword("end_if") + ~CaselessKeyword("supertype") + ~CaselessKeyword("entity") + ~CaselessKeyword("oneof") + ~CaselessKeyword("constant") + ~CaselessKeyword("end_case") + ~CaselessKeyword("end_alias") + ~CaselessKeyword("unknown") + ~CaselessKeyword("total_over") + ~CaselessKeyword("div") + ~CaselessKeyword("type") + ~CaselessKeyword("true") + ~CaselessKeyword("end_repeat") + ~CaselessKeyword("unique") + ~CaselessKeyword("end_rule") + ~CaselessKeyword("number") + ~CaselessKeyword("end_function") + ~CaselessKeyword("where") + ~CaselessKeyword("self") + ~CaselessKeyword("usedin") + ~CaselessKeyword("end_type") + ~CaselessKeyword("logical") + ~CaselessKeyword("generic_entity") + ~CaselessKeyword("end_schema") + ~CaselessKeyword("xor") + ~CaselessKeyword("until") + ~CaselessKeyword("to") + ~CaselessKeyword("in") + ~CaselessKeyword("inverse") + ~CaselessKeyword("enumeration") + ~CaselessKeyword("var") + ~CaselessKeyword("value_in") + ~CaselessKeyword("const_e") + ~CaselessKeyword("use") + ~CaselessKeyword("exists") + ~CaselessKeyword("exp") + ~CaselessKeyword("while") + ~CaselessKeyword("if") + ~CaselessKeyword("fixed") + ~CaselessKeyword("subtype") + ~CaselessKeyword("format") + ~CaselessKeyword("as") + ~CaselessKeyword("and") + ~CaselessKeyword("rule") + ~CaselessKeyword("function") + ~CaselessKeyword("lobound") + ~CaselessKeyword("length") + ~CaselessKeyword("hiindex") + ~CaselessKeyword("log2") + ~CaselessKeyword("reference") + ~CaselessKeyword("skip") + ~CaselessKeyword("with") + ~CaselessKeyword("integer") + ~CaselessKeyword("sqrt") + ~CaselessKeyword("insert") + ~CaselessKeyword("nvl") + ~CaselessKeyword("log") + ~CaselessKeyword("boolean") + ~CaselessKeyword("from") + ~CaselessKeyword("rolesof") + ~CaselessKeyword("hibound") + ~CaselessKeyword("abs") + ~CaselessKeyword("like") + ~CaselessKeyword("pi") + ~CaselessKeyword("alias") + ~CaselessKeyword("not") + ~CaselessKeyword("repeat") + ~CaselessKeyword("based_on") + ~CaselessKeyword("subtype_constraint") + ~CaselessKeyword("asin") + ~CaselessKeyword("optional") + ~CaselessKeyword("list") + ~CaselessKeyword("abstract") + ~CaselessKeyword("mod") + ~CaselessKeyword("false") + ~CaselessKeyword("log10") + ~CaselessKeyword("loindex") + ~CaselessKeyword("aggregate") + ~CaselessKeyword("end_constant") + ~CaselessKeyword("end") + ~CaselessKeyword("sizeof") + ~CaselessKeyword("remove") + ~CaselessKeyword("acos") + ~CaselessKeyword("set") + ~CaselessKeyword("renamed") + ~CaselessKeyword("end_local") + ~CaselessKeyword("of") + ~CaselessKeyword("escape") + ~CaselessKeyword("begin") + ~CaselessKeyword("select") + ~CaselessKeyword("end_procedure") + ~CaselessKeyword("else") + ~CaselessKeyword("end_subtype_constraint") + ~CaselessKeyword("cos") + ~CaselessKeyword("real") + ~CaselessKeyword("query") + ~CaselessKeyword("odd") + ~CaselessKeyword("andor") + ~CaselessKeyword("return") + ~CaselessKeyword("then") + ~CaselessKeyword("end_entity") + ~CaselessKeyword("array") + ~CaselessKeyword("blength") + ~CaselessKeyword("or") + ~CaselessKeyword("typeof") + ~CaselessKeyword("binary") + ~CaselessKeyword("atan") + ~CaselessKeyword("by") + ~CaselessKeyword("otherwise") + ~CaselessKeyword("bag") + ~CaselessKeyword("schema") + originalTextFor(Combine((letter + ZeroOrMore((letter | digit | CaselessLiteral("_"))))))("simple_id")
simple_string_literal = ((CaselessLiteral("'") + ZeroOrMore(((CaselessLiteral("'") + CaselessLiteral("'")) | not_quote)) + CaselessLiteral("'")))("simple_string_literal")
simple_id = ~CaselessKeyword("format") + ~CaselessKeyword("loindex") + ~CaselessKeyword("in") + ~CaselessKeyword("where") + ~CaselessKeyword("by") + ~CaselessKeyword("subtype") + ~CaselessKeyword("local") + ~CaselessKeyword("sin") + ~CaselessKeyword("case") + ~CaselessKeyword("false") + ~CaselessKeyword("entity") + ~CaselessKeyword("exp") + ~CaselessKeyword("hiindex") + ~CaselessKeyword("generic_entity") + ~CaselessKeyword("number") + ~CaselessKeyword("end_rule") + ~CaselessKeyword("schema") + ~CaselessKeyword("from") + ~CaselessKeyword("length") + ~CaselessKeyword("insert") + ~CaselessKeyword("real") + ~CaselessKeyword("like") + ~CaselessKeyword("hibound") + ~CaselessKeyword("if") + ~CaselessKeyword("end_schema") + ~CaselessKeyword("generic") + ~CaselessKeyword("extensible") + ~CaselessKeyword("pi") + ~CaselessKeyword("of") + ~CaselessKeyword("logical") + ~CaselessKeyword("rolesof") + ~CaselessKeyword("log") + ~CaselessKeyword("integer") + ~CaselessKeyword("or") + ~CaselessKeyword("odd") + ~CaselessKeyword("list") + ~CaselessKeyword("procedure") + ~CaselessKeyword("renamed") + ~CaselessKeyword("optional") + ~CaselessKeyword("log10") + ~CaselessKeyword("end_function") + ~CaselessKeyword("value_unique") + ~CaselessKeyword("fixed") + ~CaselessKeyword("repeat") + ~CaselessKeyword("rule") + ~CaselessKeyword("mod") + ~CaselessKeyword("exists") + ~CaselessKeyword("with") + ~CaselessKeyword("nvl") + ~CaselessKeyword("end_repeat") + ~CaselessKeyword("not") + ~CaselessKeyword("type") + ~CaselessKeyword("otherwise") + ~CaselessKeyword("lobound") + ~CaselessKeyword("query") + ~CaselessKeyword("function") + ~CaselessKeyword("reference") + ~CaselessKeyword("enumeration") + ~CaselessKeyword("oneof") + ~CaselessKeyword("bag") + ~CaselessKeyword("then") + ~CaselessKeyword("end_if") + ~CaselessKeyword("sizeof") + ~CaselessKeyword("end_procedure") + ~CaselessKeyword("end_type") + ~CaselessKeyword("string") + ~CaselessKeyword("end_case") + ~CaselessKeyword("return") + ~CaselessKeyword("end_entity") + ~CaselessKeyword("log2") + ~CaselessKeyword("end_alias") + ~CaselessKeyword("inverse") + ~CaselessKeyword("derive") + ~CaselessKeyword("select") + ~CaselessKeyword("for") + ~CaselessKeyword("set") + ~CaselessKeyword("aggregate") + ~CaselessKeyword("self") + ~CaselessKeyword("array") + ~CaselessKeyword("abs") + ~CaselessKeyword("tan") + ~CaselessKeyword("subtype_constraint") + ~CaselessKeyword("remove") + ~CaselessKeyword("to") + ~CaselessKeyword("acos") + ~CaselessKeyword("skip") + ~CaselessKeyword("end_subtype_constraint") + ~CaselessKeyword("end_local") + ~CaselessKeyword("use") + ~CaselessKeyword("abstract") + ~CaselessKeyword("sqrt") + ~CaselessKeyword("var") + ~CaselessKeyword("until") + ~CaselessKeyword("while") + ~CaselessKeyword("end") + ~CaselessKeyword("typeof") + ~CaselessKeyword("supertype") + ~CaselessKeyword("based_on") + ~CaselessKeyword("true") + ~CaselessKeyword("alias") + ~CaselessKeyword("total_over") + ~CaselessKeyword("andor") + ~CaselessKeyword("cos") + ~CaselessKeyword("div") + ~CaselessKeyword("and") + ~CaselessKeyword("const_e") + ~CaselessKeyword("unique") + ~CaselessKeyword("as") + ~CaselessKeyword("boolean") + ~CaselessKeyword("constant") + ~CaselessKeyword("escape") + ~CaselessKeyword("atan") + ~CaselessKeyword("unknown") + ~CaselessKeyword("asin") + ~CaselessKeyword("usedin") + ~CaselessKeyword("xor") + ~CaselessKeyword("else") + ~CaselessKeyword("blength") + ~CaselessKeyword("value_in") + ~CaselessKeyword("value") + ~CaselessKeyword("begin") + ~CaselessKeyword("binary") + ~CaselessKeyword("end_constant") + originalTextFor(Combine((letter + ZeroOrMore((letter | digit | CaselessLiteral("_"))))))("simple_id")
simple_string_literal = (originalTextFor((CaselessLiteral("'") + ZeroOrMore(((CaselessLiteral("'") + CaselessLiteral("'")) | not_quote)) + CaselessLiteral("'")))).addParseAction(tokenMap(str.lower))("simple_string_literal")
abstract_entity_declaration = (ABSTRACT)("abstract_entity_declaration")
abstract_supertype = ((ABSTRACT + SUPERTYPE + CaselessLiteral(";"))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="abstract_supertype"))("abstract_supertype")
add_like_op = ((CaselessLiteral("+") | CaselessLiteral("-") | OR | XOR)).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="add_like_op"))("add_like_op")
@@ -251,224 +251,224 @@ def parse(fn: str) -> mapping.Mapping:
constructed_types = ((enumeration_type | select_type)).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="constructed_types"))("constructed_types")
reference_clause = ((REFERENCE + FROM + schema_ref + Optional((CaselessLiteral("(") + resource_or_rename + ZeroOrMore((CaselessLiteral(",") + resource_or_rename)) + CaselessLiteral(")"))) + CaselessLiteral(";"))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="reference_clause"))("reference_clause")
interface_specification = ((reference_clause | use_clause)).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="interface_specification"))("interface_specification")
supertype_factor = Forward()("supertype_factor")
interval_item = Forward()("interval_item")
subtype_constraint = Forward()("subtype_constraint")
repeat_stmt = Forward()("repeat_stmt")
subsuper = Forward()("subsuper")
increment = Forward()("increment")
remark = Forward()("remark")
increment_control = Forward()("increment_control")
local_variable = Forward()("local_variable")
until_control = Forward()("until_control")
while_control = Forward()("while_control")
parameter = Forward()("parameter")
width = Forward()("width")
string_type = Forward()("string_type")
array_type = Forward()("array_type")
if_stmt = Forward()("if_stmt")
index = Forward()("index")
repetition = Forward()("repetition")
index_qualifier = Forward()("index_qualifier")
bound_1 = Forward()("bound_1")
procedure_decl = Forward()("procedure_decl")
entity_constructor = Forward()("entity_constructor")
inverse_clause = Forward()("inverse_clause")
function_head = Forward()("function_head")
formal_parameter = Forward()("formal_parameter")
interval_high = Forward()("interval_high")
entity_decl = Forward()("entity_decl")
abstract_supertype_declaration = Forward()("abstract_supertype_declaration")
index_1 = Forward()("index_1")
general_aggregation_types = Forward()("general_aggregation_types")
real_type = Forward()("real_type")
type_decl = Forward()("type_decl")
stmt = Forward()("stmt")
declaration = Forward()("declaration")
explicit_attr = Forward()("explicit_attr")
compound_stmt = Forward()("compound_stmt")
aggregation_types = Forward()("aggregation_types")
simple_factor = Forward()("simple_factor")
where_clause = Forward()("where_clause")
entity_head = Forward()("entity_head")
underlying_type = Forward()("underlying_type")
subtype_constraint_decl = Forward()("subtype_constraint_decl")
logical_expression = Forward()("logical_expression")
case_label = Forward()("case_label")
expression = Forward()("expression")
general_list_type = Forward()("general_list_type")
actual_parameter_list = Forward()("actual_parameter_list")
width_spec = Forward()("width_spec")
selector = Forward()("selector")
syntax = Forward()("syntax")
aggregate_source = Forward()("aggregate_source")
return_stmt = Forward()("return_stmt")
embedded_remark = Forward()("embedded_remark")
parameter_type = Forward()("parameter_type")
term = Forward()("term")
derived_attr = Forward()("derived_attr")
repeat_control = Forward()("repeat_control")
assignment_stmt = Forward()("assignment_stmt")
bag_type = Forward()("bag_type")
inverse_attr = Forward()("inverse_attr")
constant_body = Forward()("constant_body")
precision_spec = Forward()("precision_spec")
general_bag_type = Forward()("general_bag_type")
qualifiable_factor = Forward()("qualifiable_factor")
bound_2 = Forward()("bound_2")
instantiable_type = Forward()("instantiable_type")
general_set_type = Forward()("general_set_type")
supertype_rule = Forward()("supertype_rule")
factor = Forward()("factor")
list_type = Forward()("list_type")
one_of = Forward()("one_of")
aggregate_type = Forward()("aggregate_type")
entity_body = Forward()("entity_body")
generalized_types = Forward()("generalized_types")
case_stmt = Forward()("case_stmt")
binary_type = Forward()("binary_type")
local_decl = Forward()("local_decl")
alias_stmt = Forward()("alias_stmt")
simple_expression = Forward()("simple_expression")
general_array_type = Forward()("general_array_type")
interval = Forward()("interval")
procedure_head = Forward()("procedure_head")
function_decl = Forward()("function_decl")
supertype_expression = Forward()("supertype_expression")
set_type = Forward()("set_type")
primary = Forward()("primary")
procedure_call_stmt = Forward()("procedure_call_stmt")
simple_types = Forward()("simple_types")
query_expression = Forward()("query_expression")
index_2 = Forward()("index_2")
constant_decl = Forward()("constant_decl")
case_action = Forward()("case_action")
schema_body = Forward()("schema_body")
element = Forward()("element")
numeric_expression = Forward()("numeric_expression")
aggregate_initializer = Forward()("aggregate_initializer")
schema_decl = Forward()("schema_decl")
supertype_term = Forward()("supertype_term")
algorithm_head = Forward()("algorithm_head")
supertype_constraint = Forward()("supertype_constraint")
interval_low = Forward()("interval_low")
domain_rule = Forward()("domain_rule")
rule_decl = Forward()("rule_decl")
supertype_term = Forward()("supertype_term")
alias_stmt = Forward()("alias_stmt")
subtype_constraint_decl = Forward()("subtype_constraint_decl")
real_type = Forward()("real_type")
until_control = Forward()("until_control")
remark = Forward()("remark")
syntax = Forward()("syntax")
derived_attr = Forward()("derived_attr")
subtype_constraint = Forward()("subtype_constraint")
aggregation_types = Forward()("aggregation_types")
width = Forward()("width")
simple_expression = Forward()("simple_expression")
explicit_attr = Forward()("explicit_attr")
precision_spec = Forward()("precision_spec")
general_list_type = Forward()("general_list_type")
concrete_types = Forward()("concrete_types")
qualifier = Forward()("qualifier")
subtype_constraint_body = Forward()("subtype_constraint_body")
function_call = Forward()("function_call")
bound_spec = Forward()("bound_spec")
while_control = Forward()("while_control")
aggregate_type = Forward()("aggregate_type")
increment_control = Forward()("increment_control")
index_qualifier = Forward()("index_qualifier")
supertype_rule = Forward()("supertype_rule")
subsuper = Forward()("subsuper")
interval_low = Forward()("interval_low")
bound_2 = Forward()("bound_2")
index_1 = Forward()("index_1")
return_stmt = Forward()("return_stmt")
type_decl = Forward()("type_decl")
increment = Forward()("increment")
factor = Forward()("factor")
underlying_type = Forward()("underlying_type")
declaration = Forward()("declaration")
function_decl = Forward()("function_decl")
entity_constructor = Forward()("entity_constructor")
derive_clause = Forward()("derive_clause")
supertype_factor << (((supertype_term + ZeroOrMore((AND + supertype_term))))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="supertype_factor"))
interval_item << (simple_expression)
subtype_constraint << (((OF + CaselessLiteral("(") + supertype_expression + CaselessLiteral(")")))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="subtype_constraint"))
repeat_stmt << (((REPEAT + repeat_control + CaselessLiteral(";") + stmt + ZeroOrMore(stmt) + END_REPEAT + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="repeat_stmt"))
subsuper << (((Optional(supertype_constraint) + Optional(subtype_declaration)))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="subsuper"))
increment << (numeric_expression)
remark << (((embedded_remark | tail_remark))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="remark"))
increment_control << (((variable_id + CaselessLiteral(":=") + bound_1 + TO + bound_2 + Optional((BY + increment))))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="increment_control"))
local_variable << (((variable_id + ZeroOrMore((CaselessLiteral(",") + variable_id)) + CaselessLiteral(":") + parameter_type + Optional((CaselessLiteral(":=") + expression)) + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="local_variable"))
until_control << (((UNTIL + logical_expression))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="until_control"))
while_control << (((WHILE + logical_expression))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="while_control"))
parameter << (expression)
width << (numeric_expression)
string_type << (((STRING + Optional(width_spec)))).setParseAction(StringType)
array_type << (((ARRAY + bound_spec + OF + Optional(OPTIONAL) + Optional(UNIQUE) + instantiable_type))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="array_type"))
if_stmt << (((IF + logical_expression + THEN + stmt + ZeroOrMore(stmt) + Optional((ELSE + stmt + ZeroOrMore(stmt))) + END_IF + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="if_stmt"))
index << (numeric_expression)
repetition << (numeric_expression)
index_qualifier << (((CaselessLiteral("[") + index_1 + Optional((CaselessLiteral(":") + index_2)) + CaselessLiteral("]")))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="index_qualifier"))
bound_1 << (numeric_expression)
procedure_decl << (((procedure_head + algorithm_head + ZeroOrMore(stmt) + END_PROCEDURE + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="procedure_decl"))
entity_constructor << (((entity_ref + CaselessLiteral("(") + Optional((expression + ZeroOrMore((CaselessLiteral(",") + expression)))) + CaselessLiteral(")")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="entity_constructor"))
inverse_clause << (((INVERSE + inverse_attr + ZeroOrMore(inverse_attr)))).setParseAction(AttributeList)
function_head << (((FUNCTION + function_id + Optional((CaselessLiteral("(") + formal_parameter + ZeroOrMore((CaselessLiteral(";") + formal_parameter)) + CaselessLiteral(")"))) + CaselessLiteral(":") + parameter_type + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="function_head"))
formal_parameter << (((parameter_id + ZeroOrMore((CaselessLiteral(",") + parameter_id)) + CaselessLiteral(":") + parameter_type))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="formal_parameter"))
interval_high << (simple_expression)
entity_decl << (((entity_head + entity_body + END_ENTITY + CaselessLiteral(";")))).setParseAction(EntityDeclaration)
abstract_supertype_declaration << (((ABSTRACT + SUPERTYPE + Optional(subtype_constraint)))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="abstract_supertype_declaration"))
index_1 << (index)
general_aggregation_types << (((general_array_type | general_bag_type | general_list_type | general_set_type))).setParseAction(AggregationType)
real_type << (((REAL + Optional((CaselessLiteral("(") + precision_spec + CaselessLiteral(")")))))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="real_type"))
type_decl << (((TYPE + type_id + CaselessLiteral("=") + underlying_type + CaselessLiteral(";") + Optional(where_clause) + END_TYPE + CaselessLiteral(";")))).setParseAction(TypeDeclaration)
stmt << (((alias_stmt | assignment_stmt | case_stmt | compound_stmt | escape_stmt | if_stmt | null_stmt | procedure_call_stmt | repeat_stmt | return_stmt | skip_stmt))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="stmt"))
declaration << (((entity_decl | function_decl | procedure_decl | subtype_constraint_decl | type_decl))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="declaration"))
explicit_attr << (((attribute_decl + ZeroOrMore((CaselessLiteral(",") + attribute_decl)) + CaselessLiteral(":") + Optional(OPTIONAL) + parameter_type + CaselessLiteral(";")))).setParseAction(ExplicitAttribute)
compound_stmt << (((BEGIN + stmt + ZeroOrMore(stmt) + END + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="compound_stmt"))
aggregation_types << (((array_type | bag_type | list_type | set_type))).setParseAction(AggregationType)
simple_factor << (((aggregate_initializer | interval | query_expression | (Optional(unary_op) + ((CaselessLiteral("(") + expression + CaselessLiteral(")")) | primary)) | entity_constructor | enumeration_reference))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="simple_factor"))
where_clause << (((WHERE + domain_rule + CaselessLiteral(";") + ZeroOrMore((domain_rule + CaselessLiteral(";")))))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="where_clause"))
entity_head << (((ENTITY + entity_id + subsuper + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="entity_head"))
underlying_type << (((constructed_types | concrete_types))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="underlying_type"))
subtype_constraint_decl << (((subtype_constraint_head + subtype_constraint_body + END_SUBTYPE_CONSTRAINT + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="subtype_constraint_decl"))
logical_expression << (expression)
case_label << (expression)
expression << (((simple_expression + Optional((rel_op_extended + simple_expression))))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="expression"))
general_list_type << (((LIST + Optional(bound_spec) + OF + Optional(UNIQUE) + parameter_type))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="general_list_type"))
actual_parameter_list << (((CaselessLiteral("(") + Optional(parameter) + ZeroOrMore((CaselessLiteral(",") + parameter)) + CaselessLiteral(")")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="actual_parameter_list"))
width_spec << (((CaselessLiteral("(") + width + CaselessLiteral(")") + Optional(FIXED)))).setParseAction(WidthSpec)
selector << (expression)
syntax << (((schema_decl + ZeroOrMore(schema_decl)))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="syntax"))
aggregate_source << (simple_expression)
return_stmt << (((RETURN + Optional((CaselessLiteral("(") + expression + CaselessLiteral(")"))) + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="return_stmt"))
embedded_remark << (((CaselessLiteral("(*") + Optional(remark_tag) + ZeroOrMore(((not_paren_star + ZeroOrMore(not_paren_star)) | lparen_then_not_lparen_star | (CaselessLiteral("*") + ZeroOrMore(CaselessLiteral("*"))) | not_rparen_star_then_rparen | embedded_remark)) + CaselessLiteral("*)")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="embedded_remark"))
parameter_type << (((generalized_types | simple_types | named_types))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="parameter_type"))
term << (((factor + ZeroOrMore((multiplication_like_op + factor))))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="term"))
derived_attr << (((attribute_decl + CaselessLiteral(":") + parameter_type + CaselessLiteral(":=") + expression + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="derived_attr"))
repeat_control << (((Optional(increment_control) + Optional(while_control) + Optional(until_control)))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="repeat_control"))
assignment_stmt << (((general_ref + ZeroOrMore(qualifier) + CaselessLiteral(":=") + expression + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="assignment_stmt"))
bag_type << (((BAG + Optional(bound_spec) + OF + instantiable_type))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="bag_type"))
inverse_attr << (((attribute_decl + CaselessLiteral(":") + Optional(((SET | BAG) + Optional(bound_spec) + OF)) + entity_ref + FOR + Optional((entity_ref + CaselessLiteral("."))) + attribute_ref + CaselessLiteral(";")))).setParseAction(InverseAttribute)
constant_body << (((constant_id + CaselessLiteral(":") + instantiable_type + CaselessLiteral(":=") + expression + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="constant_body"))
precision_spec << (numeric_expression)
general_bag_type << (((BAG + Optional(bound_spec) + OF + parameter_type))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="general_bag_type"))
qualifiable_factor << (((function_call | attribute_ref | constant_factor | general_ref | population))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="qualifiable_factor"))
bound_2 << (numeric_expression)
instantiable_type << (((concrete_types | entity_ref))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="instantiable_type"))
general_set_type << (((SET + Optional(bound_spec) + OF + parameter_type))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="general_set_type"))
supertype_rule << (((SUPERTYPE + subtype_constraint))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="supertype_rule"))
factor << (((simple_factor + Optional((CaselessLiteral("**") + simple_factor))))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="factor"))
list_type << (((LIST + Optional(bound_spec) + OF + Optional(UNIQUE) + instantiable_type))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="list_type"))
one_of << (((ONEOF + CaselessLiteral("(") + supertype_expression + ZeroOrMore((CaselessLiteral(",") + supertype_expression)) + CaselessLiteral(")")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="one_of"))
aggregate_type << (((AGGREGATE + Optional((CaselessLiteral(":") + type_label)) + OF + parameter_type))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="aggregate_type"))
entity_body << (((ZeroOrMore(explicit_attr) + Optional(derive_clause) + Optional(inverse_clause) + Optional(unique_clause) + Optional(where_clause)))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="entity_body"))
generalized_types << (((aggregate_type | general_aggregation_types | generic_entity_type | generic_type))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="generalized_types"))
case_stmt << (((CASE + selector + OF + ZeroOrMore(case_action) + Optional((OTHERWISE + CaselessLiteral(":") + stmt)) + END_CASE + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="case_stmt"))
binary_type << (((BINARY + Optional(width_spec)))).setParseAction(BinaryType)
local_decl << (((LOCAL + local_variable + ZeroOrMore(local_variable) + END_LOCAL + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="local_decl"))
alias_stmt << (((ALIAS + variable_id + FOR + general_ref + ZeroOrMore(qualifier) + CaselessLiteral(";") + stmt + ZeroOrMore(stmt) + END_ALIAS + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="alias_stmt"))
simple_expression << (((term + ZeroOrMore((add_like_op + term))))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="simple_expression"))
general_array_type << (((ARRAY + Optional(bound_spec) + OF + Optional(OPTIONAL) + Optional(UNIQUE) + parameter_type))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="general_array_type"))
interval << (((CaselessLiteral("{") + interval_low + interval_op + interval_item + interval_op + interval_high + CaselessLiteral("}")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="interval"))
procedure_head << (((PROCEDURE + procedure_id + Optional((CaselessLiteral("(") + Optional(VAR) + formal_parameter + ZeroOrMore((CaselessLiteral(";") + Optional(VAR) + formal_parameter)) + CaselessLiteral(")"))) + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="procedure_head"))
function_decl << (((function_head + algorithm_head + stmt + ZeroOrMore(stmt) + END_FUNCTION + CaselessLiteral(";")))).setParseAction(FunctionDeclaration)
supertype_expression << (((supertype_factor + ZeroOrMore((ANDOR + supertype_factor))))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="supertype_expression"))
set_type << (((SET + Optional(bound_spec) + OF + instantiable_type))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="set_type"))
primary << (((literal | (qualifiable_factor + ZeroOrMore(qualifier))))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="primary"))
procedure_call_stmt << ((((built_in_procedure | procedure_ref) + actual_parameter_list + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="procedure_call_stmt"))
simple_types << (((binary_type | boolean_type | integer_type | logical_type | number_type | real_type | string_type))).setParseAction(SimpleType)
query_expression << (((QUERY + CaselessLiteral("(") + variable_id + CaselessLiteral("<*") + aggregate_source + CaselessLiteral("|") + logical_expression + CaselessLiteral(")")))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="query_expression"))
index_2 << (index)
constant_decl << (((CONSTANT + constant_body + ZeroOrMore(constant_body) + END_CONSTANT + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="constant_decl"))
case_action << (((case_label + ZeroOrMore((CaselessLiteral(",") + case_label)) + CaselessLiteral(":") + stmt))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="case_action"))
schema_body << (((ZeroOrMore(interface_specification) + Optional(constant_decl) + ZeroOrMore((declaration | rule_decl))))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="schema_body"))
element << (((expression + Optional((CaselessLiteral(":") + repetition))))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="element"))
numeric_expression << (simple_expression)
aggregate_initializer << (((CaselessLiteral("[") + Optional((element + ZeroOrMore((CaselessLiteral(",") + element)))) + CaselessLiteral("]")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="aggregate_initializer"))
schema_decl << (((SCHEMA + schema_id + Optional(schema_version_id) + CaselessLiteral(";") + schema_body + END_SCHEMA + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="schema_decl"))
supertype_term << (((one_of | (CaselessLiteral("(") + supertype_expression + CaselessLiteral(")")) | entity_ref))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="supertype_term"))
algorithm_head << (((ZeroOrMore(declaration) + Optional(constant_decl) + Optional(local_decl)))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="algorithm_head"))
supertype_constraint << (((abstract_supertype_declaration | abstract_entity_declaration | supertype_rule))).setParseAction(SuperTypeExpression)
interval_low << (simple_expression)
domain_rule << (((Optional((rule_label_id + CaselessLiteral(":"))) + expression))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="domain_rule"))
interval_item = Forward()("interval_item")
stmt = Forward()("stmt")
repeat_control = Forward()("repeat_control")
abstract_supertype_declaration = Forward()("abstract_supertype_declaration")
bound_spec = Forward()("bound_spec")
entity_decl = Forward()("entity_decl")
bound_1 = Forward()("bound_1")
inverse_clause = Forward()("inverse_clause")
logical_expression = Forward()("logical_expression")
numeric_expression = Forward()("numeric_expression")
string_type = Forward()("string_type")
formal_parameter = Forward()("formal_parameter")
generalized_types = Forward()("generalized_types")
function_head = Forward()("function_head")
constant_decl = Forward()("constant_decl")
actual_parameter_list = Forward()("actual_parameter_list")
subtype_constraint_body = Forward()("subtype_constraint_body")
procedure_decl = Forward()("procedure_decl")
case_action = Forward()("case_action")
term = Forward()("term")
general_aggregation_types = Forward()("general_aggregation_types")
function_call = Forward()("function_call")
where_clause = Forward()("where_clause")
local_variable = Forward()("local_variable")
aggregate_initializer = Forward()("aggregate_initializer")
binary_type = Forward()("binary_type")
index = Forward()("index")
case_stmt = Forward()("case_stmt")
general_set_type = Forward()("general_set_type")
procedure_call_stmt = Forward()("procedure_call_stmt")
instantiable_type = Forward()("instantiable_type")
general_array_type = Forward()("general_array_type")
set_type = Forward()("set_type")
supertype_factor = Forward()("supertype_factor")
index_2 = Forward()("index_2")
qualifiable_factor = Forward()("qualifiable_factor")
algorithm_head = Forward()("algorithm_head")
parameter_type = Forward()("parameter_type")
one_of = Forward()("one_of")
compound_stmt = Forward()("compound_stmt")
primary = Forward()("primary")
schema_decl = Forward()("schema_decl")
embedded_remark = Forward()("embedded_remark")
width_spec = Forward()("width_spec")
assignment_stmt = Forward()("assignment_stmt")
element = Forward()("element")
schema_body = Forward()("schema_body")
procedure_head = Forward()("procedure_head")
general_bag_type = Forward()("general_bag_type")
entity_head = Forward()("entity_head")
entity_body = Forward()("entity_body")
list_type = Forward()("list_type")
expression = Forward()("expression")
parameter = Forward()("parameter")
simple_types = Forward()("simple_types")
bag_type = Forward()("bag_type")
repetition = Forward()("repetition")
constant_body = Forward()("constant_body")
if_stmt = Forward()("if_stmt")
inverse_attr = Forward()("inverse_attr")
interval = Forward()("interval")
query_expression = Forward()("query_expression")
array_type = Forward()("array_type")
simple_factor = Forward()("simple_factor")
case_label = Forward()("case_label")
domain_rule = Forward()("domain_rule")
repeat_stmt = Forward()("repeat_stmt")
supertype_expression = Forward()("supertype_expression")
supertype_constraint = Forward()("supertype_constraint")
interval_high = Forward()("interval_high")
local_decl = Forward()("local_decl")
selector = Forward()("selector")
aggregate_source = Forward()("aggregate_source")
qualifier = Forward()("qualifier")
rule_decl << (((rule_head + algorithm_head + ZeroOrMore(stmt) + where_clause + END_RULE + CaselessLiteral(";")))).setParseAction(RuleDeclaration)
supertype_term << (((one_of | (CaselessLiteral("(") + supertype_expression + CaselessLiteral(")")) | entity_ref))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="supertype_term"))
alias_stmt << (((ALIAS + variable_id + FOR + general_ref + ZeroOrMore(qualifier) + CaselessLiteral(";") + stmt + ZeroOrMore(stmt) + END_ALIAS + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="alias_stmt"))
subtype_constraint_decl << (((subtype_constraint_head + subtype_constraint_body + END_SUBTYPE_CONSTRAINT + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="subtype_constraint_decl"))
real_type << (((REAL + Optional((CaselessLiteral("(") + precision_spec + CaselessLiteral(")")))))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="real_type"))
until_control << (((UNTIL + logical_expression))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="until_control"))
remark << (((embedded_remark | tail_remark))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="remark"))
syntax << (((schema_decl + ZeroOrMore(schema_decl)))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="syntax"))
derived_attr << (((attribute_decl + CaselessLiteral(":") + parameter_type + CaselessLiteral(":=") + expression + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="derived_attr"))
subtype_constraint << (((OF + CaselessLiteral("(") + supertype_expression + CaselessLiteral(")")))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="subtype_constraint"))
aggregation_types << (((array_type | bag_type | list_type | set_type))).setParseAction(AggregationType)
width << (numeric_expression)
simple_expression << (((term + ZeroOrMore((add_like_op + term))))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="simple_expression"))
explicit_attr << (((attribute_decl + ZeroOrMore((CaselessLiteral(",") + attribute_decl)) + CaselessLiteral(":") + Optional(OPTIONAL) + parameter_type + CaselessLiteral(";")))).setParseAction(ExplicitAttribute)
precision_spec << (numeric_expression)
general_list_type << (((LIST + Optional(bound_spec) + OF + Optional(UNIQUE) + parameter_type))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="general_list_type"))
concrete_types << (((aggregation_types | simple_types | type_ref))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="concrete_types"))
qualifier << (((attribute_qualifier | group_qualifier | index_qualifier))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="qualifier"))
subtype_constraint_body << (((Optional(abstract_supertype) + Optional(total_over) + Optional((supertype_expression + CaselessLiteral(";")))))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="subtype_constraint_body"))
function_call << ((((built_in_function | function_ref) + actual_parameter_list))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="function_call"))
bound_spec << (((CaselessLiteral("[") + bound_1 + CaselessLiteral(":") + bound_2 + CaselessLiteral("]")))).setParseAction(BoundSpecification)
while_control << (((WHILE + logical_expression))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="while_control"))
aggregate_type << (((AGGREGATE + Optional((CaselessLiteral(":") + type_label)) + OF + parameter_type))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="aggregate_type"))
increment_control << (((variable_id + CaselessLiteral(":=") + bound_1 + TO + bound_2 + Optional((BY + increment))))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="increment_control"))
index_qualifier << (((CaselessLiteral("[") + index_1 + Optional((CaselessLiteral(":") + index_2)) + CaselessLiteral("]")))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="index_qualifier"))
supertype_rule << (((SUPERTYPE + subtype_constraint))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="supertype_rule"))
subsuper << (((Optional(supertype_constraint) + Optional(subtype_declaration)))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="subsuper"))
interval_low << (simple_expression)
bound_2 << (numeric_expression)
index_1 << (index)
return_stmt << (((RETURN + Optional((CaselessLiteral("(") + expression + CaselessLiteral(")"))) + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="return_stmt"))
type_decl << (((TYPE + type_id + CaselessLiteral("=") + underlying_type + CaselessLiteral(";") + Optional(where_clause) + END_TYPE + CaselessLiteral(";")))).setParseAction(TypeDeclaration)
increment << (numeric_expression)
factor << (((simple_factor + Optional((CaselessLiteral("**") + simple_factor))))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="factor"))
underlying_type << (((constructed_types | concrete_types))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="underlying_type"))
declaration << (((entity_decl | function_decl | procedure_decl | subtype_constraint_decl | type_decl))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="declaration"))
function_decl << (((function_head + algorithm_head + stmt + ZeroOrMore(stmt) + END_FUNCTION + CaselessLiteral(";")))).setParseAction(FunctionDeclaration)
entity_constructor << (((entity_ref + CaselessLiteral("(") + Optional((expression + ZeroOrMore((CaselessLiteral(",") + expression)))) + CaselessLiteral(")")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="entity_constructor"))
derive_clause << (((DERIVE + derived_attr + ZeroOrMore(derived_attr)))).setParseAction(AttributeList)
interval_item << (simple_expression)
stmt << (((alias_stmt | assignment_stmt | case_stmt | compound_stmt | escape_stmt | if_stmt | null_stmt | procedure_call_stmt | repeat_stmt | return_stmt | skip_stmt))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="stmt"))
repeat_control << (((Optional(increment_control) + Optional(while_control) + Optional(until_control)))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="repeat_control"))
abstract_supertype_declaration << (((ABSTRACT + SUPERTYPE + Optional(subtype_constraint)))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="abstract_supertype_declaration"))
bound_spec << (((CaselessLiteral("[") + bound_1 + CaselessLiteral(":") + bound_2 + CaselessLiteral("]")))).setParseAction(BoundSpecification)
entity_decl << (((entity_head + entity_body + END_ENTITY + CaselessLiteral(";")))).setParseAction(EntityDeclaration)
bound_1 << (numeric_expression)
inverse_clause << (((INVERSE + inverse_attr + ZeroOrMore(inverse_attr)))).setParseAction(AttributeList)
logical_expression << (expression)
numeric_expression << (simple_expression)
string_type << (((STRING + Optional(width_spec)))).setParseAction(StringType)
formal_parameter << (((parameter_id + ZeroOrMore((CaselessLiteral(",") + parameter_id)) + CaselessLiteral(":") + parameter_type))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="formal_parameter"))
generalized_types << (((aggregate_type | general_aggregation_types | generic_entity_type | generic_type))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="generalized_types"))
function_head << (((FUNCTION + function_id + Optional((CaselessLiteral("(") + formal_parameter + ZeroOrMore((CaselessLiteral(";") + formal_parameter)) + CaselessLiteral(")"))) + CaselessLiteral(":") + parameter_type + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="function_head"))
constant_decl << (((CONSTANT + constant_body + ZeroOrMore(constant_body) + END_CONSTANT + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="constant_decl"))
actual_parameter_list << (((CaselessLiteral("(") + Optional(parameter) + ZeroOrMore((CaselessLiteral(",") + parameter)) + CaselessLiteral(")")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="actual_parameter_list"))
subtype_constraint_body << (((Optional(abstract_supertype) + Optional(total_over) + Optional((supertype_expression + CaselessLiteral(";")))))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="subtype_constraint_body"))
procedure_decl << (((procedure_head + algorithm_head + ZeroOrMore(stmt) + END_PROCEDURE + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="procedure_decl"))
case_action << (((case_label + ZeroOrMore((CaselessLiteral(",") + case_label)) + CaselessLiteral(":") + stmt))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="case_action"))
term << (((factor + ZeroOrMore((multiplication_like_op + factor))))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="term"))
general_aggregation_types << (((general_array_type | general_bag_type | general_list_type | general_set_type))).setParseAction(AggregationType)
function_call << ((((built_in_function | function_ref) + actual_parameter_list))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="function_call"))
where_clause << (((WHERE + domain_rule + CaselessLiteral(";") + ZeroOrMore((domain_rule + CaselessLiteral(";")))))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="where_clause"))
local_variable << (((variable_id + ZeroOrMore((CaselessLiteral(",") + variable_id)) + CaselessLiteral(":") + parameter_type + Optional((CaselessLiteral(":=") + expression)) + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="local_variable"))
aggregate_initializer << (((CaselessLiteral("[") + Optional((element + ZeroOrMore((CaselessLiteral(",") + element)))) + CaselessLiteral("]")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="aggregate_initializer"))
binary_type << (((BINARY + Optional(width_spec)))).setParseAction(BinaryType)
index << (numeric_expression)
case_stmt << (((CASE + selector + OF + ZeroOrMore(case_action) + Optional((OTHERWISE + CaselessLiteral(":") + stmt)) + END_CASE + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="case_stmt"))
general_set_type << (((SET + Optional(bound_spec) + OF + parameter_type))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="general_set_type"))
procedure_call_stmt << ((((built_in_procedure | procedure_ref) + actual_parameter_list + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="procedure_call_stmt"))
instantiable_type << (((concrete_types | entity_ref))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="instantiable_type"))
general_array_type << (((ARRAY + Optional(bound_spec) + OF + Optional(OPTIONAL) + Optional(UNIQUE) + parameter_type))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="general_array_type"))
set_type << (((SET + Optional(bound_spec) + OF + instantiable_type))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="set_type"))
supertype_factor << (((supertype_term + ZeroOrMore((AND + supertype_term))))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="supertype_factor"))
index_2 << (index)
qualifiable_factor << (((function_call | attribute_ref | constant_factor | general_ref | population))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="qualifiable_factor"))
algorithm_head << (((ZeroOrMore(declaration) + Optional(constant_decl) + Optional(local_decl)))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="algorithm_head"))
parameter_type << (((generalized_types | simple_types | named_types))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="parameter_type"))
one_of << (((ONEOF + CaselessLiteral("(") + supertype_expression + ZeroOrMore((CaselessLiteral(",") + supertype_expression)) + CaselessLiteral(")")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="one_of"))
compound_stmt << (((BEGIN + stmt + ZeroOrMore(stmt) + END + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="compound_stmt"))
primary << (((literal | (qualifiable_factor + ZeroOrMore(qualifier))))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="primary"))
schema_decl << (((SCHEMA + schema_id + Optional(schema_version_id) + CaselessLiteral(";") + schema_body + END_SCHEMA + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="schema_decl"))
embedded_remark << (((CaselessLiteral("(*") + Optional(remark_tag) + ZeroOrMore(((not_paren_star + ZeroOrMore(not_paren_star)) | lparen_then_not_lparen_star | (CaselessLiteral("*") + ZeroOrMore(CaselessLiteral("*"))) | not_rparen_star_then_rparen | embedded_remark)) + CaselessLiteral("*)")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="embedded_remark"))
width_spec << (((CaselessLiteral("(") + width + CaselessLiteral(")") + Optional(FIXED)))).setParseAction(WidthSpec)
assignment_stmt << (((general_ref + ZeroOrMore(qualifier) + CaselessLiteral(":=") + expression + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="assignment_stmt"))
element << (((expression + Optional((CaselessLiteral(":") + repetition))))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="element"))
schema_body << (((ZeroOrMore(interface_specification) + Optional(constant_decl) + ZeroOrMore((declaration | rule_decl))))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="schema_body"))
procedure_head << (((PROCEDURE + procedure_id + Optional((CaselessLiteral("(") + Optional(VAR) + formal_parameter + ZeroOrMore((CaselessLiteral(";") + Optional(VAR) + formal_parameter)) + CaselessLiteral(")"))) + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="procedure_head"))
general_bag_type << (((BAG + Optional(bound_spec) + OF + parameter_type))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="general_bag_type"))
entity_head << (((ENTITY + entity_id + subsuper + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="entity_head"))
entity_body << (((ZeroOrMore(explicit_attr) + Optional(derive_clause) + Optional(inverse_clause) + Optional(unique_clause) + Optional(where_clause)))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="entity_body"))
list_type << (((LIST + Optional(bound_spec) + OF + Optional(UNIQUE) + instantiable_type))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="list_type"))
expression << (((simple_expression + Optional((rel_op_extended + simple_expression))))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="expression"))
parameter << (expression)
simple_types << (((binary_type | boolean_type | integer_type | logical_type | number_type | real_type | string_type))).setParseAction(SimpleType)
bag_type << (((BAG + Optional(bound_spec) + OF + instantiable_type))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="bag_type"))
repetition << (numeric_expression)
constant_body << (((constant_id + CaselessLiteral(":") + instantiable_type + CaselessLiteral(":=") + expression + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="constant_body"))
if_stmt << (((IF + logical_expression + THEN + stmt + ZeroOrMore(stmt) + Optional((ELSE + stmt + ZeroOrMore(stmt))) + END_IF + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="if_stmt"))
inverse_attr << (((attribute_decl + CaselessLiteral(":") + Optional(((SET | BAG) + Optional(bound_spec) + OF)) + entity_ref + FOR + Optional((entity_ref + CaselessLiteral("."))) + attribute_ref + CaselessLiteral(";")))).setParseAction(InverseAttribute)
interval << (((CaselessLiteral("{") + interval_low + interval_op + interval_item + interval_op + interval_high + CaselessLiteral("}")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="interval"))
query_expression << (((QUERY + CaselessLiteral("(") + variable_id + CaselessLiteral("<*") + aggregate_source + CaselessLiteral("|") + logical_expression + CaselessLiteral(")")))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="query_expression"))
array_type << (((ARRAY + bound_spec + OF + Optional(OPTIONAL) + Optional(UNIQUE) + instantiable_type))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="array_type"))
simple_factor << (((aggregate_initializer | interval | query_expression | (Optional(unary_op) + ((CaselessLiteral("(") + expression + CaselessLiteral(")")) | primary)) | entity_constructor | enumeration_reference))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="simple_factor"))
case_label << (expression)
domain_rule << (((Optional((rule_label_id + CaselessLiteral(":"))) + expression))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="domain_rule"))
repeat_stmt << (((REPEAT + repeat_control + CaselessLiteral(";") + stmt + ZeroOrMore(stmt) + END_REPEAT + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="repeat_stmt"))
supertype_expression << (((supertype_factor + ZeroOrMore((ANDOR + supertype_factor))))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="supertype_expression"))
supertype_constraint << (((abstract_supertype_declaration | abstract_entity_declaration | supertype_rule))).setParseAction(SuperTypeExpression)
interval_high << (simple_expression)
local_decl << (((LOCAL + local_variable + ZeroOrMore(local_variable) + END_LOCAL + CaselessLiteral(";")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="local_decl"))
selector << (expression)
aggregate_source << (simple_expression)
qualifier << (((attribute_qualifier | group_qualifier | index_qualifier))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="qualifier"))
syntax.ignore("--" + restOfLine)
syntax.ignore(Regex(r"\((?:\*(?:[^*]*\*+)+?\))"))
@@ -695,6 +695,14 @@ codegen_rule("MOD", lambda context: "%")
codegen_rule("TRUE", lambda context: "True")
codegen_rule("FALSE", lambda context: "False")
def _dotted_name(node: ast.AST):
"""Return dotted name for Name/Attribute chains, else None."""
if isinstance(node, ast.Name):
return node.id
if isinstance(node, ast.Attribute):
base = _dotted_name(node.value)
return f"{base}.{node.attr}" if base else node.attr
return None
class AttributeGetattrTransformer(ast.NodeTransformer):
def visit_Attribute(self, node):
@@ -712,7 +720,7 @@ class AttributeGetattrTransformer(ast.NodeTransformer):
if isinstance(node.ctx, ast.Store):
return node
if node.attr == "create_entity":
if _dotted_name(node) in ('ifcopenshell.create_entity', 'str.lower'):
return node
if node.attr.startswith("__"):
@@ -4686,7 +4686,7 @@ class IfcCurveStyle_WR11:
@staticmethod
def __call__(self):
curvewidth = express_getattr(self, 'CurveWidth', INDETERMINATE)
assert (not exists(curvewidth) or 'ifc2x3.ifcpositivelengthmeasure' in typeof(curvewidth) or ('ifc2x3.ifcdescriptivemeasure' in typeof(curvewidth) and curvewidth == 'bylayer')) is not False
assert (not exists(curvewidth) or 'ifc2x3.ifcpositivelengthmeasure' in typeof(curvewidth) or ('ifc2x3.ifcdescriptivemeasure' in typeof(curvewidth) and curvewidth == 'by layer')) is not False
class IfcCurveStyleFontPattern_WR01:
SCOPE = 'entity'
@@ -4947,7 +4947,7 @@ class IfcDraughtingPreDefinedColour_WR31:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['black', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white', 'bylayer']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['black', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white', 'by layer']) is not False
class IfcDraughtingPreDefinedCurveFont_WR31:
SCOPE = 'entity'
@@ -4956,7 +4956,7 @@ class IfcDraughtingPreDefinedCurveFont_WR31:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['continuous', 'chain', 'chaindoubledash', 'dashed', 'dotted', 'bylayer']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['continuous', 'chain', 'chain double dash', 'dashed', 'dotted', 'by layer']) is not False
class IfcDraughtingPreDefinedTextFont_WR31:
SCOPE = 'entity'
@@ -4965,7 +4965,7 @@ class IfcDraughtingPreDefinedTextFont_WR31:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['iso3098-1fonta', 'iso3098-1fontb']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['iso 3098-1 font a', 'iso 3098-1 font b']) is not False
class IfcDuctFittingType_WR2:
SCOPE = 'entity'
@@ -5795,7 +5795,7 @@ class IfcPreDefinedDimensionSymbol_WR31:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['arclength', 'conicaltaper', 'counterbore', 'countersink', 'depth', 'diameter', 'plusminus', 'radius', 'slope', 'sphericaldiameter', 'sphericalradius', 'square']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['arc length', 'conical taper', 'counterbore', 'countersink', 'depth', 'diameter', 'plus minus', 'radius', 'slope', 'spherical diameter', 'spherical radius', 'square']) is not False
class IfcPreDefinedPointMarkerSymbol_WR31:
SCOPE = 'entity'
@@ -5813,7 +5813,7 @@ class IfcPreDefinedTerminatorSymbol_WR31:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['blankedarrow', 'blankedbox', 'blankeddot', 'dimensionorigin', 'filledarrow', 'filledbox', 'filleddot', 'integralsymbol', 'openarrow', 'slash', 'unfilledarrow']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['blanked arrow', 'blanked box', 'blanked dot', 'dimension origin', 'filled arrow', 'filled box', 'filled dot', 'integral symbol', 'open arrow', 'slash', 'unfilled arrow']) is not False
class IfcProcedure_WR1:
SCOPE = 'entity'
@@ -6799,7 +6799,7 @@ class IfcStructuredDimensionCallout_WR31:
@staticmethod
def __call__(self):
contents = express_getattr(self, 'Contents', INDETERMINATE)
assert (sizeof([ato for ato in [con for con in express_getattr(self, 'contents', INDETERMINATE) if 'ifc2x3.ifcannotationtextoccurrence' in typeof(con)] if not express_getattr(express_getattr(ato, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['dimensionvalue', 'tolerancevalue', 'unittext', 'prefixtext', 'suffixtext']]) == 0) is not False
assert (sizeof([ato for ato in [con for con in express_getattr(self, 'contents', INDETERMINATE) if 'ifc2x3.ifcannotationtextoccurrence' in typeof(con)] if not express_getattr(express_getattr(ato, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['dimension value', 'tolerance value', 'unit text', 'prefix text', 'suffix text']]) == 0) is not False
class IfcStyledItem_WR11:
SCOPE = 'entity'
@@ -6331,7 +6331,7 @@ class IfcCurveStyle_MeasureOfWidth:
@staticmethod
def __call__(self):
curvewidth = express_getattr(self, 'CurveWidth', INDETERMINATE)
assert (not exists(curvewidth) or 'ifc4.ifcpositivelengthmeasure' in typeof(curvewidth) or ('ifc4.ifcdescriptivemeasure' in typeof(curvewidth) and curvewidth == 'bylayer')) is not False
assert (not exists(curvewidth) or 'ifc4.ifcpositivelengthmeasure' in typeof(curvewidth) or ('ifc4.ifcdescriptivemeasure' in typeof(curvewidth) and curvewidth == 'by layer')) is not False
class IfcCurveStyle_IdentifiableCurveStyle:
SCOPE = 'entity'
@@ -6593,7 +6593,7 @@ class IfcDraughtingPreDefinedColour_PreDefinedColourNames:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['black', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white', 'bylayer']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['black', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white', 'by layer']) is not False
class IfcDraughtingPreDefinedCurveFont_PreDefinedCurveFontNames:
SCOPE = 'entity'
@@ -6602,7 +6602,7 @@ class IfcDraughtingPreDefinedCurveFont_PreDefinedCurveFontNames:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['continuous', 'chain', 'chaindoubledash', 'dashed', 'dotted', 'bylayer']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['continuous', 'chain', 'chain double dash', 'dashed', 'dotted', 'by layer']) is not False
class IfcDuctFitting_CorrectPredefinedType:
SCOPE = 'entity'
@@ -6422,7 +6422,7 @@ class IfcCurveStyle_MeasureOfWidth:
@staticmethod
def __call__(self):
curvewidth = express_getattr(self, 'CurveWidth', INDETERMINATE)
assert (not exists(curvewidth) or 'ifc4x1.ifcpositivelengthmeasure' in typeof(curvewidth) or ('ifc4x1.ifcdescriptivemeasure' in typeof(curvewidth) and curvewidth == 'bylayer')) is not False
assert (not exists(curvewidth) or 'ifc4x1.ifcpositivelengthmeasure' in typeof(curvewidth) or ('ifc4x1.ifcdescriptivemeasure' in typeof(curvewidth) and curvewidth == 'by layer')) is not False
class IfcCurveStyle_IdentifiableCurveStyle:
SCOPE = 'entity'
@@ -6684,7 +6684,7 @@ class IfcDraughtingPreDefinedColour_PreDefinedColourNames:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['black', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white', 'bylayer']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['black', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white', 'by layer']) is not False
class IfcDraughtingPreDefinedCurveFont_PreDefinedCurveFontNames:
SCOPE = 'entity'
@@ -6693,7 +6693,7 @@ class IfcDraughtingPreDefinedCurveFont_PreDefinedCurveFontNames:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['continuous', 'chain', 'chaindoubledash', 'dashed', 'dotted', 'bylayer']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['continuous', 'chain', 'chain double dash', 'dashed', 'dotted', 'by layer']) is not False
class IfcDuctFitting_CorrectPredefinedType:
SCOPE = 'entity'
@@ -6633,7 +6633,7 @@ class IfcCurveStyle_MeasureOfWidth:
@staticmethod
def __call__(self):
curvewidth = express_getattr(self, 'CurveWidth', INDETERMINATE)
assert (not exists(curvewidth) or 'ifc4x2.ifcpositivelengthmeasure' in typeof(curvewidth) or ('ifc4x2.ifcdescriptivemeasure' in typeof(curvewidth) and curvewidth == 'bylayer')) is not False
assert (not exists(curvewidth) or 'ifc4x2.ifcpositivelengthmeasure' in typeof(curvewidth) or ('ifc4x2.ifcdescriptivemeasure' in typeof(curvewidth) and curvewidth == 'by layer')) is not False
class IfcCurveStyle_IdentifiableCurveStyle:
SCOPE = 'entity'
@@ -6905,7 +6905,7 @@ class IfcDraughtingPreDefinedColour_PreDefinedColourNames:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['black', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white', 'bylayer']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['black', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white', 'by layer']) is not False
class IfcDraughtingPreDefinedCurveFont_PreDefinedCurveFontNames:
SCOPE = 'entity'
@@ -6914,7 +6914,7 @@ class IfcDraughtingPreDefinedCurveFont_PreDefinedCurveFontNames:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['continuous', 'chain', 'chaindoubledash', 'dashed', 'dotted', 'bylayer']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['continuous', 'chain', 'chain double dash', 'dashed', 'dotted', 'by layer']) is not False
class IfcDuctFitting_CorrectPredefinedType:
SCOPE = 'entity'
@@ -7403,7 +7403,7 @@ class IfcCurveStyle_MeasureOfWidth:
@staticmethod
def __call__(self):
curvewidth = express_getattr(self, 'CurveWidth', INDETERMINATE)
assert (not exists(curvewidth) or 'ifc4x3.ifcpositivelengthmeasure' in typeof(curvewidth) or ('ifc4x3.ifcdescriptivemeasure' in typeof(curvewidth) and curvewidth == 'bylayer')) is not False
assert (not exists(curvewidth) or 'ifc4x3.ifcpositivelengthmeasure' in typeof(curvewidth) or ('ifc4x3.ifcdescriptivemeasure' in typeof(curvewidth) and curvewidth == 'by layer')) is not False
class IfcCurveStyleFontPattern_VisibleLengthGreaterEqualZero:
SCOPE = 'entity'
@@ -7725,7 +7725,7 @@ class IfcDraughtingPreDefinedColour_PreDefinedColourNames:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['black', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white', 'bylayer']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['black', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white', 'by layer']) is not False
class IfcDraughtingPreDefinedCurveFont_PreDefinedCurveFontNames:
SCOPE = 'entity'
@@ -7734,7 +7734,7 @@ class IfcDraughtingPreDefinedCurveFont_PreDefinedCurveFontNames:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['continuous', 'chain', 'chaindoubledash', 'dashed', 'dotted', 'bylayer']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['continuous', 'chain', 'chain double dash', 'dashed', 'dotted', 'by layer']) is not False
class IfcDuctFitting_CorrectPredefinedType:
SCOPE = 'entity'
@@ -7352,7 +7352,7 @@ class IfcCurveStyle_MeasureOfWidth:
@staticmethod
def __call__(self):
curvewidth = express_getattr(self, 'CurveWidth', INDETERMINATE)
assert (not exists(curvewidth) or 'ifc4x3_add1.ifcpositivelengthmeasure' in typeof(curvewidth) or ('ifc4x3_add1.ifcdescriptivemeasure' in typeof(curvewidth) and curvewidth == 'bylayer')) is not False
assert (not exists(curvewidth) or 'ifc4x3_add1.ifcpositivelengthmeasure' in typeof(curvewidth) or ('ifc4x3_add1.ifcdescriptivemeasure' in typeof(curvewidth) and curvewidth == 'by layer')) is not False
class IfcCurveStyleFontPattern_VisibleLengthGreaterEqualZero:
SCOPE = 'entity'
@@ -7674,7 +7674,7 @@ class IfcDraughtingPreDefinedColour_PreDefinedColourNames:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['black', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white', 'bylayer']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['black', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white', 'by layer']) is not False
class IfcDraughtingPreDefinedCurveFont_PreDefinedCurveFontNames:
SCOPE = 'entity'
@@ -7683,7 +7683,7 @@ class IfcDraughtingPreDefinedCurveFont_PreDefinedCurveFontNames:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['continuous', 'chain', 'chaindoubledash', 'dashed', 'dotted', 'bylayer']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['continuous', 'chain', 'chain double dash', 'dashed', 'dotted', 'by layer']) is not False
class IfcDuctFitting_CorrectPredefinedType:
SCOPE = 'entity'
@@ -7356,7 +7356,7 @@ class IfcCurveStyle_MeasureOfWidth:
@staticmethod
def __call__(self):
curvewidth = express_getattr(self, 'CurveWidth', INDETERMINATE)
assert (not exists(curvewidth) or 'ifc4x3_add2.ifcpositivelengthmeasure' in typeof(curvewidth) or ('ifc4x3_add2.ifcdescriptivemeasure' in typeof(curvewidth) and curvewidth == 'bylayer')) is not False
assert (not exists(curvewidth) or 'ifc4x3_add2.ifcpositivelengthmeasure' in typeof(curvewidth) or ('ifc4x3_add2.ifcdescriptivemeasure' in typeof(curvewidth) and curvewidth == 'by layer')) is not False
class IfcCurveStyleFontPattern_VisibleLengthGreaterEqualZero:
SCOPE = 'entity'
@@ -7678,7 +7678,7 @@ class IfcDraughtingPreDefinedColour_PreDefinedColourNames:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['black', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white', 'bylayer']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['black', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white', 'by layer']) is not False
class IfcDraughtingPreDefinedCurveFont_PreDefinedCurveFontNames:
SCOPE = 'entity'
@@ -7687,7 +7687,7 @@ class IfcDraughtingPreDefinedCurveFont_PreDefinedCurveFontNames:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['continuous', 'chain', 'chaindoubledash', 'dashed', 'dotted', 'bylayer']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['continuous', 'chain', 'chain double dash', 'dashed', 'dotted', 'by layer']) is not False
class IfcDuctFitting_CorrectPredefinedType:
SCOPE = 'entity'
@@ -7263,7 +7263,7 @@ class IfcCurveStyle_MeasureOfWidth:
@staticmethod
def __call__(self):
curvewidth = express_getattr(self, 'CurveWidth', INDETERMINATE)
assert (not exists(curvewidth) or 'ifc4x3_rc1.ifcpositivelengthmeasure' in typeof(curvewidth) or ('ifc4x3_rc1.ifcdescriptivemeasure' in typeof(curvewidth) and curvewidth == 'bylayer')) is not False
assert (not exists(curvewidth) or 'ifc4x3_rc1.ifcpositivelengthmeasure' in typeof(curvewidth) or ('ifc4x3_rc1.ifcdescriptivemeasure' in typeof(curvewidth) and curvewidth == 'by layer')) is not False
class IfcCurveStyle_IdentifiableCurveStyle:
SCOPE = 'entity'
@@ -7577,7 +7577,7 @@ class IfcDraughtingPreDefinedColour_PreDefinedColourNames:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['black', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white', 'bylayer']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['black', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white', 'by layer']) is not False
class IfcDraughtingPreDefinedCurveFont_PreDefinedCurveFontNames:
SCOPE = 'entity'
@@ -7586,7 +7586,7 @@ class IfcDraughtingPreDefinedCurveFont_PreDefinedCurveFontNames:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['continuous', 'chain', 'chaindoubledash', 'dashed', 'dotted', 'bylayer']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['continuous', 'chain', 'chain double dash', 'dashed', 'dotted', 'by layer']) is not False
class IfcDuctFitting_CorrectPredefinedType:
SCOPE = 'entity'
@@ -7351,7 +7351,7 @@ class IfcCurveStyle_MeasureOfWidth:
@staticmethod
def __call__(self):
curvewidth = express_getattr(self, 'CurveWidth', INDETERMINATE)
assert (not exists(curvewidth) or 'ifc4x3_rc2.ifcpositivelengthmeasure' in typeof(curvewidth) or ('ifc4x3_rc2.ifcdescriptivemeasure' in typeof(curvewidth) and curvewidth == 'bylayer')) is not False
assert (not exists(curvewidth) or 'ifc4x3_rc2.ifcpositivelengthmeasure' in typeof(curvewidth) or ('ifc4x3_rc2.ifcdescriptivemeasure' in typeof(curvewidth) and curvewidth == 'by layer')) is not False
class IfcCurveStyle_IdentifiableCurveStyle:
SCOPE = 'entity'
@@ -7665,7 +7665,7 @@ class IfcDraughtingPreDefinedColour_PreDefinedColourNames:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['black', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white', 'bylayer']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['black', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white', 'by layer']) is not False
class IfcDraughtingPreDefinedCurveFont_PreDefinedCurveFontNames:
SCOPE = 'entity'
@@ -7674,7 +7674,7 @@ class IfcDraughtingPreDefinedCurveFont_PreDefinedCurveFontNames:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['continuous', 'chain', 'chaindoubledash', 'dashed', 'dotted', 'bylayer']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['continuous', 'chain', 'chain double dash', 'dashed', 'dotted', 'by layer']) is not False
class IfcDuctFitting_CorrectPredefinedType:
SCOPE = 'entity'
@@ -7354,7 +7354,7 @@ class IfcCurveStyle_MeasureOfWidth:
@staticmethod
def __call__(self):
curvewidth = express_getattr(self, 'CurveWidth', INDETERMINATE)
assert (not exists(curvewidth) or 'ifc4x3_rc3.ifcpositivelengthmeasure' in typeof(curvewidth) or ('ifc4x3_rc3.ifcdescriptivemeasure' in typeof(curvewidth) and curvewidth == 'bylayer')) is not False
assert (not exists(curvewidth) or 'ifc4x3_rc3.ifcpositivelengthmeasure' in typeof(curvewidth) or ('ifc4x3_rc3.ifcdescriptivemeasure' in typeof(curvewidth) and curvewidth == 'by layer')) is not False
class IfcCurveStyle_IdentifiableCurveStyle:
SCOPE = 'entity'
@@ -7698,7 +7698,7 @@ class IfcDraughtingPreDefinedColour_PreDefinedColourNames:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['black', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white', 'bylayer']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['black', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white', 'by layer']) is not False
class IfcDraughtingPreDefinedCurveFont_PreDefinedCurveFontNames:
SCOPE = 'entity'
@@ -7707,7 +7707,7 @@ class IfcDraughtingPreDefinedCurveFont_PreDefinedCurveFontNames:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['continuous', 'chain', 'chaindoubledash', 'dashed', 'dotted', 'bylayer']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['continuous', 'chain', 'chain double dash', 'dashed', 'dotted', 'by layer']) is not False
class IfcDuctFitting_CorrectPredefinedType:
SCOPE = 'entity'
@@ -7370,7 +7370,7 @@ class IfcCurveStyle_MeasureOfWidth:
@staticmethod
def __call__(self):
curvewidth = express_getattr(self, 'CurveWidth', INDETERMINATE)
assert (not exists(curvewidth) or 'ifc4x3_rc4.ifcpositivelengthmeasure' in typeof(curvewidth) or ('ifc4x3_rc4.ifcdescriptivemeasure' in typeof(curvewidth) and curvewidth == 'bylayer')) is not False
assert (not exists(curvewidth) or 'ifc4x3_rc4.ifcpositivelengthmeasure' in typeof(curvewidth) or ('ifc4x3_rc4.ifcdescriptivemeasure' in typeof(curvewidth) and curvewidth == 'by layer')) is not False
class IfcCurveStyle_IdentifiableCurveStyle:
SCOPE = 'entity'
@@ -7714,7 +7714,7 @@ class IfcDraughtingPreDefinedColour_PreDefinedColourNames:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['black', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white', 'bylayer']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['black', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white', 'by layer']) is not False
class IfcDraughtingPreDefinedCurveFont_PreDefinedCurveFontNames:
SCOPE = 'entity'
@@ -7723,7 +7723,7 @@ class IfcDraughtingPreDefinedCurveFont_PreDefinedCurveFontNames:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['continuous', 'chain', 'chaindoubledash', 'dashed', 'dotted', 'bylayer']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['continuous', 'chain', 'chain double dash', 'dashed', 'dotted', 'by layer']) is not False
class IfcDuctFitting_CorrectPredefinedType:
SCOPE = 'entity'
@@ -7329,7 +7329,7 @@ class IfcCurveStyle_MeasureOfWidth:
@staticmethod
def __call__(self):
curvewidth = express_getattr(self, 'CurveWidth', INDETERMINATE)
assert (not exists(curvewidth) or 'ifc4x3_tc1.ifcpositivelengthmeasure' in typeof(curvewidth) or ('ifc4x3_tc1.ifcdescriptivemeasure' in typeof(curvewidth) and curvewidth == 'bylayer')) is not False
assert (not exists(curvewidth) or 'ifc4x3_tc1.ifcpositivelengthmeasure' in typeof(curvewidth) or ('ifc4x3_tc1.ifcdescriptivemeasure' in typeof(curvewidth) and curvewidth == 'by layer')) is not False
class IfcCurveStyleFontPattern_VisibleLengthGreaterEqualZero:
SCOPE = 'entity'
@@ -7651,7 +7651,7 @@ class IfcDraughtingPreDefinedColour_PreDefinedColourNames:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['black', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white', 'bylayer']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['black', 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'white', 'by layer']) is not False
class IfcDraughtingPreDefinedCurveFont_PreDefinedCurveFontNames:
SCOPE = 'entity'
@@ -7660,7 +7660,7 @@ class IfcDraughtingPreDefinedCurveFont_PreDefinedCurveFontNames:
@staticmethod
def __call__(self):
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['continuous', 'chain', 'chaindoubledash', 'dashed', 'dotted', 'bylayer']) is not False
assert (express_getattr(express_getattr(self, 'Name', INDETERMINATE), 'lower', INDETERMINATE)() in ['continuous', 'chain', 'chain double dash', 'dashed', 'dotted', 'by layer']) is not False
class IfcDuctFitting_CorrectPredefinedType:
SCOPE = 'entity'
@@ -145,7 +145,8 @@ class configuration:
config.set(
"snippets",
"print all wall ids",
self.config_encode("""
self.config_encode(
"""
###########################################################################
# A simple script that iterates over all walls in the current model #
# and prints their Globally unique IDs (GUIDS) to the console window #
@@ -153,13 +154,15 @@ class configuration:
for wall in model.by_type("IfcWall"):
print ("wall with global id: "+str(wall.GlobalId))
""".lstrip()),
""".lstrip()
),
)
config.set(
"snippets",
"print properties of current selection",
self.config_encode("""
self.config_encode(
"""
###########################################################################
# A simple script that iterates over all IfcPropertySets of the currently #
# selected object and prints them to the console #
@@ -177,7 +180,8 @@ if selection:
for prop in relDefinesByProperties.RelatingPropertyDefinition.HasProperties:
print ("{:<20} :{}".format(prop.Name,prop.NominalValue.wrappedValue))
print ("\\n")
""".lstrip()),
""".lstrip()
),
)
with open(conf_file, "w") as configfile:
config.write(configfile)
@@ -300,13 +300,16 @@ class iterator(ifcopenshell_wrapper.Iterator):
include: Optional[Union[list[entity_instance], list[str]]] = None,
exclude: Optional[Union[list[entity_instance], list[str]]] = None,
geometry_library: GEOMETRY_LIBRARY = "opencascade",
logger=None,
):
self.settings = settings
if logger is None and (logger_type := getattr(ifcopenshell_wrapper, "logger", None)):
logger = logger_type.Root()
if isinstance(file_or_filename, file):
self.file = file
file_or_filename = file_or_filename
else:
file_or_filename = self.file = open(file_or_filename)
file_or_filename = self.file = open(file_or_filename, logger=logger)
if include is not None and exclude is not None:
raise ValueError("include and exclude cannot be specified simultaneously")
@@ -334,13 +337,18 @@ class iterator(ifcopenshell_wrapper.Iterator):
else:
initializer = ifcopenshell_wrapper.construct_iterator_with_include_exclude
self.this = initializer(
geometry_library, self.settings, file_or_filename, include_or_exclude, include is not None, num_threads
args = (
geometry_library,
self.settings,
file_or_filename,
include_or_exclude,
include is not None,
num_threads,
)
self.this = initializer(*args, *((logger,) if logger is not None else ()))
else:
self.this = ifcopenshell_wrapper.construct_iterator(
geometry_library, self.settings, file_or_filename, num_threads
)
args = (geometry_library, self.settings, file_or_filename, num_threads)
self.this = ifcopenshell_wrapper.construct_iterator(*args, *((logger,) if logger is not None else ()))
if has_occ:
@@ -454,6 +462,7 @@ def create_shape(
inst: entity_instance,
repr: Optional[entity_instance] = None,
geometry_library: GEOMETRY_LIBRARY = "opencascade",
logger: Optional[ifcopenshell.logger] = None,
) -> Union[ShapeType, ShapeElementType, ifcopenshell_wrapper.Transformation, utils.shape_tuple, TopoDS.TopoDS_Shape]:
"""
Returns a geometric interpretation of the IFC entity instance
@@ -500,9 +509,9 @@ def create_shape(
return wrap_shape_creation(
settings,
(
ifcopenshell_wrapper.create_shape(settings, inst, repr, geometry_library)
ifcopenshell_wrapper.create_shape(settings, inst, repr, geometry_library, *((logger,) if logger is not None else ()),)
if repr
else ifcopenshell_wrapper.create_shape(settings, inst, geometry_library)
else ifcopenshell_wrapper.create_shape(settings, inst, geometry_library, *((logger,) if logger is not None else ()),)
),
)
@@ -556,6 +565,7 @@ def iterate(
*,
with_progress: Literal[False] = False,
geometry_library: GEOMETRY_LIBRARY = "opencascade",
logger=None,
) -> Generator[IteratorOutput, None, None]: ...
@overload
def iterate(
@@ -567,6 +577,7 @@ def iterate(
*,
with_progress: Literal[True] = True,
geometry_library: GEOMETRY_LIBRARY = "opencascade",
logger=None,
) -> Generator[tuple[int, IteratorOutput], None, None]: ...
@overload
def iterate(
@@ -578,6 +589,7 @@ def iterate(
*,
with_progress: bool = False,
geometry_library: GEOMETRY_LIBRARY = "opencascade",
logger=None,
) -> Generator[Union[IteratorOutput, tuple[int, IteratorOutput]], None, None]: ...
def iterate(
settings: settings,
@@ -588,6 +600,7 @@ def iterate(
*,
with_progress: bool = False,
geometry_library: GEOMETRY_LIBRARY = "opencascade",
logger=None,
) -> Generator[Union[IteratorOutput, tuple[int, IteratorOutput]], None, None]:
"""Get a geometry iterator for the provided file."""
it = iterator(settings, file_or_filename, num_threads, include, exclude, geometry_library)
@@ -355,7 +355,8 @@ def get_cost_rate(
class CostValueUnserialiser:
def parse(self, formula: str):
l = lark.Lark("""start: formula
l = lark.Lark(
"""start: formula
formula: operand (operator operand)*
operand: value | category "(" formula ")"
value: NUMBER?
@@ -392,7 +393,8 @@ class CostValueUnserialiser:
NEWLINE: (CR? LF)+
%ignore WS // Disregard spaces in text
""")
"""
)
start = l.parse(formula)
return self.get_formula(start.children[0])
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
import functools
import json
import os
import time
@@ -148,6 +149,57 @@ def get_subtypes(
return get_classes(declaration)
def _enum_value_outside_target(attribute: ifcopenshell_wrapper.attribute, value: Any) -> bool:
"""``True`` when ``attribute`` is an enumeration and the string ``value``
is not in its declared items. Used by the Migrator to silently skip enum
values that exist in the source schema but not the target without
parsing C++ wrapper error strings."""
if not isinstance(value, str):
return False
try:
enum_items = ifcopenshell.util.attribute.get_enum_items(attribute)
except (AssertionError, AttributeError):
return False
return value not in enum_items
@functools.cache
def geometry_classes_introduced_after(target_schema: IFC_SCHEMA, source_schema: IFC_SCHEMA = "IFC4") -> frozenset[str]:
"""``IfcRepresentationItem`` subclasses present in ``source_schema`` but
missing in ``target_schema``.
Derived from the loaded schema declarations once per (source, target) pair
and cached. The result is the canonical set of geometry classes a
downgrade from ``source_schema`` to ``target_schema`` must convert
(``IfcPolygonalFaceSet``, ``IfcTriangulatedFaceSet``, ``IfcAdvancedBrep``,
B-splines, advanced surfaces, alignment curves on IFC4X3 2X3, ) or
purge. Defaults match the IFC4 IFC2X3 case for backwards compatibility
with the original caller."""
source = ifcopenshell_wrapper.schema_by_name(source_schema)
target = ifcopenshell_wrapper.schema_by_name(target_schema)
target_names = {decl.name() for decl in target.entities()}
result: set[str] = set()
for decl in source.entities():
if decl.name() in target_names:
continue
cursor: Any = decl
while cursor is not None:
if cursor.name() == "IfcRepresentationItem":
result.add(decl.name())
break
cursor = cursor.supertype()
return frozenset(result)
def ifc4_only_geometry_classes() -> frozenset[str]:
"""Backwards-compatible alias for the IFC4 → IFC2X3 geometry-gap set.
New code should call :func:`geometry_classes_introduced_after` with the
explicit (target, source) pair so IFC4X3 IFC2X3 downgrades pick up the
additional IFC4X3-only geometry classes."""
return geometry_classes_introduced_after("IFC2X3", "IFC4")
def reassign_class(
ifc_file: Union[ifcopenshell.file, None], element: ifcopenshell.entity_instance, new_class: str
) -> ifcopenshell.entity_instance:
@@ -263,7 +315,20 @@ class Migrator:
migrated_ids: dict[int, int]
attribute_overrides: dict[int, dict[int, str]]
def __init__(self):
def __init__(self, *, fallback_element_to_proxy: bool = False) -> None:
"""Construct a schema migrator.
:param fallback_element_to_proxy: When ``True`` and the target schema is
IFC2X3, IFC4 entity classes that have no direct IFC2X3 equivalent
but inherit from ``IfcElement`` / ``IfcElementType`` are migrated as
``IfcBuildingElementProxy`` / ``IfcBuildingElementProxyType``
respectively, instead of raising. Caller code is then responsible
for preserving the lost original class information out-of-band (the
``Migrate`` ifcpatch recipe encodes it into ``ObjectType``).
Defaults to ``False`` so non-recipe callers keep the strict
failure-on-unmappable contract.
"""
self.fallback_element_to_proxy = fallback_element_to_proxy
self.migrated_ids = {}
self.attribute_overrides = {}
self.class_4_to_2x3 = json.load(open(os.path.join(cwd, "class_4_to_2x3.json"), "r"))
@@ -379,6 +444,17 @@ class Migrator:
self.migrated_ids[element.id()] = new_element.id()
return new_element
@staticmethod
def _is_subclass_of(ifc_class: str, ancestor: str, source_file: ifcopenshell.file) -> bool:
schema = ifcopenshell_wrapper.schema_by_name(source_file.schema_identifier)
try:
return is_a(schema.declaration_by_name(ifc_class), ancestor)
except RuntimeError:
# Class doesn't exist in the source schema — happens for cross-schema
# introspection of an entity created with a name the wrapper doesn't
# recognise. Treat as "not a subclass".
return False
def migrate_class(
self, element: ifcopenshell.entity_instance, new_file: ifcopenshell.file
) -> ifcopenshell.entity_instance:
@@ -389,15 +465,44 @@ class Migrator:
if isinstance(value, float):
ifc_class = "IfcQuantityNumber"
try:
new_element = new_file.create_entity(ifc_class)
return new_file.create_entity(ifc_class)
except:
# The element does not exist in this schema
# Complex migration is not yet supported (e.g. polygonal face set to faceted brep)
if new_file.schema == "IFC2X3":
new_element = new_file.create_entity(self.class_4_to_2x3[ifc_class])
elif new_file.schema == "IFC4":
new_element = new_file.create_entity(self.class_2x3_to_4[ifc_class])
return new_element
pass
# The class does not exist in the target schema — look up an equivalent.
# The lookup tables use empty-string as a sentinel meaning "no direct
# equivalent, needs geometric translation" (e.g. polygonal face set →
# faceted brep). Callers that want a clean downgrade are expected to
# preprocess such carriers before calling the Migrator; see the
# `Migrate` ifcpatch recipe.
if new_file.schema == "IFC2X3":
equivalent = self.class_4_to_2x3.get(ifc_class, None)
elif new_file.schema == "IFC4":
equivalent = self.class_2x3_to_4.get(ifc_class, None)
else:
equivalent = None
# IfcBuildingElementProxy fallback is opt-in (see constructor) — only
# the IfcElement / IfcElementType subtrees have a meaningful generic
# IFC2X3 stand-in; non-element IFC4-only classes (rels, geometry items,
# materials, times) still raise below.
if not equivalent and new_file.schema == "IFC2X3" and self.fallback_element_to_proxy:
if self._is_subclass_of(ifc_class, "IfcElement", element.wrapped_data.file):
equivalent = "IfcBuildingElementProxy"
elif self._is_subclass_of(ifc_class, "IfcElementType", element.wrapped_data.file):
equivalent = "IfcBuildingElementProxyType"
if not equivalent:
inverses = element.wrapped_data.file.get_inverse(element)
inverse_hint = ", ".join(f"#{i.id()}={i.is_a()}" for i in list(inverses)[:3])
if len(inverses) > 3:
inverse_hint += f", … (+{len(inverses) - 3} more)"
raise NotImplementedError(
f"Cannot migrate #{element.id()}={ifc_class} to schema "
f"{new_file.schema}: no direct equivalent exists. "
f"Referenced by: {inverse_hint or '(no inverses)'}."
)
return new_file.create_entity(equivalent)
def migrate_attributes(
self,
@@ -526,11 +631,40 @@ class Migrator:
new_value.append(self.migrate(item, new_file))
value = new_value
if value is not None:
if _enum_value_outside_target(attribute, value):
# Enum value present in source schema but missing in target
# (typically a downgrade after a cross-class fallback, e.g.
# IfcLamp.PredefinedType=COMPACTFLUORESCENT copied onto
# IfcBuildingElementProxy.CompositionType whose enum is
# IfcElementCompositionEnum). Leave the attribute unset rather
# than abort the whole entity's migration. Detected
# structurally so other RuntimeError causes (type mismatches,
# invalid values) still propagate.
return
setattr(new_element, attribute.name(), value)
def generate_default_value(self, attribute: ifcopenshell_wrapper.attribute, new_file: ifcopenshell.file) -> Any:
if attribute.name() in self.default_values:
return self.default_values[attribute.name()]
elif attribute.name() == "Position":
# IFC4 relaxed Position to OPTIONAL for many profile defs; IFC2X3
# still requires it. Synthesize a unit placement at origin so
# IfcIShapeProfileDef and friends downgrade without crashing
# downstream validators.
try:
type_name = attribute.type_of_attribute().as_named_type().declared_type().name()
except Exception:
type_name = None
if type_name == "IfcAxis2Placement2D":
return new_file.create_entity(
"IfcAxis2Placement2D",
Location=new_file.create_entity("IfcCartesianPoint", (0.0, 0.0)),
)
if type_name == "IfcAxis2Placement3D":
return new_file.create_entity(
"IfcAxis2Placement3D",
Location=new_file.create_entity("IfcCartesianPoint", (0.0, 0.0, 0.0)),
)
elif attribute.name() == "OwnerHistory":
self.default_entities[attribute.name()] = new_file.create_entity(
"IfcOwnerHistory",
@@ -39,7 +39,8 @@ import ifcopenshell.util.shape
import ifcopenshell.util.system
import ifcopenshell.util.unit
filter_elements_grammar = lark.Lark("""start: filter_group
filter_elements_grammar = lark.Lark(
"""start: filter_group
filter_group: facet_list ("+" facet_list)*
facet_list: facet ("," facet)*
@@ -110,9 +111,11 @@ filter_elements_grammar = lark.Lark("""start: filter_group
NEWLINE: (CR? LF)+
%ignore WS // Disregard spaces in text
""")
"""
)
get_element_grammar = lark.Lark("""start: keys
get_element_grammar = lark.Lark(
"""start: keys
keys: key ("." key)*
key: quoted_string | regex_string | unquoted_string
@@ -127,9 +130,11 @@ get_element_grammar = lark.Lark("""start: keys
WS: /[ \\t\\f\\r\\n]/+
%ignore WS // Disregard spaces in text
""")
"""
)
format_grammar = lark.Lark("""start: expression
format_grammar = lark.Lark(
"""start: expression
?expression: add_sub
?add_sub: mul_div
@@ -188,7 +193,8 @@ format_grammar = lark.Lark("""start: expression
NEWLINE: (CR? LF)+
%ignore WS // Disregard spaces in text
""")
"""
)
class FormatTransformer(lark.Transformer):
@@ -21,7 +21,7 @@ from __future__ import annotations
import collections.abc
from collections.abc import Sequence
from itertools import chain
from math import atan, cos, degrees, pi, radians, sin, sqrt, tan
from math import atan, atan2, cos, degrees, hypot, isclose, pi, radians, sin, sqrt, tan
from typing import TYPE_CHECKING, Any, Literal, Optional, Union
import numpy as np
@@ -301,6 +301,130 @@ def intersect_x_axis_2d(p1: VectorType, p2: VectorType, y=0) -> Optional[float]:
return x1 + t * (x2 - x1)
def arc_to_polyline_points(
start: VectorType, mid: VectorType, end: VectorType, subdivisions: int = 16
) -> list[tuple[float, ...]]:
"""Approximate a circular arc through (start, mid, end) with chord points.
The arc is determined uniquely by three points a circle is fit in the
XY plane and the angle is walked from start through mid to end, sampling
``subdivisions + 1`` points inclusive of the endpoints. Falls back to a
straight chord ``[start, end]`` for collinear / degenerate inputs.
Only planar arcs in the XY plane are supported. For 3D inputs (length 3
tuples), the Z coordinate of each output point is held constant at
``start[2]``. Inputs where start/mid/end have differing Z values raise
``ValueError`` rather than silently project caller should rotate the
arc into the XY plane first if it lives in a non-axis-aligned plane.
:raises ValueError: if subdivisions < 1, or if 3D inputs have mismatched
Z coordinates (non-planar arc).
"""
if subdivisions < 1:
raise ValueError(f"subdivisions must be >= 1, got {subdivisions}")
if len(start) >= 3:
# Tolerance accommodates floating-point noise from kernel transforms
# — IFC point coordinates that the author wrote as the same Z value
# may diverge by ~1e-15 after placement-matrix round-trips.
z_tol = 1e-9
if not (isclose(start[2], mid[2], abs_tol=z_tol) and isclose(start[2], end[2], abs_tol=z_tol)):
raise ValueError(
f"arc_to_polyline_points only handles arcs in the XY plane; "
f"got mismatched Z coordinates ({start[2]}, {mid[2]}, {end[2]})."
)
sx, sy = start[0], start[1]
mx, my = mid[0], mid[1]
ex, ey = end[0], end[1]
d = 2 * (sx * (my - ey) + mx * (ey - sy) + ex * (sy - my))
if abs(d) < 1e-12:
return [tuple(start), tuple(end)]
cx = ((sx**2 + sy**2) * (my - ey) + (mx**2 + my**2) * (ey - sy) + (ex**2 + ey**2) * (sy - my)) / d
cy = ((sx**2 + sy**2) * (ex - mx) + (mx**2 + my**2) * (sx - ex) + (ex**2 + ey**2) * (mx - sx)) / d
a_start = atan2(sy - cy, sx - cx)
a_mid = atan2(my - cy, mx - cx)
a_end = atan2(ey - cy, ex - cx)
sweep = _signed_sweep_through_mid(a_start, a_mid, a_end)
radius = hypot(sx - cx, sy - cy)
pts: list[tuple[float, ...]] = []
for i in range(subdivisions + 1):
t = i / subdivisions
angle = a_start + sweep * t
x = cx + radius * cos(angle)
y = cy + radius * sin(angle)
if len(start) == 2:
pts.append((x, y))
else:
pts.append((x, y, start[2]))
return pts
def _signed_sweep_through_mid(a_start: float, a_mid: float, a_end: float) -> float:
"""Total angle (radians) from a_start to a_end going through a_mid."""
two_pi = 2 * pi
ccw_total = (a_end - a_start) % two_pi
ccw_to_mid = (a_mid - a_start) % two_pi
if ccw_to_mid <= ccw_total:
return ccw_total
return -((a_start - a_end) % two_pi)
def polygonal_face_set_to_faceted_brep(face_set: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
"""Convert an ``IfcPolygonalFaceSet`` or ``IfcTriangulatedFaceSet`` into an
``IfcFacetedBrep`` in the same file, preserving vertex coordinates and face
topology (including inner voids on ``IfcIndexedPolygonalFaceWithVoids``).
The returned brep is the canonical IFC2X3-compatible form of these IFC4
tessellated representations. The caller is responsible for rewiring inverse
references and removing the source face set when downgrading.
:raises TypeError: if ``face_set`` is not an ``IfcPolygonalFaceSet`` or
``IfcTriangulatedFaceSet``.
:raises ValueError: if ``face_set.Coordinates`` is missing or any face's
coordinate index references a vertex outside the coordinate list.
"""
if not (face_set.is_a("IfcPolygonalFaceSet") or face_set.is_a("IfcTriangulatedFaceSet")):
raise TypeError(
f"polygonal_face_set_to_faceted_brep expected IfcPolygonalFaceSet or "
f"IfcTriangulatedFaceSet, got {face_set.is_a()}."
)
if face_set.Coordinates is None:
raise ValueError(f"{face_set.is_a()} #{face_set.id()} has no Coordinates point list.")
ifc_file = face_set.file
coords = face_set.Coordinates.CoordList
vertex_count = len(coords)
ifc_points = [ifc_file.createIfcCartesianPoint(tuple(c)) for c in coords]
def _resolve(indices: Sequence[int]) -> list[ifcopenshell.entity_instance]:
# IfcIndexedPolygonalFace.CoordIndex / IfcTriangulatedFaceSet.CoordIndex
# are 1-based. Out-of-range hits early with a clear message rather
# than the cryptic IndexError from list[i-1].
out = []
for index in indices:
if not 1 <= index <= vertex_count:
raise ValueError(
f"{face_set.is_a()} #{face_set.id()} face references vertex {index}, "
f"outside CoordList range 1..{vertex_count}."
)
out.append(ifc_points[index - 1])
return out
ifc_faces: list[ifcopenshell.entity_instance] = []
if face_set.is_a("IfcTriangulatedFaceSet"):
for triangle in face_set.CoordIndex:
loop = ifc_file.createIfcPolyLoop(_resolve(triangle))
ifc_faces.append(ifc_file.createIfcFace([ifc_file.createIfcFaceOuterBound(loop, True)]))
else: # IfcPolygonalFaceSet
for indexed_face in face_set.Faces:
outer_loop = ifc_file.createIfcPolyLoop(_resolve(indexed_face.CoordIndex))
bounds = [ifc_file.createIfcFaceOuterBound(outer_loop, True)]
if indexed_face.is_a("IfcIndexedPolygonalFaceWithVoids"):
for inner in indexed_face.InnerCoordIndices or ():
bounds.append(ifc_file.createIfcFaceBound(ifc_file.createIfcPolyLoop(_resolve(inner)), True))
ifc_faces.append(ifc_file.createIfcFace(bounds))
return ifc_file.createIfcFacetedBrep(ifc_file.createIfcClosedShell(ifc_faces))
# Note: using ShapeBuilder try not to reuse IFC elements in the process
# otherwise you might run into situation where builder.mirror or other operation
# is applied twice during one run to the same element
@@ -912,6 +912,13 @@ def convert_file_length_units(ifc_file: ifcopenshell.file, target_units: str = "
new_value = convert_value(val)
setattr(element, attr.name(), new_value)
# IfcGeometricRepresentationContext.Precision is typed as a plain IfcReal
# but is interpreted in the project length unit, so it must be scaled too.
# Subcontexts derive Precision from their parent and cannot be set.
for context in file_patched.by_type("IfcGeometricRepresentationContext", include_subtypes=False):
if context.Precision is not None:
context.Precision = convert_unit(context.Precision, old_length, new_length)
has_map_unit = False
if (
ifc_file.schema == "IFC2X3"