mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-06 07:51:47 +00:00
Compare commits
90 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2c6082d94c | |||
| 821cf7b671 | |||
| e01979187a | |||
| 816eba5145 | |||
| 4963bddd06 | |||
| 8718db63da | |||
| c013b9aca7 | |||
| 24e454ce0c | |||
| cb497b37f7 | |||
| 71c6950a59 | |||
| 5a8aa0a659 | |||
| f4526d152f | |||
| a7a7edfd27 | |||
| 6ca8c8ac94 | |||
| 5273569b08 | |||
| 78712ead98 | |||
| 6efb8a4373 | |||
| 9e25c12b16 | |||
| 0968d06780 | |||
| 3a8619726b | |||
| 1b1da821f1 | |||
| d772b24bd6 | |||
| 549f81a76e | |||
| e5c7206a37 | |||
| 5b968d5c75 | |||
| 6075187720 | |||
| 92528d84cd | |||
| 3955718145 | |||
| 501246cd0b | |||
| 1b863ff8be | |||
| dcd88b6cdd | |||
| fb8b2ee878 | |||
| 8a00ce84cc | |||
| 4032bbbd17 | |||
| d728f09d86 | |||
| 3e9ef82448 | |||
| a5c77fd096 | |||
| 56ed79792e | |||
| 9c91727402 | |||
| d183961280 | |||
| d30c25010c | |||
| 97d1a6e488 | |||
| 6dec340161 | |||
| 780739719f | |||
| 4a717ca7ff | |||
| 5a831e3d21 | |||
| d30286225c | |||
| 65695fb878 | |||
| ab15750747 | |||
| 694a44e638 | |||
| a3950ac191 | |||
| 6f90badda8 | |||
| 8b05510d6c | |||
| b1470223d3 | |||
| f25b072fa0 | |||
| ffb867f254 | |||
| 36e21e882f | |||
| d0eca6fa90 | |||
| 6306ce0f80 | |||
| 53187ddae9 | |||
| 92c50ed3b4 | |||
| fa98aad469 | |||
| 980988f208 | |||
| d4805387ef | |||
| 69a4be68e8 | |||
| 06da416b8f | |||
| 21ae78fbc2 | |||
| 0a8ae14789 | |||
| 2eea7728d2 | |||
| 6b3cc54afc | |||
| 5c11946470 | |||
| 0b7e25a3ef | |||
| d16c283aef | |||
| a0f493b471 | |||
| e389939092 | |||
| 380675e214 | |||
| 3e55c5126c | |||
| 7e3d2f936d | |||
| 0d70812641 | |||
| dd9fa65629 | |||
| eb7324e7fc | |||
| 061bb90d50 | |||
| a8d0ef3437 | |||
| 438c0955f2 | |||
| b9deb9c63d | |||
| e14b3ec8a0 | |||
| c0d2c2ea24 | |||
| 0ce6e94352 | |||
| be55400ec6 | |||
| 6f1737bb58 |
@@ -109,7 +109,7 @@ jobs:
|
||||
# Ensure Bonsai and ifcsverchok enable/disable works before uploading to extensions repo.
|
||||
|
||||
# Download Blender.
|
||||
wget -q -O blender.tar.xz https://download.blender.org/release/Blender5.1/blender-5.1.0-linux-x64.tar.xz
|
||||
wget -q -O blender.tar.xz https://download.blender.org/release/Blender5.2/blender-5.2.0-linux-x64.tar.xz
|
||||
tar -xf blender.tar.xz
|
||||
|
||||
# Setup Blender.
|
||||
@@ -179,8 +179,7 @@ jobs:
|
||||
blender --online-mode --command extension install --enable --sync sun_position
|
||||
|
||||
cd IfcOpenShell/src/bonsai
|
||||
pip install pytest-blender
|
||||
pip install pytest-bdd
|
||||
pip install -r requirements-dev.txt
|
||||
blender --background --python scripts/setup_pytest.py
|
||||
blender --python-expr "import bonsai; print(bonsai.bbim_semver); import ifcopenshell; print(ifcopenshell.version)" --background
|
||||
make test
|
||||
|
||||
@@ -27,10 +27,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
uv tool install ruff
|
||||
uv tool install black
|
||||
uv tool install poethepoet
|
||||
uv tool install ty==0.0.34
|
||||
cat requirements-tools.txt | xargs -L1 uv tool install
|
||||
|
||||
# black doesn't catch all syntax errors, so we check them explicitly.
|
||||
- name: Check syntax errors
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
/_deps-vs*-x*-installed/
|
||||
/_installed-vs*-x*/
|
||||
/build/
|
||||
/build.log
|
||||
/output/
|
||||
/src/examples/build/
|
||||
# ifctester docs output
|
||||
/src/ifctester/test/build/
|
||||
@@ -22,6 +24,7 @@
|
||||
__pycache__
|
||||
*.py.bak
|
||||
venv
|
||||
uv.lock
|
||||
|
||||
# Visual Studio Code files
|
||||
.vscode
|
||||
@@ -127,6 +130,7 @@ src/ifcopenshell-python/ifcopenshell/express/*.exp.cache.dat
|
||||
|
||||
# temp files from AI coding tools
|
||||
*.claude
|
||||
CLAUDE.local.md
|
||||
*.py.tmp*
|
||||
*.json.tmp*
|
||||
|
||||
|
||||
@@ -314,8 +314,12 @@ if(WASM_BUILD)
|
||||
else()
|
||||
# @todo review this, shouldn't this be all possible header-only now?
|
||||
# ... or rewritten using C++17 features?
|
||||
# Boost.System has been header-only since 1.69 and its compiled stub library
|
||||
# was dropped in newer Boost, so requesting it as a component makes
|
||||
# find_package fail on Boost 1.70 and up (for example Boost 1.90). It is
|
||||
# still pulled in transitively by thread / iostreams where needed, so do not
|
||||
# request it explicitly.
|
||||
set(BOOST_COMPONENTS
|
||||
system
|
||||
program_options
|
||||
regex
|
||||
thread
|
||||
@@ -559,8 +563,8 @@ if(COMPILE_SCHEMA)
|
||||
# Bootstrap the parser
|
||||
message(STATUS "Compiling schema, this will take a while...")
|
||||
execute_process(
|
||||
COMMAND ${PYTHON_EXECUTABLE} bootstrap.py express.bnf
|
||||
WORKING_DIRECTORY ../src/ifcexpressparser
|
||||
COMMAND ${PYTHON_EXECUTABLE} bootstrap.py
|
||||
WORKING_DIRECTORY ../src/ifcopenshell-python/ifcopenshell/express
|
||||
OUTPUT_FILE express_parser.py
|
||||
RESULT_VARIABLE SUCCESS
|
||||
)
|
||||
@@ -571,7 +575,7 @@ if(COMPILE_SCHEMA)
|
||||
|
||||
# Generate code
|
||||
execute_process(
|
||||
COMMAND ${PYTHON_EXECUTABLE} ../ifcexpressparser/express_parser.py ../../${COMPILE_SCHEMA}
|
||||
COMMAND ${PYTHON_EXECUTABLE} ../ifcopenshell-python/ifcopenshell/express/express_parser.py ../../${COMPILE_SCHEMA}
|
||||
WORKING_DIRECTORY ../src/ifcparse
|
||||
OUTPUT_VARIABLE COMPILED_SCHEMA_NAME
|
||||
)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
.env
|
||||
*.pyc
|
||||
__pycache__
|
||||
@@ -0,0 +1,3 @@
|
||||
.env
|
||||
*.pyc
|
||||
__pycache__
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
# .ifcos_env
|
||||
# register autocompletes. just source the file in your shell, i.e.
|
||||
# source .ifcos_env
|
||||
|
||||
.ifcos_env() {
|
||||
local cur prev opts
|
||||
COMPREPLY=()
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
|
||||
opts="create update up down restart build attach logs ps config remove help"
|
||||
|
||||
# Basic static completion
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Register the completion for the command "ifcos_env"
|
||||
complete -F .ifcos_env ./ifcos_env
|
||||
@@ -0,0 +1,67 @@
|
||||
FROM rockylinux:9
|
||||
|
||||
# Update system, enable CRB (needed by some EPEL packages) and install EPEL,
|
||||
# then install required packages + some common tools for a bit of command
|
||||
# line comfort. Combined into one layer so a later `create` always installs
|
||||
# against packages from the same dnf update, rather than layering fresh
|
||||
# installs on top of a stale cached "update" layer.
|
||||
RUN dnf update -y && \
|
||||
dnf install -y epel-release && \
|
||||
dnf config-manager --set-enabled crb && \
|
||||
dnf install -y --allowerasing --setopt=install_weak_deps=False --setopt=tsflags=nodocs \
|
||||
bash-completion vim git curl wget which tree htop sudo \
|
||||
gcc gcc-c++ autoconf automake bison make zip cmake \
|
||||
python3 python3-pip \
|
||||
bzip2 patch mesa-libGL-devel libffi-devel fontconfig-devel \
|
||||
sqlite-devel bzip2-devel zlib-devel openssl-devel xz-devel \
|
||||
readline-devel ncurses-devel libuuid-devel git-lfs \
|
||||
findutils xz byacc ccache && \
|
||||
git lfs install --system && \
|
||||
dnf clean all && \
|
||||
rm -rf /var/cache/dnf
|
||||
|
||||
# Trust bind-mounted repos regardless of which user (root or builder) or host
|
||||
# UID owns them, rather than a per-user config that only one of them sees.
|
||||
RUN git config --system --add safe.directory '*'
|
||||
|
||||
# Configure ccache. CCACHE_MAXSIZE (not `ccache -M`) because /ccache is a
|
||||
# volume mount point at runtime - anything `ccache -M` writes to a config
|
||||
# file under it during this build gets shadowed once the real volume is
|
||||
# mounted, so the size cap only actually takes effect via the env var.
|
||||
# 2G is generous: a full build (IfcParse+IfcGeom+IfcConvert+wrapper, one
|
||||
# Python version) measures ~300MB, and the volume is now shared across all
|
||||
# checkouts (see compose.yaml), so this covers several diverging branches.
|
||||
ENV CCACHE_DIR=/ccache
|
||||
ENV CCACHE_MAXSIZE=2G
|
||||
ENV PATH="/usr/lib/ccache:$PATH"
|
||||
|
||||
# Non-root user matching the host UID/GID that bind-mounts the repo (default
|
||||
# 1000:1000, the common single-user-Linux-box case), so files the build
|
||||
# creates under the mount keep sane, non-root ownership on the host side.
|
||||
# Override with --build-arg USER_UID=$(id -u) --build-arg USER_GID=$(id -g)
|
||||
# if your host user has a different UID/GID.
|
||||
ARG USER_UID=1000
|
||||
ARG USER_GID=1000
|
||||
# groupadd fails outright if USER_GID is already taken by an existing
|
||||
# system group - which happens whenever a host's primary GID collides with
|
||||
# one baked into the rockylinux9 base image. The main real-world case is
|
||||
# macOS, where the default user's primary group is "staff" at GID 20, and
|
||||
# GID 20 is "games" on RHEL-family images. Only create the "builder" group
|
||||
# when that GID is actually free; otherwise useradd just attaches to
|
||||
# whichever group already owns it. Either way the builder user ends up
|
||||
# with the right GID for bind-mount ownership, which is all that matters.
|
||||
RUN (getent group "${USER_GID}" >/dev/null || groupadd -g "${USER_GID}" builder) \
|
||||
&& useradd -m -u "${USER_UID}" -g "${USER_GID}" -s /bin/bash builder \
|
||||
&& echo "builder ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/builder
|
||||
|
||||
# Copied while still root: /bin is not writable by the builder user.
|
||||
COPY --from=ghcr.io/astral-sh/uv:0.11.27 /uv /uvx /bin/
|
||||
|
||||
USER builder
|
||||
WORKDIR /__w/IfcOpenShell/IfcOpenShell
|
||||
|
||||
# Installed as builder so managed Python interpreters land under builder's
|
||||
# $HOME, matching the user that actually runs the build.
|
||||
RUN uv python install
|
||||
|
||||
CMD ["sleep", "infinity"]
|
||||
@@ -0,0 +1,78 @@
|
||||
Docker build environment
|
||||
========================
|
||||
|
||||
This is a small utility to make it easy to compile a perfect `_ifcopenshell_wrapper.cpython-*-x86_64-linux-gnu.so`
|
||||
files.
|
||||
|
||||
The reason for this tool is that I was trying to follow the web page directions, and my build was behaving differently
|
||||
to the release builds. Eventually I concluded that the differences between toolchains on the RHEL based rocky9 image
|
||||
and Ubuntu were just too great. Getting the build setup was already a lot of trial and error, so I thought I'd spend
|
||||
more time trying to reuse the github actions that perform the build, using a utility called `act`. I learnt a lot, in
|
||||
particular how much time, energy, and bandwidth Github waste. I also realised I was most of the way to a regular docker
|
||||
setup anyway, so I might as well just do that. So I've deconstructed all the github action steps, and turned it into
|
||||
a local docker build environment that uses the exact same base, tools, libraries, and build command/flags etc.
|
||||
|
||||
Right now a Github action will:
|
||||
- launch the rocky9 base
|
||||
- upgrade all the packages
|
||||
- install a bunch of extra tools
|
||||
- do a recursive checkout of your repo
|
||||
- checkout the build repository
|
||||
- unpack dependencies
|
||||
- run the build script, making all python versions (5? right now I think)
|
||||
- create the .zip release files
|
||||
|
||||
And it does _all_ of that _every_ time. This is not a fault of the action writers - it's just how Github seems to work.
|
||||
|
||||
These dockers tools do the following differently, and it's actually a bit more powerful too:
|
||||
- build the base image once.
|
||||
- update the packages once.
|
||||
- install the extra tools once.
|
||||
- the repository is the one on your host, that gets bind mounted in the container as the working directory.
|
||||
- by adding an environment variable to .env, restricts to compiling for just a single python version.
|
||||
- when the build is finished the created files are right there under your local repositry (but not added to git) for
|
||||
ease of access
|
||||
- each repository can have it's own build environment container.
|
||||
- the image is shared between those environments.
|
||||
- the containers share the ccache, so additional envs should get a helping hand.
|
||||
- it has a simple set of user friendly commands to drive it all.
|
||||
|
||||
For example:
|
||||
``` bash
|
||||
# To see the commands (a superset of docker compose commands)
|
||||
./ifcos_env
|
||||
|
||||
# Enable autocomplete of commands
|
||||
source .ifcos_env
|
||||
|
||||
# First time commands
|
||||
./ifcos_env create
|
||||
./ifcos_env up
|
||||
./ifcos_env build
|
||||
|
||||
# install and test library
|
||||
# find an issue
|
||||
# edit code
|
||||
./ifcos_env build
|
||||
|
||||
# and so on. When done stop and optionally delete the container
|
||||
./ifcos_env stop
|
||||
./ifcos_env remove
|
||||
```
|
||||
|
||||
To limit the build to one python version just add
|
||||
``` bash
|
||||
PY_TGT=py-311
|
||||
```
|
||||
or whichever version your Blender requires.
|
||||
|
||||
You might see UNIQUE_ID in the .env file too. This keeps containers for separate folders, separate.
|
||||
|
||||
System requirements
|
||||
1. Linux-x64 only at this time.
|
||||
2. Docker and docker-compose need to be installed.
|
||||
3. Have a good amount of disk space. (image is in /var (typically the root partition) and will be about 1.7 GB)
|
||||
4. The build action will create about 10GB in your repository folder. Make sure this partition is spacious
|
||||
particularly if you intent on having multiple clones building.
|
||||
5. ... I think that covers most of it.
|
||||
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
---
|
||||
name: ifcopenshell-docker-build
|
||||
description: >-
|
||||
Build a real ifcopenshell_wrapper (.so + .py) and IfcConvert locally via
|
||||
the docker/ifcos_env toolchain, then wire them into a checkout for
|
||||
running C++-dependent parts of the test suite (geometry, the SWIG
|
||||
wrapper stub, the C++ parser). Use whenever a task needs to compile
|
||||
IfcOpenShell's C++ core rather than just read/patch source - e.g.
|
||||
reproducing or fixing a bug in src/ifcgeom, src/ifcparse, src/ifcwrap,
|
||||
or validating util/scripts/validate_stub.py against the actual
|
||||
generated wrapper.
|
||||
---
|
||||
|
||||
# Building IfcOpenShell locally with docker/ifcos_env
|
||||
|
||||
`docker/` mirrors the project's GitHub Actions build environment locally,
|
||||
in a persistent, non-root container with ccache so repeat builds are fast.
|
||||
See `docker/README.md` for the design rationale. Pure-Python changes don't
|
||||
need any of this - only reach for it when you need a real compiled
|
||||
`_ifcopenshell_wrapper*.so` or `IfcConvert` binary.
|
||||
|
||||
## Placement
|
||||
|
||||
This `docker/` folder must live as a direct child of the repo root you want
|
||||
to build (sibling of `src/`, `cmake/`, etc.) - `compose.yaml` and
|
||||
`ifcos_env` resolve the repo via `../` relative to wherever `docker/`
|
||||
itself sits, and bind-mount it into the container. If you're setting this
|
||||
up in a fresh clone, copy the whole `docker/` directory there first.
|
||||
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
cd docker
|
||||
./ifcos_env create # build the image (shared by name across all your clones/checkouts, so usually instant after the first time anywhere)
|
||||
./ifcos_env up # create + start the container, clone/unpack the third-party dependency cache (~10GB, one-time per container)
|
||||
./ifcos_env build # full build: all deps + IfcParse + IfcGeom + IfcConvert + the Python wrapper, for one Python version
|
||||
```
|
||||
|
||||
`PY_TGT` and `UNIQUE_ID` live in `docker/.env` - `PY_TGT` (e.g. `py-311`)
|
||||
restricts the build to one Python version instead of building five;
|
||||
`UNIQUE_ID` is a hash of the folder path, recalculated on every `up`, so
|
||||
each checkout gets its own container/volumes automatically.
|
||||
|
||||
A full first build takes ~1.5 hours (mostly compiling IfcOpenShell's own
|
||||
C++, not the cached third-party deps). After that, ccache makes incremental
|
||||
rebuilds of a couple of touched `.cpp` files **under a minute**.
|
||||
|
||||
## Container lifecycle
|
||||
|
||||
The container is long-lived (`sleep infinity`) so exec'd commands and
|
||||
ccache state persist between builds. Commands map directly onto Docker
|
||||
Compose's own container-vs-image distinction:
|
||||
|
||||
```bash
|
||||
./ifcos_env up # create the container if it doesn't exist, then start it (runs ready_repo too)
|
||||
./ifcos_env stop # stop the container, keep it around
|
||||
./ifcos_env start # start it back up (same container, same filesystem layer)
|
||||
./ifcos_env restart # stop, then start
|
||||
./ifcos_env down # remove the container (and its network) entirely
|
||||
./ifcos_env recreate # down, then up - a fresh container
|
||||
```
|
||||
|
||||
Named volumes (`ccache`) and the bind-mounted repo/`build/` are unaffected
|
||||
by `down`/`recreate` - only the container itself goes away, and `up`
|
||||
recreates it from the image.
|
||||
|
||||
## Fast iteration
|
||||
|
||||
Pass a target to `build` to skip the parts you don't need:
|
||||
|
||||
```bash
|
||||
./ifcos_env build IfcConvert # only the executables (IfcConvert, IfcGeomServer) - skips the Python wrapper entirely
|
||||
./ifcos_env build IfcOpenShell-Python # only the SWIG Python wrapper - skips executables entirely
|
||||
./ifcos_env build # no target = everything (needed the first time, or after touching shared headers)
|
||||
```
|
||||
|
||||
Use this to keep the edit -> rebuild -> test loop fast when debugging: if
|
||||
you're only touching `src/ifcgeom/`, build `IfcConvert`; if you're only
|
||||
exercising the Python API, build `IfcOpenShell-Python`.
|
||||
|
||||
## Where the artifacts land
|
||||
|
||||
Build output goes to `<repo_root>/build/Linux/x86_64/install/` on the host
|
||||
(bind-mounted, not just inside the container), owned by you (see
|
||||
"Container user" below):
|
||||
|
||||
- `ifcopenshell/bin/IfcConvert` - the CLI binary
|
||||
- `python-<version>/lib/python<X.Y>/site-packages/ifcopenshell/_ifcopenshell_wrapper*.so`
|
||||
and `ifcopenshell_wrapper.py` - the compiled wrapper + its generated
|
||||
Python glue
|
||||
|
||||
## Testing against a checkout (automated / AI-driven)
|
||||
|
||||
`_ifcopenshell_wrapper*.so` and `ifcopenshell_wrapper.py` are already
|
||||
gitignored under `src/ifcopenshell-python/ifcopenshell/`, which is exactly
|
||||
where a normal in-tree build would put them - copy the two files there:
|
||||
|
||||
```bash
|
||||
SRC=build/Linux/x86_64/install/python-3.11.8/lib/python3.11/site-packages/ifcopenshell
|
||||
cp "$SRC/_ifcopenshell_wrapper.cpython-311-x86_64-linux-gnu.so" src/ifcopenshell-python/ifcopenshell/
|
||||
cp "$SRC/ifcopenshell_wrapper.py" src/ifcopenshell-python/ifcopenshell/
|
||||
```
|
||||
|
||||
Then, to run the test suite against it:
|
||||
|
||||
```bash
|
||||
export PATH="$PWD/build/Linux/x86_64/install/ifcopenshell/bin:$PATH" # for IfcConvert-dependent tests
|
||||
cd src/ifcopenshell-python/test
|
||||
PYTHONPATH="$PWD/.." python3.11 -m pytest -p no:pytest-blender .
|
||||
```
|
||||
|
||||
(`-p no:pytest-blender` avoids the pytest-blender plugin trying to find a
|
||||
`blender` executable and failing collection entirely, even for non-Blender
|
||||
tests.) You'll need the matching Python version's `pip install`s too
|
||||
(numpy, shapely, isodate, lark, tabulate, pytest, ... - whatever the
|
||||
modules under test import) since this is a bare interpreter, not the
|
||||
project's pixi env.
|
||||
|
||||
**This is the pattern to use for automated or AI-driven verification.**
|
||||
Don't use `try` (below) for that - it overwrites files in a real, live
|
||||
Blender installation, which isn't something an automated/AI workflow
|
||||
should ever do without the human explicitly asking for it in the moment.
|
||||
|
||||
## Testing in Blender itself (human only)
|
||||
|
||||
`try` copies the built wrapper straight into your actual Blender/Bonsai
|
||||
extension install, for manual in-Blender testing:
|
||||
|
||||
```bash
|
||||
./ifcos_env try
|
||||
```
|
||||
|
||||
It reads `BLENDER_USER_RESOURCE` from `.env` - set this to wherever
|
||||
Blender's user resource folder for the Bonsai extension actually lives on
|
||||
your system, which depends on your own Blender setup:
|
||||
|
||||
```bash
|
||||
# in docker/.env
|
||||
BLENDER_USER_RESOURCE=~/.config/blender/bonsai/
|
||||
```
|
||||
|
||||
`try` figures out the built Python version from `build/.../install/`
|
||||
(disambiguating with `PY_TGT` if more than one version was built) and
|
||||
copies the wrapper to
|
||||
`$BLENDER_USER_RESOURCE/extensions/.local/lib/python<X.Y>/site-packages/ifcopenshell/`.
|
||||
|
||||
## Container user
|
||||
|
||||
The image runs as a non-root `builder` user, UID/GID matching your host
|
||||
account (passed as `--build-arg` by `create` from `id -u`/`id -g`, so it
|
||||
adjusts automatically - no manual flag needed even if you're not 1000:1000).
|
||||
Files the build creates under the bind mount come out owned by you, not
|
||||
root. Passwordless `sudo` is available inside the container (e.g. via
|
||||
`attach`) for the rare case you need root for something ad hoc.
|
||||
|
||||
If you're picking up an existing checkout that was previously built with
|
||||
an older, root-based image, you may hit `Permission denied` the first time
|
||||
you run `up`/`build` under the new image - `build/`, `.git/modules/`, the
|
||||
`ccache` volume, `output/`, and `build.log` can all be left root-owned from
|
||||
before. Fix it once via the container's own root (no host `sudo` needed):
|
||||
|
||||
```bash
|
||||
docker exec -u root -w /__w/IfcOpenShell/IfcOpenShell <container-name> \
|
||||
chown -R "$(id -u)":"$(id -g)" .git/modules build output build.log /ccache
|
||||
```
|
||||
|
||||
(`<container-name>` is `ifcopenshell-<UNIQUE_ID>` - see `docker ps -a`.)
|
||||
|
||||
## Other things worth knowing
|
||||
|
||||
- **Linux x64 only.** `compose.yaml` pins `platform: linux/amd64`; on an
|
||||
ARM host (e.g. Apple Silicon) this build isn't available.
|
||||
- **The final "Package .zip archives" step of `build()` has a pre-existing
|
||||
bash syntax error**, unrelated to compilation - the actual build already
|
||||
succeeded by that point (look for `Built IfcOpenShell...` in the output),
|
||||
so this is safe to ignore if you only need the raw artifacts under
|
||||
`build/.../install/`, not packaged release zips.
|
||||
- **`test_mmaped_stream` and similar `USE_MMAP`-dependent tests will fail**
|
||||
against this build - `nix/build-all.py` is invoked with `USE_MMAP=OFF`
|
||||
here. Not a bug in your code if you see it fail.
|
||||
- Only the bind-mounted `<repo>/build` lives on the host filesystem your
|
||||
repo is checked out on. Anything the container writes *outside* that
|
||||
mount lives in the container's own writable layer under Docker's data
|
||||
root (commonly `/var/lib/docker`, i.e. usually your root partition) -
|
||||
keep an eye on `df -h /` if you're running several of these containers
|
||||
at once.
|
||||
@@ -0,0 +1,15 @@
|
||||
name: ifcopenshell-${UNIQUE_ID}
|
||||
services:
|
||||
ifcopenshell:
|
||||
container_name: ifcopenshell-${UNIQUE_ID}
|
||||
image: ifcopenshell-build-env:updated
|
||||
platform: linux/amd64
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ../
|
||||
target: /__w/IfcOpenShell/IfcOpenShell
|
||||
- ccache:/ccache
|
||||
|
||||
volumes:
|
||||
ccache:
|
||||
name: ifcopenshell-ccache-shared
|
||||
Executable
+339
@@ -0,0 +1,339 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ================== CONFIG ==================
|
||||
SCRIPT_NAME=$(basename "$0")
|
||||
ENV_FILE=".env"
|
||||
WORKDIR="/__w/IfcOpenShell/IfcOpenShell"
|
||||
NAMEPREFIX=ifcopenshell
|
||||
|
||||
function set_env() {
|
||||
# Load .env file if it exists
|
||||
if [[ -f "$ENV_FILE" ]]; then
|
||||
set -a
|
||||
source "$ENV_FILE"
|
||||
set +a
|
||||
echo "✅ Loaded environment variables from $ENV_FILE"
|
||||
else
|
||||
echo "⚠️ No $ENV_FILE found, proceeding without it."
|
||||
fi
|
||||
}
|
||||
|
||||
set_env
|
||||
|
||||
# ================ FUNCTIONS =================
|
||||
|
||||
function create() {
|
||||
echo "⭐ Creating image: ifcopenshell-build-env"
|
||||
docker build -f Dockerfile \
|
||||
--build-arg USER_UID="$(id -u)" --build-arg USER_GID="$(id -g)" \
|
||||
-t ifcopenshell-build-env:updated .
|
||||
}
|
||||
|
||||
function update() {
|
||||
# The Dockerfile always builds FROM a clean rockylinux:9 and does
|
||||
# `dnf update -y` as its first step, so re-running create() is enough
|
||||
# to get fresh packages.
|
||||
echo "⚡ Updating image: ifcopenshell-build-env"
|
||||
create
|
||||
}
|
||||
|
||||
function up() {
|
||||
# Creates the container if it doesn't exist yet (and starts it either
|
||||
# way) - this is the one that needs ready_repo, since a freshly created
|
||||
# container has no submodules/dependency cache in place yet.
|
||||
echo "🚀 Creating/starting stack: ifcopenshell-${UNIQUE_ID}"
|
||||
unique # Update UNIQUE_ID first
|
||||
docker compose up -d "$@" # Container must exist before ready_repo can exec into it.
|
||||
ready_repo # Ensure repo is recursive, and the build repo is in place.
|
||||
}
|
||||
|
||||
function down() {
|
||||
# Removes the container (and its network) entirely. Named volumes
|
||||
# (ccache) and the bind-mounted repo/build/ survive; up() will recreate
|
||||
# the container from scratch next time.
|
||||
echo "🔥 Removing stack: ifcopenshell-${UNIQUE_ID}"
|
||||
docker compose down "$@"
|
||||
}
|
||||
|
||||
function stop() {
|
||||
# Stops the existing container without removing it - the container,
|
||||
# its filesystem layer, and its exec history all remain intact.
|
||||
echo "🛑 Stopping stack: ifcopenshell-${UNIQUE_ID}"
|
||||
docker compose stop "$@"
|
||||
}
|
||||
|
||||
function start() {
|
||||
# Starts a previously-stopped container back up. Does nothing (and
|
||||
# won't create anything) if the container doesn't exist - use up() for
|
||||
# that.
|
||||
echo "▶️ Starting stack: ifcopenshell-${UNIQUE_ID}"
|
||||
docker compose start "$@"
|
||||
}
|
||||
|
||||
function restart() {
|
||||
echo "🔄 Restarting stack (stop, then start)..."
|
||||
stop
|
||||
start
|
||||
}
|
||||
|
||||
function recreate() {
|
||||
echo "♻️ Recreating stack (down, then up)..."
|
||||
down
|
||||
up
|
||||
}
|
||||
|
||||
function logs() {
|
||||
echo "📜 Showing logs..."
|
||||
docker compose logs -f "$@"
|
||||
}
|
||||
|
||||
function ps() {
|
||||
docker compose ps
|
||||
}
|
||||
|
||||
function config() {
|
||||
echo "🔍 Validated compose configuration:"
|
||||
docker compose config
|
||||
}
|
||||
|
||||
function remove() {
|
||||
# Lower-level than down(): removes already-stopped containers without
|
||||
# touching the compose network. Mostly useful after a plain stop().
|
||||
echo "🗑️ Removing stopped containers: ifcopenshell-${UNIQUE_ID}"
|
||||
docker compose rm "$@"
|
||||
}
|
||||
|
||||
function unique() {
|
||||
echo "🔧 Making stack name folder specific..."
|
||||
|
||||
REGEX="^UNIQUE_ID="
|
||||
|
||||
if [[ ! -f "$ENV_FILE" ]] || ! grep -qE "$REGEX" "$ENV_FILE"; then
|
||||
echo -e "\nUNIQUE_ID=dummy\n" >> "$ENV_FILE"
|
||||
fi
|
||||
|
||||
export UNIQUE_ID="$(pwd | sha256sum | cut -c -8)"
|
||||
|
||||
# `sed -i` takes incompatible syntax between GNU sed (Linux) and BSD sed
|
||||
# (macOS) - `-si` is GNU-only and errors as "illegal option -- s" under
|
||||
# BSD/macOS sed. Avoid -i altogether and do the in-place edit via a temp
|
||||
# file + mv instead, which behaves identically with either sed.
|
||||
local tmp_file
|
||||
tmp_file="$(mktemp "${ENV_FILE}.XXXXXX")"
|
||||
sed "s/^UNIQUE_ID=.*$/UNIQUE_ID=${UNIQUE_ID}/" "$ENV_FILE" > "$tmp_file"
|
||||
mv "$tmp_file" "$ENV_FILE"
|
||||
|
||||
set_env
|
||||
}
|
||||
|
||||
function ready_repo() {
|
||||
echo "👍 Getting the repo ready to build..."
|
||||
docker exec -i -w "${WORKDIR}" "${NAMEPREFIX}-${UNIQUE_ID}" bash -c '
|
||||
set -euo pipefail # Recommended for robustness
|
||||
|
||||
git submodule update --init --recursive
|
||||
|
||||
if [[ ! -d "build" ]]; then
|
||||
git clone -b rockylinux9-x64 https://github.com/IfcOpenShell/build-outputs.git build
|
||||
else
|
||||
cd build
|
||||
git pull
|
||||
cd ..
|
||||
fi
|
||||
|
||||
if [[ ! -d "build/Linux/x86_64/install/boost-1.86.0/" ]]; then
|
||||
cd build
|
||||
uv run ../nix/cache_dependencies.py unpack
|
||||
cd ..
|
||||
fi
|
||||
'
|
||||
}
|
||||
|
||||
function build() {
|
||||
echo "☕ Execute the build, go make yourself a cuppa... I'll be a while"
|
||||
local BUILD_TARGET="$1"
|
||||
|
||||
docker exec -i -w "${WORKDIR}" -e PY_TGT="${PY_TGT}" -e BUILD_TARGET="${BUILD_TARGET}" "${NAMEPREFIX}-${UNIQUE_ID}" bash -c '
|
||||
set -o pipefail
|
||||
CXXFLAGS="-O3" CFLAGS="-O3 ${DARWIN_C_SOURCE}" ADD_COMMIT_SHA=1 BUILD_CFG=Release uv run ./nix/build-all.py -v ${PY_TGT:+-$PY_TGT} --diskcleanup ${BUILD_TARGET} 2>&1 | tee build.log
|
||||
'
|
||||
echo "🎒 Pack Dependencies"
|
||||
docker exec -i -w "${WORKDIR}" "${NAMEPREFIX}-${UNIQUE_ID}" bash -c '
|
||||
cd build
|
||||
uv run ../nix/cache_dependencies.py pack
|
||||
'
|
||||
|
||||
echo "🎁 Package .zip archives"
|
||||
docker exec -i -w "${WORKDIR}" -e GITHUB_SHA="$(git rev-parse HEAD)" "${NAMEPREFIX}-${UNIQUE_ID}" bash -c '
|
||||
OUTPUT_DIR=${PWD}/output
|
||||
VERSION=v`cat VERSION`
|
||||
mkdir -p ${OUTPUT_DIR}
|
||||
cd ./build/`uname`/*/install/ifcopenshell
|
||||
|
||||
ls -d python-* | while read py_version; do
|
||||
postfix=`echo ${py_version: -1} | sed s/[0-9]//`
|
||||
numbers=`echo $py_version | grep -oE "[0-9]+\.[0-9]+" | tr -d "."`
|
||||
py_version_major=python-${numbers}$postfix
|
||||
pushd . > /dev/null
|
||||
cd $py_version
|
||||
if [ ! -d ifcopenshell ]; then
|
||||
mkdir ../ifcopenshell_
|
||||
mv * ../ifcopenshell_
|
||||
mv ../ifcopenshell_ ifcopenshell
|
||||
fi
|
||||
[ -d ifcopenshell/__pycache__ ] && rm -rf ifcopenshell/__pycache__
|
||||
find ifcopenshell -name "*.pyc" -delete
|
||||
zip -r -qq ifcopenshell-${py_version_major}-${VERSION}-${GITHUB_SHA:0:7}-linux64.zip ifcopenshell/*
|
||||
mv *.zip ${OUTPUT_DIR}/
|
||||
popd > /dev/null
|
||||
done
|
||||
|
||||
cd bin
|
||||
if compgen -G "./*.zip" > /dev/null; then
|
||||
rm *.zip 2>&1 >/dev/null || true
|
||||
ls | while read exe; do
|
||||
zip -qq -r ${exe}-${VERSION}-${GITHUB_SHA:0:7}-linux64.zip $exe
|
||||
done
|
||||
mv *.zip ${OUTPUT_DIR}/
|
||||
cd ..
|
||||
'
|
||||
}
|
||||
|
||||
function attach() {
|
||||
echo "🔦 Connect to interactive shell"
|
||||
docker exec -it -w "${WORKDIR}" "${NAMEPREFIX}-${UNIQUE_ID}" /bin/bash
|
||||
}
|
||||
|
||||
function try() {
|
||||
# Copies the freshly built wrapper into your actual Blender/Bonsai
|
||||
# installation for manual, in-Blender testing. This is a human-only
|
||||
# convenience: it overwrites files in your live Blender setup, so it's
|
||||
# not something that should run unattended as part of an automated or
|
||||
# AI-driven build/test loop (which should instead copy the wrapper into
|
||||
# the repo's own src/ifcopenshell-python/ifcopenshell/ - see SKILL.md).
|
||||
echo "🚴 Copying build artifacts into your Blender resource folder for testing"
|
||||
|
||||
if [[ -z "${BLENDER_USER_RESOURCE:-}" ]]; then
|
||||
echo "❌ BLENDER_USER_RESOURCE is not set in .env."
|
||||
echo " Add a line pointing at wherever Blender's user resource folder for"
|
||||
echo " the Bonsai extension actually is on your system, e.g.:"
|
||||
echo " BLENDER_USER_RESOURCE=~/.config/blender/bonsai/"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Normalise: expand a leading ~ (in case it was quoted in .env and so
|
||||
# never went through shell tilde-expansion when set_env sourced it),
|
||||
# then resolve to an absolute, symlink-free path.
|
||||
local resource="${BLENDER_USER_RESOURCE/#\~/$HOME}"
|
||||
resource="$(realpath -m "$resource")"
|
||||
|
||||
local install_dir="../build/Linux/x86_64/install"
|
||||
local py_dirs=("$install_dir"/python-*)
|
||||
if [[ ${#py_dirs[@]} -gt 1 && -n "${PY_TGT:-}" ]]; then
|
||||
# PY_TGT is compact (py-311); the install dirs are dotted
|
||||
# (python-3.11.8) - reinsert the dot (assumes a single-digit major
|
||||
# version, true for the Python 3.x line) before matching.
|
||||
local py_tgt_digits="${PY_TGT#py-}"
|
||||
local py_tgt_dotted="${py_tgt_digits:0:1}.${py_tgt_digits:1}"
|
||||
local filtered=() d
|
||||
for d in "${py_dirs[@]}"; do
|
||||
[[ "$(basename "$d")" == "python-${py_tgt_dotted}."* ]] && filtered+=("$d")
|
||||
done
|
||||
[[ ${#filtered[@]} -gt 0 ]] && py_dirs=("${filtered[@]}")
|
||||
fi
|
||||
if [[ ${#py_dirs[@]} -ne 1 || ! -d "${py_dirs[0]}" ]]; then
|
||||
echo "❌ Expected exactly one built python-* dir under $install_dir, found ${#py_dirs[@]}."
|
||||
echo " Run 'build' first, or set PY_TGT in .env to disambiguate a multi-version build."
|
||||
return 1
|
||||
fi
|
||||
|
||||
local py_minor
|
||||
py_minor="$(basename "${py_dirs[0]}" | grep -oE '[0-9]+\.[0-9]+')"
|
||||
local wrapper_dir="${py_dirs[0]}/lib/python${py_minor}/site-packages/ifcopenshell"
|
||||
if [[ ! -f "$wrapper_dir/ifcopenshell_wrapper.py" ]]; then
|
||||
echo "❌ Built wrapper not found at $wrapper_dir - run 'build' first."
|
||||
return 1
|
||||
fi
|
||||
|
||||
local target="$resource/extensions/.local/lib/python${py_minor}/site-packages/ifcopenshell"
|
||||
mkdir -p "$target"
|
||||
cp "$wrapper_dir"/_ifcopenshell_wrapper*.so "$target/"
|
||||
cp "$wrapper_dir"/ifcopenshell_wrapper.py "$target/"
|
||||
echo "✅ Copied wrapper into $target"
|
||||
}
|
||||
|
||||
function clean() {
|
||||
# Host-side only - doesn't touch the container, image, or ccache volume.
|
||||
echo "💎 Clean the build and output folder up"
|
||||
if [[ -d "../build" ]]; then
|
||||
rm -rf ../build
|
||||
fi
|
||||
if [[ -d "../output" ]]; then
|
||||
rm -rf ../output
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
function help() {
|
||||
cat <<EOF
|
||||
Usage: ./$SCRIPT_NAME <command>
|
||||
|
||||
Available commands:
|
||||
create Build the rocky9-based image
|
||||
update Rebuild the image fresh, picking up OS package updates
|
||||
up Create the container if it doesn't exist yet, and start it
|
||||
down Remove the container entirely (docker compose down)
|
||||
stop Stop the container without removing it
|
||||
start Start a previously-stopped container
|
||||
restart stop, then start (same container, no recreation)
|
||||
recreate down, then up (fresh container)
|
||||
build Execute the IfcOpenShell build
|
||||
attach Connect to an interactive shell in the container
|
||||
try Copy the built wrapper into your Blender resource folder
|
||||
(human-only - see BLENDER_USER_RESOURCE below, and SKILL.md
|
||||
for the AI/automated-testing equivalent)
|
||||
clean Remove the build and output folders
|
||||
logs Follow container logs
|
||||
ps Show running containers
|
||||
config Validate and show compose config
|
||||
remove Remove stopped containers (docker compose rm)
|
||||
help Show this help
|
||||
|
||||
Environment variables from .env are automatically loaded, including:
|
||||
PY_TGT Restrict the build to one Python version, e.g. py-311
|
||||
UNIQUE_ID Recalculated automatically on every 'up', don't set by hand
|
||||
BLENDER_USER_RESOURCE Where 'try' copies the wrapper for manual testing, e.g.
|
||||
~/.config/blender/bonsai/
|
||||
EOF
|
||||
}
|
||||
|
||||
# ================= MAIN =================
|
||||
|
||||
case "$1" in
|
||||
create) create ;;
|
||||
update) update ;;
|
||||
up) up "${@:2}" ;;
|
||||
down) down "${@:2}" ;;
|
||||
stop) stop "${@:2}" ;;
|
||||
start) start "${@:2}" ;;
|
||||
restart) restart ;;
|
||||
recreate) recreate ;;
|
||||
build) build "${@:2}" ;;
|
||||
attach) attach ;;
|
||||
try) try ;;
|
||||
clean) clean ;;
|
||||
logs) logs "${@:2}" ;;
|
||||
ps) ps ;;
|
||||
config) config ;;
|
||||
remove) remove ;;
|
||||
help|-h|--help) help ;;
|
||||
"")
|
||||
echo "❌ No command provided."
|
||||
help
|
||||
;;
|
||||
*)
|
||||
echo "❌ Unknown command: $1"
|
||||
echo "Type './$SCRIPT_NAME help' for available commands."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
+15
-5
@@ -50,7 +50,7 @@ Used environment variables:
|
||||
- ``NO_CLEAN`` - do not clean `ifcopenshell` build directories but continue working on current build
|
||||
(installed dependencies are never cleared).
|
||||
By default option is disabled, to enable pass any value from `1`, `on`, `true`.
|
||||
- ``IFCOS_SCHEMAS`` - schemas to be built; defaults to cmake default (IFC2X3; IFC4; IFC4X3_ADD2) - to be supplied as `2x3;4`
|
||||
- ``IFCOS_SCHEMAS`` - schemas to be built; defaults to cmake default (8 schemas), to be supplied as `2x3;4;4x3_add2`
|
||||
- ``USE_OCCT`` - whether to use official Open CASCADE instead of Community Edition
|
||||
(`true` by default, any other value is considered `false`)
|
||||
- ``WASM_PYTHON_PATH`` - path to WASM Python installation,
|
||||
@@ -155,7 +155,7 @@ MPFR_VERSION = "3.1.6" # latest is 4.1.0
|
||||
CGAL_VERSION = "v5.6.3"
|
||||
USD_VERSION = "23.05"
|
||||
TBB_VERSION = "2021.9.0"
|
||||
ROCKSDB_VERSION = "9.11.2"
|
||||
ROCKSDB_VERSION = "10.4.2"
|
||||
ZSTD_VERSION = "1.5.7"
|
||||
# binaries
|
||||
cp = "cp"
|
||||
@@ -627,9 +627,10 @@ def build_dependency(
|
||||
build_tool_args: "list[str]",
|
||||
download_url: str,
|
||||
download_name: str,
|
||||
*,
|
||||
download_tool: Literal["py", "git"] = download_tool_default,
|
||||
revision: "Union[str, None]" = None,
|
||||
patch: "Union[str, list[str], None]" = None,
|
||||
patch: list[str] | None = None,
|
||||
shell=None,
|
||||
pre_compile_subs: "Sequence[tuple[str, str, str]]" = (),
|
||||
additional_files: "Union[dict[str, str], None]" = None,
|
||||
@@ -714,8 +715,6 @@ def build_dependency(
|
||||
urlretrieve(url, os.path.join(extract_dir, path))
|
||||
|
||||
if patch is not None:
|
||||
if isinstance(patch, str):
|
||||
patch = [patch]
|
||||
for p in patch:
|
||||
patch_abs = (SCRIPT_PATH / p).absolute().__str__()
|
||||
if os.path.exists(patch_abs):
|
||||
@@ -724,6 +723,8 @@ def build_dependency(
|
||||
except Exception as e:
|
||||
# Assert that the patch has already been applied
|
||||
run(["patch", "-p1", "--batch", "--reverse", "--dry-run", "-i", patch_abs], cwd=extract_dir)
|
||||
else:
|
||||
raise FileNotFoundError(patch_abs)
|
||||
|
||||
if shell is not None:
|
||||
sp.run(shell, shell=True, check=True, cwd=extract_dir)
|
||||
@@ -1171,6 +1172,14 @@ if "cgal" in targets:
|
||||
os.environ["CC"] = MAC_CROSS_COMPILE_INTEL_CC
|
||||
gmp_args.extend(MAC_CROSS_COMPILE_INTEL_AUTOCONF_HOST_ARGS)
|
||||
|
||||
# Fixes configure failing to find a working compiler under GCC 15's default -std=gnu23.
|
||||
# Issue presumably will be resolved in any next gmp version, but currently the last one is 6.3.0.
|
||||
# Patch is just applying fix from upstream meantion below:
|
||||
# https://gmplib.org/list-archives/gmp-bugs/2025-February/005561.html
|
||||
gmp_patches = ["./patches/gmp/001-fix-std23.patch"]
|
||||
if GMP_VERSION != "6.3.0":
|
||||
raise Exception(f"GMP_VERSION changed to {GMP_VERSION}, check whether {gmp_patches} is still needed.")
|
||||
|
||||
build_dependency(
|
||||
name=f"gmp-{GMP_VERSION}",
|
||||
mode="autoconf",
|
||||
@@ -1178,6 +1187,7 @@ if "cgal" in targets:
|
||||
pre_compile_subs=(
|
||||
[("build/config.h", "HAVE_OBSTACK_VPRINTF 1", "HAVE_OBSTACK_VPRINTF 0")] if "wasm" in flags else []
|
||||
),
|
||||
patch=gmp_patches,
|
||||
# Sometimes ftp.gnu.org is very slow, use ftpmirror.gnu.org as a workaround.
|
||||
download_url="https://ftpmirror.gnu.org/gnu/gmp/",
|
||||
download_name=f"gmp-{GMP_VERSION}.tar.bz2",
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
Fixes configure failing to find a working compiler under GCC 15's default
|
||||
-std=gnu23 (upstream fix: https://gmplib.org/repo/gmp/rev/8e7bb4ae7a18).
|
||||
|
||||
Upstream fix is patching `acinclude.m4`, but since in the release tarball
|
||||
all macros are already expanded to `configure` script, so we're patching
|
||||
all occurrences of that macro.
|
||||
|
||||
--- a/configure
|
||||
+++ b/configure
|
||||
@@ -6568,7 +6568,7 @@
|
||||
|
||||
#if defined (__GNUC__) && ! defined (__cplusplus)
|
||||
typedef unsigned long long t1;typedef t1*t2;
|
||||
-void g(){}
|
||||
+void g(int,t1 const*,t1,t2,t1 const*,int){}
|
||||
void h(){}
|
||||
static __inline__ t1 e(t2 rp,t2 up,int n,t1 v0)
|
||||
{t1 c,x,r;int i;if(v0){c=1;for(i=1;i<n;i++){x=up[i];r=x+1;rp[i]=r;}}return c;}
|
||||
@@ -8187,7 +8187,7 @@
|
||||
|
||||
#if defined (__GNUC__) && ! defined (__cplusplus)
|
||||
typedef unsigned long long t1;typedef t1*t2;
|
||||
-void g(){}
|
||||
+void g(int,t1 const*,t1,t2,t1 const*,int){}
|
||||
void h(){}
|
||||
static __inline__ t1 e(t2 rp,t2 up,int n,t1 v0)
|
||||
{t1 c,x,r;int i;if(v0){c=1;for(i=1;i<n;i++){x=up[i];r=x+1;rp[i]=r;}}return c;}
|
||||
@@ -1,32 +0,0 @@
|
||||
http://git.dev.opencascade.org/gitweb/?p=occt.git;a=commitdiff;h=0ab4e621833f4eae945a3762c9a29ee12e2eec53#patch1
|
||||
diff --git a/src/HLRBRep/HLRBRep_InternalAlgo.cxx b/src/HLRBRep/HLRBRep_InternalAlgo.cxx
|
||||
index ca885ca..c13cb06 100644 (file)
|
||||
--- a/src/HLRBRep/HLRBRep_InternalAlgo.cxx
|
||||
+++ b/src/HLRBRep/HLRBRep_InternalAlgo.cxx
|
||||
@@ -165,7 +165,7 @@ void HLRBRep_InternalAlgo::Update ()
|
||||
SB.Bounds(v1,v2,e1,e2,f1,f2);
|
||||
|
||||
for (Standard_Integer e = e1; e <= e2; e++) {
|
||||
- HLRBRep_EdgeData ed = aEDataArray.ChangeValue(e);
|
||||
+ HLRBRep_EdgeData& ed = aEDataArray.ChangeValue(e);
|
||||
HLRAlgo::DecodeMinMax(ed.MinMax(), TheMin, TheMax);
|
||||
if (FirstTime) {
|
||||
FirstTime = Standard_False;
|
||||
@@ -307,7 +307,7 @@ void HLRBRep_InternalAlgo::InitEdgeStatus ()
|
||||
Standard_Integer nf = myDS->NbFaces();
|
||||
|
||||
for (Standard_Integer e = 1; e <= ne; e++) {
|
||||
- HLRBRep_EdgeData ed = aEDataArray.ChangeValue(e);
|
||||
+ HLRBRep_EdgeData& ed = aEDataArray.ChangeValue(e);
|
||||
if (ed.Selected()) ed.Status().ShowAll();
|
||||
}
|
||||
// for (Standard_Integer f = 1; f <= nf; f++) {
|
||||
@@ -368,7 +368,7 @@ void HLRBRep_InternalAlgo::Select ()
|
||||
Standard_Integer nf = myDS->NbFaces();
|
||||
|
||||
for (Standard_Integer e = 1; e <= ne; e++) {
|
||||
- HLRBRep_EdgeData ed = aEDataArray.ChangeValue(e);
|
||||
+ HLRBRep_EdgeData& ed = aEDataArray.ChangeValue(e);
|
||||
ed.Selected(Standard_True);
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
From a0deb4ce8b43cf3c8b8c0a4225c6be5296446dbd Mon Sep 17 00:00:00 2001
|
||||
From: Adam Eri <adam.eri@blackmirror.media>
|
||||
Date: Tue, 3 Sep 2019 23:30:20 +0200
|
||||
Subject: [PATCH] Resolves compile error on macOS
|
||||
|
||||
Resolves "no member named 'isnan' in namespace 'std'" on macOS
|
||||
---
|
||||
GeneratedSaxParser/src/GeneratedSaxParserUtils.cpp | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/GeneratedSaxParser/src/GeneratedSaxParserUtils.cpp b/GeneratedSaxParser/src/GeneratedSaxParserUtils.cpp
|
||||
index 1f9a3eef..dd6f5c59 100644
|
||||
--- a/GeneratedSaxParser/src/GeneratedSaxParserUtils.cpp
|
||||
+++ b/GeneratedSaxParser/src/GeneratedSaxParserUtils.cpp
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "GeneratedSaxParserUtils.h"
|
||||
#include <math.h>
|
||||
+#include <cmath>
|
||||
#include <memory>
|
||||
#include <string.h>
|
||||
#include <limits>
|
||||
+42
-86
@@ -1,13 +1,8 @@
|
||||
[project]
|
||||
name = "IfcOpenShell"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"black==26.3.1",
|
||||
"ruff==0.15.12",
|
||||
"poethepoet",
|
||||
"ty==0.0.32",
|
||||
"gersemi==0.26.1",
|
||||
]
|
||||
# Don't provide requires-python explicitly
|
||||
# allowing pyprojects to set their own (e.g. bonsai and general ifcopenshell version differ).
|
||||
|
||||
[tool.black]
|
||||
line-length = 120
|
||||
@@ -43,6 +38,7 @@ exclude = [
|
||||
# then they will be inherited by projects' .toml files.
|
||||
# This allows using assuming different Python version for different projects.
|
||||
[tool.ruff]
|
||||
line-length = 120
|
||||
exclude = [
|
||||
# Submodules.
|
||||
"src/ifcopenshell-python/ifcopenshell/express",
|
||||
@@ -83,92 +79,39 @@ ignore = [
|
||||
]
|
||||
|
||||
[tool.ty.rules]
|
||||
all = "ignore"
|
||||
all = "error"
|
||||
|
||||
# Structural rules (no deep type inference needed, easier to adapt).
|
||||
abstract-method-in-final-class = "error"
|
||||
ambiguous-protocol-member = "error"
|
||||
conflicting-declarations = "error"
|
||||
conflicting-metaclass = "error"
|
||||
cyclic-class-definition = "error"
|
||||
cyclic-type-alias-definition = "error"
|
||||
dataclass-field-order = "error"
|
||||
duplicate-base = "error"
|
||||
duplicate-kw-only = "error"
|
||||
empty-body = "error"
|
||||
escape-character-in-forward-annotation = "error"
|
||||
final-on-non-method = "error"
|
||||
final-without-value = "error"
|
||||
ignore-comment-unknown-rule = "error"
|
||||
implicit-concatenated-string-type-annotation = "error"
|
||||
inconsistent-mro = "error"
|
||||
ineffective-final = "error"
|
||||
instance-layout-conflict = "error"
|
||||
invalid-dataclass = "error"
|
||||
invalid-dataclass-override = "error"
|
||||
invalid-enum-member-annotation = "error"
|
||||
invalid-explicit-override = "error"
|
||||
invalid-frozen-dataclass-subclass = "error"
|
||||
invalid-generic-class = "error"
|
||||
invalid-generic-enum = "error"
|
||||
invalid-ignore-comment = "error"
|
||||
invalid-legacy-positional-parameter = "error"
|
||||
invalid-legacy-type-variable = "error"
|
||||
invalid-named-tuple = "error"
|
||||
invalid-newtype = "error"
|
||||
invalid-overload = "error"
|
||||
invalid-paramspec = "error"
|
||||
invalid-protocol = "error"
|
||||
invalid-syntax-in-forward-annotation = "error"
|
||||
invalid-total-ordering = "error"
|
||||
invalid-type-alias-type = "error"
|
||||
invalid-type-checking-constant = "error"
|
||||
invalid-type-guard-definition = "error"
|
||||
invalid-type-variable-bound = "error"
|
||||
invalid-type-variable-constraints = "error"
|
||||
invalid-typed-dict-header = "error"
|
||||
invalid-typed-dict-statement = "error"
|
||||
override-of-final-method = "error"
|
||||
override-of-final-variable = "error"
|
||||
possibly-missing-import = "error"
|
||||
possibly-missing-submodule = "error"
|
||||
# Has false positives due to ty walrus operator bug.
|
||||
# possibly-unresolved-reference = "error"
|
||||
raw-string-type-annotation = "error"
|
||||
redundant-final-classvar = "error"
|
||||
shadowed-type-variable = "error"
|
||||
subclass-of-final-class = "error"
|
||||
super-call-in-named-tuple-method = "error"
|
||||
unavailable-implicit-super-arguments = "error"
|
||||
unbound-type-variable = "error"
|
||||
undefined-reveal = "error"
|
||||
unresolved-global = "error"
|
||||
unresolved-import = "error"
|
||||
unresolved-reference = "error"
|
||||
unused-ignore-comment = "error"
|
||||
unused-type-ignore-comment = "error"
|
||||
useless-overload-body = "error"
|
||||
possibly-unresolved-reference = "ignore"
|
||||
# Maybe later, requires to specify element types for all generics.
|
||||
missing-type-argument = "ignore"
|
||||
# Conflicts with `bpy` props defined using annotations.
|
||||
invalid-type-form = "ignore"
|
||||
|
||||
# Non-structural rules:
|
||||
deprecated = "error"
|
||||
zero-stepsize-in-slice = "error"
|
||||
possibly-missing-implicit-call = "error"
|
||||
unused-awaitable = "error"
|
||||
|
||||
# Function argument rules:
|
||||
# Conflicts with `ifcopenshell.api.geometry.add_representation` type of callables we have, confusing them with a module.
|
||||
# call-non-callable = "error"
|
||||
conflicting-argument-forms = "error"
|
||||
call-non-callable = "ignore"
|
||||
# bpy is missing some context manager implementations.
|
||||
invalid-context-manager = "ignore"
|
||||
# Doesn't go well with `bpy.ops.xxx.yyy`.
|
||||
unresolved-attribute = "ignore"
|
||||
# Too many false positives.
|
||||
# invalid-argument-type = "error"
|
||||
missing-argument = "error"
|
||||
parameter-already-assigned = "error"
|
||||
positional-only-parameter-as-kwarg = "error"
|
||||
too-many-positional-arguments = "error"
|
||||
unknown-argument = "error"
|
||||
# Has a lot of warnings due to current ty walrus operator issues.
|
||||
# index-out-of-bounds = "error"
|
||||
# unresolved-attribute = "error"
|
||||
invalid-argument-type = "ignore"
|
||||
invalid-method-override = "ignore"
|
||||
invalid-assignment = "ignore"
|
||||
invalid-parameter-default = "ignore"
|
||||
missing-override-decorator = "ignore"
|
||||
invalid-yield = "ignore"
|
||||
invalid-return-type = "ignore"
|
||||
non-callable-init-subclass = "ignore"
|
||||
not-iterable = "ignore"
|
||||
possibly-missing-attribute = "ignore"
|
||||
no-matching-overload = "ignore"
|
||||
not-subscriptable = "ignore"
|
||||
unsupported-dynamic-base = "ignore"
|
||||
unsupported-operator = "ignore"
|
||||
type-assertion-failure = "ignore"
|
||||
|
||||
[tool.ty.environment]
|
||||
extra-paths = [
|
||||
@@ -215,6 +158,18 @@ exclude = [
|
||||
|
||||
[tool.poe.tasks]
|
||||
|
||||
dev-setup.sequence = [
|
||||
{cmd = "uv sync"},
|
||||
{cmd = "uv pip install -e ./src/bsdd/"},
|
||||
{cmd = "uv pip install -e ./src/ifcopenshell-python/[advanced,dev]"},
|
||||
{cmd = "uv pip install -e ./src/ifcedit/"},
|
||||
{cmd = "uv pip install -e ./src/ifcpatch/"},
|
||||
{cmd = "uv pip install -e ./src/ifcquery/"},
|
||||
{cmd = "uv pip install -e './src/ifcmcp/[mcp]'"},
|
||||
{cmd = "uv pip install -r src/bonsai/requirements-dev.txt"},
|
||||
]
|
||||
dev-setup.help = "Install repo packages in editable mode"
|
||||
|
||||
ruff = "ruff check"
|
||||
|
||||
black = "black ."
|
||||
@@ -243,6 +198,7 @@ cmake-format = "gersemi . --in-place"
|
||||
# --ignore unresolved-reference: walrus operator false positives in ty.
|
||||
cmd = """
|
||||
ty check
|
||||
nix/
|
||||
src/bcf
|
||||
src/bsdd
|
||||
src/ifc2ca
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
black==26.3.1
|
||||
ruff==0.15.12
|
||||
poethepoet
|
||||
ty==0.0.59
|
||||
gersemi==0.26.1
|
||||
@@ -320,9 +320,11 @@ def loadIfcStore(scene: bpy.types.Scene) -> None:
|
||||
IfcStore.purge()
|
||||
refresh_ui_data()
|
||||
if not tool.Ifc.get():
|
||||
tool.Autosave.cancel_timer()
|
||||
return
|
||||
tool.Ifc.schema()
|
||||
IfcStore.relink_all_objects()
|
||||
tool.Autosave.reset_timer()
|
||||
|
||||
|
||||
@persistent
|
||||
|
||||
@@ -46,7 +46,7 @@ IFC_CONNECTED_TYPE = Union[bpy.types.Material, bpy.types.Object]
|
||||
class OperationData(TypedDict):
|
||||
id: int
|
||||
guid: NotRequired[str]
|
||||
obj: str
|
||||
obj: NotRequired[str]
|
||||
|
||||
|
||||
class EditObjectOperationData(TypedDict):
|
||||
|
||||
@@ -980,8 +980,13 @@ class IfcImporter:
|
||||
if unit.Name == "METRE":
|
||||
if not unit.Prefix:
|
||||
bpy.context.scene.unit_settings.length_unit = "METERS"
|
||||
else:
|
||||
elif f"{unit.Prefix}METERS" in ("KILOMETERS", "CENTIMETERS", "MILLIMETERS", "MICROMETERS"):
|
||||
bpy.context.scene.unit_settings.length_unit = f"{unit.Prefix}METERS"
|
||||
else:
|
||||
# Blender's length_unit enum has no entry for other
|
||||
# SI prefixes (e.g. DECIMETERS), so fall back to
|
||||
# adaptive display instead of failing to open.
|
||||
bpy.context.scene.unit_settings.length_unit = "ADAPTIVE"
|
||||
else:
|
||||
bpy.context.scene.unit_settings.system = "IMPERIAL"
|
||||
name = unit.Name.lower()
|
||||
|
||||
@@ -156,16 +156,13 @@ class BrickschemaReferencesData:
|
||||
for rel in getattr(tool.Ifc.get_entity(bpy.context.active_object), "HasAssociations", []):
|
||||
if rel.is_a("IfcRelAssociatesLibrary"):
|
||||
reference = rel.RelatingLibrary
|
||||
if tool.Ifc.get_schema() == "IFC2X3" and "#" not in reference.ItemReference:
|
||||
continue
|
||||
if tool.Ifc.get_schema() != "IFC2X3" and "#" not in reference.Identification:
|
||||
identification = tool.Document.get_external_reference_id(reference)
|
||||
if not identification or "#" not in identification:
|
||||
continue
|
||||
results.append(
|
||||
{
|
||||
"id": reference.id(),
|
||||
"identification": (
|
||||
reference.ItemReference if tool.Ifc.get_schema() == "IFC2X3" else reference.Identification
|
||||
),
|
||||
"identification": identification,
|
||||
"name": reference.Name or "Unnamed",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -127,36 +127,25 @@ class ObjectDocumentData:
|
||||
identification = None
|
||||
|
||||
if is_information:
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
identification = relating_document.DocumentId
|
||||
else:
|
||||
identification = relating_document.Identification
|
||||
identification = tool.Document.get_document_information_id(relating_document)
|
||||
|
||||
location = getattr(relating_document, "Location", None)
|
||||
description = getattr(relating_document, "Description", "No description")
|
||||
else:
|
||||
description = relating_document.Description
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
reference_to_document = relating_document.ReferenceToDocument
|
||||
if not name and reference_to_document:
|
||||
name = reference_to_document[0].Name
|
||||
referenced_document = tool.Document.get_reference_document(relating_document)
|
||||
|
||||
identification = relating_document.ItemReference
|
||||
if not identification and reference_to_document:
|
||||
identification = reference_to_document[0].DocumentId
|
||||
location = relating_document.Location
|
||||
else:
|
||||
referenced_document = relating_document.ReferencedDocument
|
||||
if not name and referenced_document:
|
||||
name = referenced_document.Name
|
||||
if not name and referenced_document:
|
||||
name = referenced_document.Name
|
||||
|
||||
identification = relating_document.Identification
|
||||
if not identification and referenced_document:
|
||||
identification = referenced_document.Identification
|
||||
identification = tool.Document.get_external_reference_id(relating_document)
|
||||
if not identification and referenced_document:
|
||||
identification = tool.Document.get_document_information_id(referenced_document)
|
||||
|
||||
location = relating_document.Location
|
||||
if location is None and referenced_document:
|
||||
location = referenced_document.Location
|
||||
location = relating_document.Location
|
||||
# IFC2X3 IfcDocumentInformation has no Location to fall back to.
|
||||
if location is None and referenced_document and tool.Ifc.get_schema() != "IFC2X3":
|
||||
location = referenced_document.Location
|
||||
|
||||
location = cls.convert_to_file_uri(location) if location else None
|
||||
|
||||
|
||||
@@ -189,14 +189,20 @@ def format_distance(
|
||||
if hasattr(length_unit, "Prefix") and length_unit.Prefix:
|
||||
unit_length = length_unit.Prefix + length_unit.Name
|
||||
unit_length_mapping = {
|
||||
"MILE": "MILES",
|
||||
"FOOT": "FEET",
|
||||
"INCH": "INCHES",
|
||||
"KILOMETRE": "KILOMETERS",
|
||||
"METRE": "METERS",
|
||||
"DECIMETRE": "DECIMETERS",
|
||||
"CENTIMETRE": "CENTIMETERS",
|
||||
"MILLIMETRE": "MILLIMETERS",
|
||||
"MICROMETRE": "MICROMETERS",
|
||||
}
|
||||
unit_length = unit_length_mapping[unit_length]
|
||||
# Fall through for units without a dedicated formatter (e.g.
|
||||
# HECTOMETRE) so they use the adaptive branch instead of a
|
||||
# KeyError (#8255).
|
||||
unit_length = unit_length_mapping.get(unit_length, unit_length)
|
||||
# For now we only format area in IFC Units
|
||||
if area_unit := ifcopenshell.util.unit.get_project_unit(tool.Ifc.get(), "AREAUNIT"):
|
||||
area_unit_symbol = " " + ifcopenshell.util.unit.get_unit_symbol(area_unit)
|
||||
|
||||
@@ -1706,6 +1706,12 @@ class CreateDrawing(bpy.types.Operator):
|
||||
key=lambda a: (
|
||||
tool.Drawing.get_annotation_z_index(a),
|
||||
1 if ifcopenshell.util.element.get_predefined_type(a) == "TEXT" else 0,
|
||||
# Deterministic tiebreaker so equal-priority annotations keep a
|
||||
# stable order across sessions. Without it the order comes from
|
||||
# the set union above, which depends on entity hashes (and thus
|
||||
# the file pointer), shuffling annotations between Blender
|
||||
# restarts. See #6608.
|
||||
a.id(),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -2343,7 +2349,9 @@ class ActivateDrawingBase(tool.Ifc.Operator):
|
||||
"Activates the selected drawing view.\n\n"
|
||||
+ "ALT+CLICK to keep the viewport position.\n\n"
|
||||
+ "SHIFT+CLICK to load a quick preview of the drawing view.\n\n"
|
||||
+ "SHIFT+CTRL+CLICK to load the annotations of all selected drawings without switching views"
|
||||
+ "SHIFT+CTRL+CLICK to load the annotations of all selected drawings without switching views, "
|
||||
+ "then select their cameras (the first selected drawing's camera becomes active).\n\n"
|
||||
+ "SHIFT+CTRL+ALT+CLICK to do the same but also select the annotations, not just the cameras"
|
||||
)
|
||||
|
||||
drawing: bpy.props.IntProperty()
|
||||
@@ -2365,16 +2373,25 @@ class ActivateDrawingBase(tool.Ifc.Operator):
|
||||
default=False,
|
||||
options={"SKIP_SAVE"},
|
||||
)
|
||||
include_annotations_in_selection: bpy.props.BoolProperty(
|
||||
name="Include Annotations In Selection",
|
||||
description="Also select the loaded annotation objects, not just the drawing cameras.",
|
||||
default=False,
|
||||
options={"SKIP_SAVE"},
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
drawing: int
|
||||
should_view_from_camera: bool
|
||||
use_quick_preview: bool
|
||||
load_selected_annotations: bool
|
||||
include_annotations_in_selection: bool
|
||||
|
||||
def invoke(self, context, event) -> set["rna_enums.OperatorReturnItems"]:
|
||||
if event.type == "LEFTMOUSE" and event.shift and event.ctrl:
|
||||
self.load_selected_annotations = True
|
||||
if event.alt:
|
||||
self.include_annotations_in_selection = True
|
||||
return self.execute(context)
|
||||
if event.type == "LEFTMOUSE" and event.alt:
|
||||
self.should_view_from_camera = False
|
||||
@@ -2389,15 +2406,34 @@ class ActivateDrawingBase(tool.Ifc.Operator):
|
||||
bpy.ops.bim.load_drawings()
|
||||
|
||||
if self.load_selected_annotations:
|
||||
objs_to_select = []
|
||||
active_camera = None
|
||||
for d in props.drawings:
|
||||
if not (d.is_drawing and d.is_selected):
|
||||
continue
|
||||
selected_drawing = tool.Ifc.get().by_id(d.ifc_definition_id)
|
||||
# Importing the camera (if missing) ensures the drawing's
|
||||
# collection exists so the annotations get collected into it.
|
||||
if not tool.Ifc.get_object(selected_drawing):
|
||||
tool.Drawing.import_drawing(selected_drawing)
|
||||
tool.Drawing.import_annotations_in_group(tool.Drawing.get_drawing_group(selected_drawing))
|
||||
if not (camera := tool.Ifc.get_object(selected_drawing)):
|
||||
camera = tool.Drawing.import_drawing(selected_drawing)
|
||||
group = tool.Drawing.get_drawing_group(selected_drawing)
|
||||
tool.Drawing.import_annotations_in_group(group)
|
||||
|
||||
if active_camera is None:
|
||||
active_camera = camera
|
||||
objs_to_select.append(camera)
|
||||
if self.include_annotations_in_selection:
|
||||
for element in tool.Drawing.get_group_elements(group) or []:
|
||||
if element.is_a("IfcAnnotation") and element.ObjectType != "DRAWING":
|
||||
if annotation_obj := tool.Ifc.get_object(element):
|
||||
objs_to_select.append(annotation_obj)
|
||||
|
||||
# Select the checked drawings' objects, with the first drawing's camera as active.
|
||||
bpy.ops.object.select_all(action="DESELECT")
|
||||
for obj in objs_to_select:
|
||||
obj.select_set(True)
|
||||
if active_camera is not None:
|
||||
context.view_layer.objects.active = active_camera
|
||||
return {"FINISHED"}
|
||||
|
||||
drawing = tool.Ifc.get().by_id(self.drawing)
|
||||
@@ -2486,7 +2522,9 @@ class ActivateDrawing(bpy.types.Operator, ActivateDrawingBase):
|
||||
"Activates the selected drawing view.\n\n"
|
||||
+ "ALT+CLICK to keep the viewport position.\n\n"
|
||||
+ "SHIFT+CLICK to load a quick preview of the drawing view.\n\n"
|
||||
+ "SHIFT+CTRL+CLICK to load the annotations of all selected drawings without switching views"
|
||||
+ "SHIFT+CTRL+CLICK to load the annotations of all selected drawings without switching views, "
|
||||
+ "then select their cameras (the first selected drawing's camera becomes active).\n\n"
|
||||
+ "SHIFT+CTRL+ALT+CLICK to do the same but also select the annotations, not just the cameras"
|
||||
)
|
||||
|
||||
|
||||
@@ -3548,7 +3586,7 @@ class EditSheet(bpy.types.Operator, tool.Ifc.Operator):
|
||||
if sheet.is_a("IfcDocumentInformation"):
|
||||
self.document_type = "SHEET"
|
||||
self.name = sheet.Name
|
||||
self.identification = sheet.DocumentId if tool.Ifc.get_schema() == "IFC2X3" else sheet.Identification
|
||||
self.identification = tool.Document.get_document_information_id(sheet)
|
||||
elif sheet.is_a("IfcDocumentReference") and tool.Drawing.get_reference_description(sheet) == "TITLEBLOCK":
|
||||
self.document_type = "TITLEBLOCK"
|
||||
else:
|
||||
|
||||
@@ -903,12 +903,8 @@ class SvgWriter:
|
||||
continue
|
||||
sheet = tool.Drawing.get_reference_document(sheet_reference)
|
||||
if sheet:
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
reference_id = sheet_reference.ItemReference or "-"
|
||||
sheet_id = sheet.DocumentId or "-"
|
||||
else:
|
||||
reference_id = sheet_reference.Identification or "-"
|
||||
sheet_id = sheet.Identification or "-"
|
||||
reference_id = tool.Document.get_external_reference_id(sheet_reference) or "-"
|
||||
sheet_id = tool.Document.get_document_information_id(sheet) or "-"
|
||||
return (reference_id, sheet_id)
|
||||
break
|
||||
return ("-", "-")
|
||||
|
||||
@@ -103,9 +103,7 @@ class LibraryReferencesData:
|
||||
results.append(
|
||||
{
|
||||
"id": library.id(),
|
||||
"identification": (
|
||||
library.ItemReference if tool.Ifc.get_schema() == "IFC2X3" else library.Identification
|
||||
),
|
||||
"identification": tool.Document.get_external_reference_id(library),
|
||||
"name": library.Name or "Unnamed",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -418,6 +418,13 @@ class ImportQuickFavorites(bpy.types.Operator):
|
||||
bl_description = "Import operators from Blender's Quick Favorites menu, including their configured properties"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if bpy.app.version[:2] not in tool.Misc.QuickFavorites.OFFSET_USER_MENUS:
|
||||
cls.poll_message_set(f"Blender version {bpy.app.version_string} is not supported.")
|
||||
return False
|
||||
return True
|
||||
|
||||
def execute(self, context) -> set["rna_enums.OperatorReturnItems"]:
|
||||
props = tool.Misc.get_misc_props()
|
||||
props.quick_favorites.clear()
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, cast
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
@@ -122,8 +122,8 @@ class ExecuteIfcPatch(bpy.types.Operator):
|
||||
if props.should_load_from_memory and tool.Ifc.get():
|
||||
args["file"] = tool.Ifc.get()
|
||||
else:
|
||||
args["input"] = cast(str, props.ifc_patch_input)
|
||||
args["file"] = cast(ifcopenshell.file, ifcopenshell.open(props.ifc_patch_input))
|
||||
args["input"] = props.ifc_patch_input
|
||||
args["file"] = ifcopenshell.open(props.ifc_patch_input)
|
||||
|
||||
# Store this in case the patch recipe resets the Blender session, such as by loading a new project.
|
||||
ifc_patch_output = props.ifc_patch_output or props.ifc_patch_input
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
import bpy
|
||||
|
||||
import bonsai.tool as tool
|
||||
|
||||
from . import decorator, gizmo, operator, prop, ui, workspace
|
||||
|
||||
classes = (
|
||||
@@ -58,6 +60,8 @@ classes = (
|
||||
operator.LinkIfc,
|
||||
operator.LoadBlendMetadataAndIFC,
|
||||
operator.LoadLink,
|
||||
operator.AutosavePrompt,
|
||||
operator.LoadAutosavedRecoveryPopup,
|
||||
operator.LoadLinkedProject,
|
||||
operator.LoadProject,
|
||||
operator.LoadProjectElements,
|
||||
@@ -136,6 +140,7 @@ def register():
|
||||
def unregister():
|
||||
if not bpy.app.background:
|
||||
bpy.utils.unregister_tool(workspace.ExploreTool)
|
||||
tool.Autosave.cancel_timer()
|
||||
del bpy.types.Scene.BIMProjectProperties
|
||||
del bpy.types.Scene.MeasureToolSettings
|
||||
bpy.app.handlers.load_post.remove(decorator.toggle_decorations_on_load)
|
||||
|
||||
@@ -985,8 +985,10 @@ class LoadProject(bpy.types.Operator, IFCFileSelector, ImportHelper):
|
||||
),
|
||||
default=False,
|
||||
)
|
||||
skip_autosave_recovery: bpy.props.BoolProperty(default=False, options={"HIDDEN", "SKIP_SAVE"})
|
||||
use_detailed_tooltip: bpy.props.BoolProperty(default=False, options={"HIDDEN"})
|
||||
filename_ext = ".ifc"
|
||||
skip_recent: bpy.props.BoolProperty(default=False, options={"HIDDEN", "SKIP_SAVE"})
|
||||
|
||||
if TYPE_CHECKING:
|
||||
filepath: str
|
||||
@@ -995,6 +997,7 @@ class LoadProject(bpy.types.Operator, IFCFileSelector, ImportHelper):
|
||||
use_relative_path: bool
|
||||
should_start_fresh_session: bool
|
||||
import_without_ifc_data: bool
|
||||
skip_autosave_recovery: bool
|
||||
use_detailed_tooltip: bool
|
||||
|
||||
@classmethod
|
||||
@@ -1041,7 +1044,33 @@ class LoadProject(bpy.types.Operator, IFCFileSelector, ImportHelper):
|
||||
|
||||
return tooltip
|
||||
|
||||
def check_autosave_recovery(self, context: bpy.types.Context) -> bool:
|
||||
if self.skip_autosave_recovery:
|
||||
return False
|
||||
autosaved_filepath = tool.Autosave.get_newer_autosaved_path(self.get_filepath_abs())
|
||||
if not autosaved_filepath:
|
||||
return False
|
||||
# Fire-and-forget: don't propagate this popup's own RUNNING_MODAL
|
||||
# return value up as if *this* operator were running modally too -
|
||||
# we never call modal_handler_add() on ourselves, so the window
|
||||
# manager would be left tracking a modal operator with no handler,
|
||||
# corrupting its operator bookkeeping until it crashes later when
|
||||
# the (real) popup modal handler is closed.
|
||||
bpy.ops.bim.load_autosaved_recovery_popup(
|
||||
"INVOKE_DEFAULT",
|
||||
original_filepath=str(self.get_filepath_abs()),
|
||||
autosaved_filepath=autosaved_filepath,
|
||||
is_advanced=self.is_advanced,
|
||||
use_relative_path=self.use_relative_path,
|
||||
should_start_fresh_session=self.should_start_fresh_session,
|
||||
import_without_ifc_data=self.import_without_ifc_data,
|
||||
)
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
if self.check_autosave_recovery(context):
|
||||
return {"FINISHED"}
|
||||
|
||||
if (
|
||||
tool.Blender.get_addon_preferences().save_metadata_blend_file
|
||||
and self.should_start_fresh_session
|
||||
@@ -1136,7 +1165,8 @@ class LoadProject(bpy.types.Operator, IFCFileSelector, ImportHelper):
|
||||
props.should_save_metadata_for_this_file = metadata_doc is not None
|
||||
|
||||
tool.Blender.register_toolbar()
|
||||
tool.Project.add_recent_ifc_project(self.get_filepath_abs())
|
||||
if not self.skip_recent:
|
||||
tool.Project.add_recent_ifc_project(self.get_filepath_abs())
|
||||
|
||||
if self.is_advanced:
|
||||
pass
|
||||
@@ -1149,10 +1179,13 @@ class LoadProject(bpy.types.Operator, IFCFileSelector, ImportHelper):
|
||||
except:
|
||||
bonsai.last_error = traceback.format_exc()
|
||||
raise
|
||||
tool.Autosave.reset_timer()
|
||||
return {"FINISHED"}
|
||||
|
||||
def invoke(self, context, event):
|
||||
if self.filepath:
|
||||
if self.check_autosave_recovery(context):
|
||||
return {"FINISHED"}
|
||||
return self.execute(context)
|
||||
return ImportHelper.invoke(self, context, event)
|
||||
|
||||
@@ -1947,6 +1980,7 @@ class ExportIFC(bpy.types.Operator, ExportHelper):
|
||||
json_compact: bpy.props.BoolProperty(name="Export Compact IFCJSON", default=False)
|
||||
should_save_as: bpy.props.BoolProperty(name="Should Save As", default=False, options={"HIDDEN"})
|
||||
use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=False)
|
||||
skip_recent: bpy.props.BoolProperty(default=False, options={"HIDDEN", "SKIP_SAVE"})
|
||||
|
||||
if TYPE_CHECKING:
|
||||
filter_glob: str
|
||||
@@ -2007,6 +2041,18 @@ class ExportIFC(bpy.types.Operator, ExportHelper):
|
||||
return {"FINISHED"}
|
||||
|
||||
def _execute(self, context):
|
||||
project_props = tool.Project.get_project_props()
|
||||
project_props.use_relative_project_path = self.use_relative_path
|
||||
|
||||
# Fallback if filepath is not set
|
||||
if not getattr(self, "filepath", None) or self.filepath.strip() in ("", ".ifc"):
|
||||
props = tool.Blender.get_bim_props()
|
||||
if props.ifc_file:
|
||||
self.filepath = str(tool.Blender.ensure_blender_path_is_abs(Path(props.ifc_file)))
|
||||
else:
|
||||
self.report({"ERROR"}, "No filepath available for saving.")
|
||||
return {"CANCELLED"}
|
||||
|
||||
committed, failed_commits = tool.Parametric.commit_pending_edits()
|
||||
# Previews are session-transient — discard rather than commit. Sibling
|
||||
# gizmo polls gate on each preview's is_active flag, and a stuck flag
|
||||
@@ -2069,7 +2115,8 @@ class ExportIFC(bpy.types.Operator, ExportHelper):
|
||||
settings.logger.info("Export finished in {:.2f} seconds".format(time.time() - start))
|
||||
print("Export finished in {:.2f} seconds".format(time.time() - start))
|
||||
# New project created in Bonsai should be in recent projects too.
|
||||
tool.Project.add_recent_ifc_project(Path(output_file))
|
||||
if not self.skip_recent:
|
||||
tool.Project.add_recent_ifc_project(Path(output_file))
|
||||
props = tool.Project.get_project_props()
|
||||
if props.use_relative_project_path and bpy.data.is_saved:
|
||||
output_file = os.path.relpath(output_file, bpy.path.abspath("//"))
|
||||
@@ -2103,6 +2150,7 @@ class ExportIFC(bpy.types.Operator, ExportHelper):
|
||||
)
|
||||
|
||||
bonsai.bim.handler.refresh_ui_data()
|
||||
tool.Autosave.reset_timer()
|
||||
|
||||
@classmethod
|
||||
def description(cls, context, properties):
|
||||
@@ -2111,6 +2159,123 @@ class ExportIFC(bpy.types.Operator, ExportHelper):
|
||||
return "Save the IFC file. Will save both .IFC/.BLEND files if synced together"
|
||||
|
||||
|
||||
class LoadAutosavedRecoveryPopup(bpy.types.Operator):
|
||||
bl_idname = "bim.load_autosaved_recovery_popup"
|
||||
bl_label = "Recover Autosaved File"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
original_filepath: bpy.props.StringProperty(options={"SKIP_SAVE"})
|
||||
autosaved_filepath: bpy.props.StringProperty(options={"SKIP_SAVE"})
|
||||
is_advanced: bpy.props.BoolProperty(default=False, options={"SKIP_SAVE"})
|
||||
use_relative_path: bpy.props.BoolProperty(default=False, options={"SKIP_SAVE"})
|
||||
should_start_fresh_session: bpy.props.BoolProperty(default=True, options={"SKIP_SAVE"})
|
||||
import_without_ifc_data: bpy.props.BoolProperty(default=False, options={"SKIP_SAVE"})
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.label(text="A newer autosaved copy was found:", icon="INFO")
|
||||
layout.label(text=os.path.basename(self.autosaved_filepath))
|
||||
layout.separator()
|
||||
layout.label(text="Do you want to load the autosaved version instead?")
|
||||
layout.label(text="(Cancel will load the original)")
|
||||
|
||||
def invoke(self, context, event):
|
||||
# invoke_props_dialog is modal - unlike invoke_popup/popup_menu, it
|
||||
# isn't dismissed by the mouse simply leaving its bounds. It always
|
||||
# renders both a fixed "Cancel" button and this confirm_text one, so
|
||||
# the question is framed as Yes/Cancel rather than adding separate
|
||||
# Load buttons on top.
|
||||
return context.window_manager.invoke_props_dialog(
|
||||
self, width=420, title="Recover Autosaved File", confirm_text="Yes"
|
||||
)
|
||||
|
||||
def _load_kwargs(self, filepath: str, skip_recent: bool) -> dict:
|
||||
return dict(
|
||||
filepath=filepath,
|
||||
skip_autosave_recovery=True, # Prevent infinite loop
|
||||
is_advanced=self.is_advanced,
|
||||
use_relative_path=self.use_relative_path,
|
||||
should_start_fresh_session=self.should_start_fresh_session,
|
||||
import_without_ifc_data=self.import_without_ifc_data,
|
||||
skip_recent=skip_recent,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _defer(callback) -> None:
|
||||
def on_timer() -> None:
|
||||
callback()
|
||||
return None
|
||||
|
||||
# bim.load_project (with should_start_fresh_session, our default)
|
||||
# calls wm.read_homefile(), which tears down the window
|
||||
# manager/screens/regions. Calling that synchronously from this
|
||||
# dialog's execute()/cancel() - themselves invoked from deep inside
|
||||
# Blender's modal handling for this popup's button click - frees
|
||||
# data that the still-on-stack caller dereferences once we return,
|
||||
# segfaulting Blender. Deferring by one timer tick runs the reload
|
||||
# after the popup's own modal handling has fully unwound. The
|
||||
# callback only closes over plain values (not `self`), since the
|
||||
# operator instance itself may no longer be valid by the time the
|
||||
# timer fires.
|
||||
bpy.app.timers.register(on_timer, first_interval=0.0)
|
||||
|
||||
def execute(self, context):
|
||||
kwargs = self._load_kwargs(self.autosaved_filepath, skip_recent=True)
|
||||
original_filepath = self.original_filepath
|
||||
|
||||
def load_and_repoint() -> None:
|
||||
bpy.ops.bim.load_project(**kwargs)
|
||||
# Re-point tracking at the original path so future saves write
|
||||
# back to it, not "_autosaved.ifc".
|
||||
tool.Ifc.set_path(original_filepath)
|
||||
|
||||
self._defer(load_and_repoint)
|
||||
return {"FINISHED"}
|
||||
|
||||
def cancel(self, context):
|
||||
# Also reached via Escape or a click outside the dialog, not just Cancel.
|
||||
kwargs = self._load_kwargs(self.original_filepath, skip_recent=False)
|
||||
self._defer(lambda: bpy.ops.bim.load_project(**kwargs))
|
||||
|
||||
|
||||
class AutosavePrompt(bpy.types.Operator):
|
||||
bl_idname = "bim.autosave_prompt"
|
||||
bl_label = "Autosave Reminder"
|
||||
bl_options = set()
|
||||
|
||||
def invoke(self, context, event):
|
||||
return context.window_manager.invoke_props_dialog(
|
||||
self, width=400, confirm_text="Save", title="Autosave Reminder"
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.label(text="The autosave timer has expired.", icon="INFO")
|
||||
layout.label(text="Would you like to save your IFC project now?")
|
||||
|
||||
def execute(self, context):
|
||||
# Get current IFC path
|
||||
props = tool.Blender.get_bim_props()
|
||||
current_ifc_path = props.ifc_file
|
||||
|
||||
if not current_ifc_path:
|
||||
self.report({"WARNING"}, "No IFC file path set. Please save manually.")
|
||||
tool.Autosave.reset_timer()
|
||||
return {"CANCELLED"}
|
||||
|
||||
# Call save_project with explicit filepath using EXEC_DEFAULT
|
||||
result = bpy.ops.bim.save_project(
|
||||
"EXEC_DEFAULT", filepath=current_ifc_path, should_save_as=False, skip_recent=True
|
||||
)
|
||||
|
||||
tool.Autosave.reset_timer()
|
||||
return result
|
||||
|
||||
def cancel(self, context):
|
||||
tool.Autosave.reset_timer()
|
||||
return {"CANCELLED"}
|
||||
|
||||
|
||||
class LoadLinkedProject(bpy.types.Operator, ImportHelper):
|
||||
bl_idname = "bim.load_linked_project"
|
||||
bl_label = "Load Project For Viewing Only"
|
||||
|
||||
@@ -71,7 +71,11 @@ class LoadByDirection(TypedDict):
|
||||
|
||||
ProcessedLoad = TypedDict(
|
||||
"ProcessedLoad",
|
||||
{"linear loads": LoadByDirection, "max linear load": float, "discrete loads": list[list[DiscreteConfigItem]]},
|
||||
{
|
||||
"linear loads": dict[str, LoadByDirection] | None,
|
||||
"max linear load": float,
|
||||
"discrete loads": list[list[DiscreteConfigItem]],
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -845,13 +849,16 @@ class ShaderInfo:
|
||||
v = l1[1] + fac * (pos - l1[0])
|
||||
return v
|
||||
|
||||
def interpolate(self, pos: float, loadinfo: list[LoadConfigItem], start: int, end: int, key: str) -> np.ndarray:
|
||||
def interpolate(self, pos: float, loadinfo: list[LoadConfigItem], start: int, end: int) -> np.ndarray:
|
||||
"""interpolate the result vectors between load poits"""
|
||||
result = np.zeros(6)
|
||||
for i in range(6):
|
||||
value1 = [loadinfo[start]["pos"], loadinfo[start][key][i]] # [position, force_component]
|
||||
value2 = [loadinfo[end]["pos"], loadinfo[end][key][i]] # [position, force_component]
|
||||
result[i] = self.interp1d(value1, value2, pos) # interpolated [position, force_component]
|
||||
# [position, force_component]
|
||||
value1 = [loadinfo[start]["pos"], loadinfo[start]["load values"][i]]
|
||||
# [position, force_component]
|
||||
value2 = [loadinfo[end]["pos"], loadinfo[end]["load values"][i]]
|
||||
# interpolated [position, force_component]
|
||||
result[i] = self.interp1d(value1, value2, pos)
|
||||
return result
|
||||
|
||||
def get_before_and_after(self, pos: float, load_config_list: list[list[LoadConfigItem]]) -> dict[str, list[float]]:
|
||||
@@ -895,8 +902,8 @@ class ShaderInfo:
|
||||
load_before += config[end]["load values"]
|
||||
|
||||
elif end - start == 1:
|
||||
load_before += self.interpolate(pos, config, start, end, "load values")
|
||||
load_after += self.interpolate(pos, config, start, end, "load values")
|
||||
load_before += self.interpolate(pos, config, start, end)
|
||||
load_after += self.interpolate(pos, config, start, end)
|
||||
start += 1
|
||||
end -= 1
|
||||
return_value = {"before": load_before.tolist(), "after": load_after.tolist()}
|
||||
|
||||
@@ -577,6 +577,43 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences):
|
||||
should_disable_undo_on_save: BoolProperty(
|
||||
name="Disable Undo When Saving (Faster saves, no undo for you!)", default=False
|
||||
)
|
||||
|
||||
def update_autosave_settings(self, context: bpy.types.Context) -> None:
|
||||
if self.autosave_enabled:
|
||||
tool.Autosave.reset_timer()
|
||||
else:
|
||||
tool.Autosave.cancel_timer()
|
||||
|
||||
autosave_enabled: BoolProperty(
|
||||
name="Enable IFC Autosave Timer",
|
||||
description="Periodically remind you to save or automatically create a backup copy of the IFC file",
|
||||
default=False,
|
||||
update=update_autosave_settings,
|
||||
)
|
||||
autosave_interval_minutes: bpy.props.IntProperty(
|
||||
name="Autosave Interval (Minutes)",
|
||||
description="Time between autosave reminders or backups. The timer resets whenever you open or save a project",
|
||||
default=10,
|
||||
min=1,
|
||||
max=1440,
|
||||
update=update_autosave_settings,
|
||||
)
|
||||
autosave_mode: bpy.props.EnumProperty(
|
||||
name="Autosave Mode",
|
||||
items=[
|
||||
(
|
||||
"PROMPT",
|
||||
"Prompt to Save",
|
||||
"Show a dialog offering to save the IFC project when the timer expires",
|
||||
),
|
||||
(
|
||||
"BACKUP",
|
||||
"Automatic Backup",
|
||||
"Save a backup copy as filename_autosaved.ifc when the timer expires",
|
||||
),
|
||||
],
|
||||
default="PROMPT",
|
||||
)
|
||||
should_stream: BoolProperty(name="Stream Data From IFC-SPF (Only for advanced users)", default=False)
|
||||
should_always_cache: BoolProperty(
|
||||
name="Always Cache Geometry",
|
||||
@@ -689,6 +726,9 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences):
|
||||
bsdd_load_test_dictionaries: bool
|
||||
bsdd_baseurl: str
|
||||
should_disable_undo_on_save: bool
|
||||
autosave_enabled: bool
|
||||
autosave_interval_minutes: int
|
||||
autosave_mode: Literal["PROMPT", "BACKUP"]
|
||||
should_stream: bool
|
||||
should_always_cache: bool
|
||||
occurrence_name_style: Literal["CLASS", "TYPE", "CUSTOM"]
|
||||
@@ -837,6 +877,12 @@ class BIM_ADDON_preferences(bpy.types.AddonPreferences):
|
||||
def draw_other_settings(self, layout: bpy.types.UILayout, context: bpy.types.Context) -> None:
|
||||
layout.prop(self, "opening_focus_opacity")
|
||||
layout.prop(self, "should_disable_undo_on_save")
|
||||
layout.separator()
|
||||
layout.label(text="Autosave:")
|
||||
layout.prop(self, "autosave_enabled")
|
||||
if self.autosave_enabled:
|
||||
layout.prop(self, "autosave_interval_minutes")
|
||||
layout.prop(self, "autosave_mode")
|
||||
layout.prop(self, "should_stream")
|
||||
layout.prop(self, "should_always_cache")
|
||||
layout.label(text="bSDD:")
|
||||
|
||||
@@ -303,17 +303,7 @@ def add_drawing(
|
||||
ifc_representation_class=None,
|
||||
)
|
||||
|
||||
drawings_parent_group = None
|
||||
for group in ifc.get().by_type("IfcGroup"):
|
||||
if group.Name == "DRAWINGS" and group.ObjectType == "DRAWINGS":
|
||||
drawings_parent_group = group
|
||||
break
|
||||
|
||||
if not drawings_parent_group:
|
||||
drawings_parent_group = ifc.run("group.add_group")
|
||||
ifc.run(
|
||||
"group.edit_group", group=drawings_parent_group, attributes={"Name": "DRAWINGS", "ObjectType": "DRAWINGS"}
|
||||
)
|
||||
drawings_parent_group = drawing.ensure_drawings_parent_group()
|
||||
|
||||
group = ifc.run("group.add_group")
|
||||
ifc.run("group.edit_group", group=group, attributes={"Name": drawing_name, "ObjectType": "DRAWING"})
|
||||
@@ -352,19 +342,7 @@ def add_drawing(
|
||||
)
|
||||
drawing.setup_shading_styles_path(shading_styles_path)
|
||||
|
||||
drawings_parent_document = None
|
||||
for document in ifc.get().by_type("IfcDocumentInformation"):
|
||||
if document.Name == "DRAWINGS" and document.Scope == "DRAWINGS":
|
||||
drawings_parent_document = document
|
||||
break
|
||||
|
||||
if not drawings_parent_document:
|
||||
drawings_parent_document = ifc.run("document.add_information")
|
||||
if ifc.get_schema() == "IFC2X3":
|
||||
attributes = {"DocumentId": "DRAWINGS", "Name": "DRAWINGS", "Scope": "DRAWINGS"}
|
||||
else:
|
||||
attributes = {"Identification": "DRAWINGS", "Name": "DRAWINGS", "Scope": "DRAWINGS"}
|
||||
ifc.run("document.edit_information", information=drawings_parent_document, attributes=attributes)
|
||||
drawings_parent_document = drawing.ensure_drawings_parent_document()
|
||||
|
||||
information = ifc.run("document.add_information", parent=drawings_parent_document)
|
||||
uri = drawing.get_default_drawing_path(drawing_name)
|
||||
@@ -395,17 +373,7 @@ def duplicate_drawing(
|
||||
group = drawing_tool.get_drawing_group(new_drawing)
|
||||
ifc.run("group.unassign_group", group=group, products=[new_drawing])
|
||||
|
||||
drawings_parent_group = None
|
||||
for parent_group in ifc.get().by_type("IfcGroup"):
|
||||
if parent_group.Name == "DRAWINGS" and parent_group.ObjectType == "DRAWINGS":
|
||||
drawings_parent_group = parent_group
|
||||
break
|
||||
|
||||
if not drawings_parent_group:
|
||||
drawings_parent_group = ifc.run("group.add_group")
|
||||
ifc.run(
|
||||
"group.edit_group", group=drawings_parent_group, attributes={"Name": "DRAWINGS", "ObjectType": "DRAWINGS"}
|
||||
)
|
||||
drawings_parent_group = drawing_tool.ensure_drawings_parent_group()
|
||||
|
||||
new_group = ifc.run("group.add_group")
|
||||
ifc.run("group.edit_group", group=new_group, attributes={"Name": drawing_name, "ObjectType": "DRAWING"})
|
||||
@@ -426,19 +394,7 @@ def duplicate_drawing(
|
||||
old_reference = drawing_tool.get_drawing_document(new_drawing)
|
||||
ifc.run("document.unassign_document", products=[new_drawing], document=old_reference)
|
||||
|
||||
drawings_parent_document = None
|
||||
for document in ifc.get().by_type("IfcDocumentInformation"):
|
||||
if document.Name == "DRAWINGS" and document.Scope == "DRAWINGS":
|
||||
drawings_parent_document = document
|
||||
break
|
||||
|
||||
if not drawings_parent_document:
|
||||
drawings_parent_document = ifc.run("document.add_information")
|
||||
if ifc.get_schema() == "IFC2X3":
|
||||
attributes = {"DocumentId": "DRAWINGS", "Name": "DRAWINGS", "Scope": "DRAWINGS"}
|
||||
else:
|
||||
attributes = {"Identification": "DRAWINGS", "Name": "DRAWINGS", "Scope": "DRAWINGS"}
|
||||
ifc.run("document.edit_information", information=drawings_parent_document, attributes=attributes)
|
||||
drawings_parent_document = drawing_tool.ensure_drawings_parent_document()
|
||||
|
||||
information = ifc.run("document.add_information", parent=drawings_parent_document)
|
||||
uri = drawing_tool.get_default_drawing_path(drawing_name)
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
# Bonsai - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2026
|
||||
#
|
||||
# This file is part of Bonsai.
|
||||
#
|
||||
# Bonsai is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Bonsai is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# This file was generated with the assistance of an AI coding tool.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
from collections.abc import Iterable
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import bonsai.core.geometry
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import bpy
|
||||
|
||||
import bonsai.tool as tool
|
||||
|
||||
|
||||
Z_ROTATION_ALIGNMENT_TOLERANCE = 1e-9
|
||||
|
||||
|
||||
def _z_rotation_diff(target_z: float, source_z: float) -> float:
|
||||
"""Signed Z-Euler difference wrapped to [-π, π]."""
|
||||
return (target_z - source_z + math.pi) % (2 * math.pi) - math.pi
|
||||
|
||||
|
||||
def copy_z_rotation_to_selected(
|
||||
ifc: type[tool.Ifc],
|
||||
geometry: type[tool.Geometry],
|
||||
surveyor: type[tool.Surveyor],
|
||||
*,
|
||||
active: bpy.types.Object,
|
||||
targets: Iterable[bpy.types.Object],
|
||||
flip: bool = False,
|
||||
) -> int:
|
||||
"""Apply ``active``'s Z-Euler rotation to each target."""
|
||||
source_z = surveyor.get_z_rotation(active) # ty: ignore[missing-argument]
|
||||
if flip:
|
||||
source_z += math.pi
|
||||
rotated = 0
|
||||
for obj in targets:
|
||||
target_z = surveyor.get_z_rotation(obj) # ty: ignore[missing-argument]
|
||||
if abs(_z_rotation_diff(target_z, source_z)) < Z_ROTATION_ALIGNMENT_TOLERANCE:
|
||||
continue
|
||||
surveyor.set_z_rotation(obj, source_z) # ty: ignore[missing-argument]
|
||||
rotated += 1
|
||||
if ifc.get_entity(obj) is not None:
|
||||
bonsai.core.geometry.edit_object_placement(ifc, geometry, surveyor, obj=obj)
|
||||
return rotated
|
||||
@@ -254,7 +254,6 @@ class Cost:
|
||||
def get_cost_schedule(cls, cost_schedule): pass
|
||||
def get_cost_value_attributes(cls): pass
|
||||
def get_cost_value_unit_component(cls): pass
|
||||
def get_direct_cost_item_products(cls): pass
|
||||
def get_highlighted_cost_item(cls): pass
|
||||
def get_products(cls, related_object_type): pass
|
||||
def get_schedule_cost_items(cls, cost_schedule): pass
|
||||
@@ -355,6 +354,8 @@ class Drawing:
|
||||
def enable_editing_schedules(cls): pass
|
||||
def enable_editing_sheets(cls): pass
|
||||
def enable_editing_text(cls, obj): pass
|
||||
def ensure_drawings_parent_document(cls): pass
|
||||
def ensure_drawings_parent_group(cls): pass
|
||||
def ensure_unique_drawing_name(cls, name): pass
|
||||
def ensure_unique_identification(cls, identification): pass
|
||||
def export_font_size(cls, obj): pass
|
||||
@@ -1170,8 +1171,6 @@ class Style:
|
||||
@interface
|
||||
class Surveyor:
|
||||
def get_absolute_matrix(cls, obj): pass
|
||||
def get_z_rotation(cls, obj): pass
|
||||
def set_z_rotation(cls, obj, z): pass
|
||||
|
||||
|
||||
@interface
|
||||
|
||||
@@ -80,3 +80,6 @@ from bonsai.tool.type import Type
|
||||
from bonsai.tool.unit import Unit
|
||||
from bonsai.tool.wall import Wall
|
||||
from bonsai.tool.web import Web
|
||||
|
||||
# Have to move after import of tool.drawing
|
||||
from bonsai.tool.autosave import Autosave # isort: skip
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
# Bonsai - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2026
|
||||
#
|
||||
# This file is part of Bonsai.
|
||||
#
|
||||
# Bonsai is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Bonsai is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# This file was generated with the assistance of an AI coding tool.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import atexit
|
||||
import logging
|
||||
import os
|
||||
from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
from typing import Union
|
||||
|
||||
import bpy
|
||||
|
||||
import bonsai.tool as tool
|
||||
from bonsai.bim import export_ifc
|
||||
from bonsai.bim.module.model import preview_base
|
||||
|
||||
AUTOSAVING_SUFFIX = "_autosaving.ifc"
|
||||
AUTOSAVED_SUFFIX = "_autosaved.ifc"
|
||||
|
||||
_timer_callback: Union[Callable[[], None], None] = None
|
||||
# See cleanup_stale_autosave() for why this is a cached plain string rather
|
||||
# than looked up live.
|
||||
_active_ifc_path_cache: Union[str, None] = None
|
||||
|
||||
|
||||
class Autosave:
|
||||
@classmethod
|
||||
def get_paths(cls, ifc_path: Union[str, Path]) -> tuple[Path, Path, Path]:
|
||||
path = Path(ifc_path)
|
||||
stem = path.stem if path.suffix.lower() == ".ifc" else path.name
|
||||
parent = path.parent
|
||||
main_path = path if path.suffix.lower() == ".ifc" else parent / f"{stem}.ifc"
|
||||
autosaving_path = parent / f"{stem}{AUTOSAVING_SUFFIX}"
|
||||
autosaved_path = parent / f"{stem}{AUTOSAVED_SUFFIX}"
|
||||
return main_path, autosaving_path, autosaved_path
|
||||
|
||||
@classmethod
|
||||
def get_active_ifc_path(cls) -> Union[Path, None]:
|
||||
props = tool.Blender.get_bim_props()
|
||||
if not props.ifc_file:
|
||||
return None
|
||||
path = tool.Blender.ensure_blender_path_is_abs(Path(props.ifc_file))
|
||||
if path.suffix.lower() != ".ifc":
|
||||
return None
|
||||
return path
|
||||
|
||||
@classmethod
|
||||
def _update_active_ifc_path_cache(cls) -> None:
|
||||
global _active_ifc_path_cache
|
||||
ifc_path = cls.get_active_ifc_path()
|
||||
_active_ifc_path_cache = ifc_path.as_posix() if ifc_path is not None else None
|
||||
|
||||
@classmethod
|
||||
def is_enabled(cls) -> bool:
|
||||
return bool(tool.Blender.get_addon_preferences().autosave_enabled)
|
||||
|
||||
@classmethod
|
||||
def get_interval_seconds(cls) -> float:
|
||||
minutes = tool.Blender.get_addon_preferences().autosave_interval_minutes
|
||||
return max(1.0, float(minutes) * 60.0)
|
||||
|
||||
@classmethod
|
||||
def is_eligible(cls) -> bool:
|
||||
return cls.is_enabled() and tool.Ifc.get() is not None and cls.get_active_ifc_path() is not None
|
||||
|
||||
@classmethod
|
||||
def cancel_timer(cls) -> None:
|
||||
global _timer_callback
|
||||
if _timer_callback is not None and bpy.app.timers.is_registered(_timer_callback):
|
||||
bpy.app.timers.unregister(_timer_callback)
|
||||
_timer_callback = None
|
||||
|
||||
@classmethod
|
||||
def reset_timer(cls) -> None:
|
||||
cls.cancel_timer()
|
||||
cls._update_active_ifc_path_cache()
|
||||
if not cls.is_eligible():
|
||||
return
|
||||
|
||||
def on_timer() -> Union[float, None]:
|
||||
cls._on_timer_expired()
|
||||
# Reschedule by returning the next interval rather than calling
|
||||
# reset_timer(), which would unregister this timer from within
|
||||
# its own callback. Blender frees the timer's internal registry
|
||||
# entry on that manual unregister, then frees it again when the
|
||||
# callback returns - a double free that corrupts the heap and
|
||||
# crashes Blender shortly after (e.g. when the prompt dialog
|
||||
# spawned below is next interacted with).
|
||||
return cls.get_interval_seconds() if cls.is_eligible() else None
|
||||
|
||||
global _timer_callback
|
||||
_timer_callback = on_timer
|
||||
bpy.app.timers.register(on_timer, first_interval=cls.get_interval_seconds())
|
||||
|
||||
@classmethod
|
||||
def _on_timer_expired(cls) -> None:
|
||||
if not cls.is_eligible():
|
||||
return
|
||||
|
||||
prefs = tool.Blender.get_addon_preferences()
|
||||
bim_props = tool.Blender.get_bim_props()
|
||||
|
||||
if bim_props.is_dirty:
|
||||
if prefs.autosave_mode == "PROMPT":
|
||||
bpy.ops.bim.autosave_prompt("INVOKE_DEFAULT")
|
||||
elif prefs.autosave_mode == "BACKUP":
|
||||
try:
|
||||
cls.perform_backup(bpy.context)
|
||||
except Exception as error:
|
||||
print(f"Bonsai: autosave backup failed: {error}")
|
||||
|
||||
@classmethod
|
||||
def perform_backup(cls, context: bpy.types.Context) -> None:
|
||||
ifc_path = cls.get_active_ifc_path()
|
||||
if ifc_path is None:
|
||||
return
|
||||
|
||||
_, autosaving_path, autosaved_path = cls.get_paths(ifc_path)
|
||||
autosaving_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
tool.Parametric.commit_pending_edits()
|
||||
preview_base.discard_pending_previews(context.scene)
|
||||
|
||||
logger = logging.getLogger("ExportIFC")
|
||||
output_file = autosaving_path.as_posix().replace("\\", "/")
|
||||
settings = export_ifc.IfcExportSettings.factory(context, output_file, logger)
|
||||
export_ifc.IfcExporter(settings).export()
|
||||
|
||||
try:
|
||||
os.replace(autosaving_path, autosaved_path)
|
||||
except OSError:
|
||||
if autosaving_path.is_file():
|
||||
autosaving_path.unlink(missing_ok=True)
|
||||
raise
|
||||
|
||||
@classmethod
|
||||
def get_newer_autosaved_path(cls, ifc_path: Union[str, Path]) -> Union[str, None]:
|
||||
path = Path(ifc_path)
|
||||
if path.suffix.lower() != ".ifc" or not path.is_file():
|
||||
return None
|
||||
|
||||
_, _, autosaved_path = cls.get_paths(path)
|
||||
if not autosaved_path.is_file():
|
||||
return None
|
||||
if autosaved_path.stat().st_mtime > path.stat().st_mtime:
|
||||
return autosaved_path.as_posix().replace("\\", "/")
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def cleanup_stale_autosave(cls) -> None:
|
||||
"""Remove the active IFC's autosave file(s) on a graceful shutdown.
|
||||
|
||||
Registered via `atexit`, which only runs on a normal interpreter
|
||||
shutdown - never on an actual crash. So a deliberate quit (whether
|
||||
the user saved or chose "don't save") clears the recovery file and
|
||||
won't prompt on next startup, while a genuine crash leaves it in
|
||||
place for recovery, since no atexit callbacks fire then.
|
||||
|
||||
Deliberately reads only `_active_ifc_path_cache` - a plain string
|
||||
kept up to date by `reset_timer()` - rather than touching `bpy` here.
|
||||
By the time `atexit` fires, Blender's own C++ side is torn down far
|
||||
enough that even reading `bpy.context.scene` aborts the process
|
||||
(std::bad_optional_access) instead of raising a catchable exception.
|
||||
"""
|
||||
if _active_ifc_path_cache is None:
|
||||
return
|
||||
try:
|
||||
_, autosaving_path, autosaved_path = cls.get_paths(_active_ifc_path_cache)
|
||||
autosaving_path.unlink(missing_ok=True)
|
||||
autosaved_path.unlink(missing_ok=True)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
atexit.register(Autosave.cleanup_stale_autosave)
|
||||
@@ -192,10 +192,9 @@ class Brick(bonsai.core.tool.Brick):
|
||||
def get_brick(cls, element: ifcopenshell.entity_instance) -> Union[str, None]:
|
||||
for rel in element.HasAssociations:
|
||||
if rel.is_a("IfcRelAssociatesLibrary"):
|
||||
if tool.Ifc.get_schema() == "IFC2X3" and "#" in rel.RelatingLibrary.ItemReference:
|
||||
return rel.RelatingLibrary.ItemReference
|
||||
if tool.Ifc.get_schema() != "IFC2X3" and "#" in rel.RelatingLibrary.Identification:
|
||||
return rel.RelatingLibrary.Identification
|
||||
identification = tool.Document.get_external_reference_id(rel.RelatingLibrary)
|
||||
if identification and "#" in identification:
|
||||
return identification
|
||||
|
||||
@classmethod
|
||||
def get_brick_class(cls, element: ifcopenshell.entity_instance) -> Union[str, None]:
|
||||
|
||||
@@ -261,7 +261,8 @@ class Document(bonsai.core.tool.Document):
|
||||
def get_reference_document(cls, reference: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance | None:
|
||||
# TODO: migrate to util.document and replace all instances
|
||||
if reference.file.schema == "IFC2X3":
|
||||
return (reference.ReferenceToDocument or (None))[0]
|
||||
reference_to_document = reference.ReferenceToDocument
|
||||
return reference_to_document[0] if reference_to_document else None
|
||||
return reference.ReferencedDocument
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -38,6 +38,7 @@ import ifcopenshell.api.context
|
||||
import ifcopenshell.api.document
|
||||
import ifcopenshell.api.drawing
|
||||
import ifcopenshell.api.geometry
|
||||
import ifcopenshell.api.group
|
||||
import ifcopenshell.api.pset
|
||||
import ifcopenshell.api.root
|
||||
import ifcopenshell.geom
|
||||
@@ -773,6 +774,32 @@ class Drawing(bonsai.core.tool.Drawing):
|
||||
def get_drawing_target_view(cls, drawing: ifcopenshell.entity_instance) -> str:
|
||||
return ifcopenshell.util.element.get_psets(drawing).get("EPset_Drawing", {}).get("TargetView", "MODEL_VIEW")
|
||||
|
||||
@classmethod
|
||||
def ensure_drawings_parent_document(cls) -> ifcopenshell.entity_instance:
|
||||
ifc_file = tool.Ifc.get()
|
||||
for document in ifc_file.by_type("IfcDocumentInformation"):
|
||||
if document.Name == "DRAWINGS" and document.Scope == "DRAWINGS":
|
||||
return document
|
||||
document = ifcopenshell.api.document.add_information(ifc_file)
|
||||
if ifc_file.schema == "IFC2X3":
|
||||
attributes = {"DocumentId": "DRAWINGS", "Name": "DRAWINGS", "Scope": "DRAWINGS"}
|
||||
else:
|
||||
attributes = {"Identification": "DRAWINGS", "Name": "DRAWINGS", "Scope": "DRAWINGS"}
|
||||
ifcopenshell.api.document.edit_information(ifc_file, information=document, attributes=attributes)
|
||||
return document
|
||||
|
||||
@classmethod
|
||||
def ensure_drawings_parent_group(cls) -> ifcopenshell.entity_instance:
|
||||
ifc_file = tool.Ifc.get()
|
||||
for group in ifc_file.by_type("IfcGroup"):
|
||||
if group.Name == "DRAWINGS" and group.ObjectType == "DRAWINGS":
|
||||
return group
|
||||
group = ifcopenshell.api.group.add_group(ifc_file)
|
||||
ifcopenshell.api.group.edit_group(
|
||||
ifc_file, group=group, attributes={"Name": "DRAWINGS", "ObjectType": "DRAWINGS"}
|
||||
)
|
||||
return group
|
||||
|
||||
@classmethod
|
||||
def get_group_elements(cls, group: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]:
|
||||
for rel in group.IsGroupedBy or []:
|
||||
@@ -1140,10 +1167,7 @@ class Drawing(bonsai.core.tool.Drawing):
|
||||
new = documents_collection.add()
|
||||
new.ifc_definition_id = schedule.id()
|
||||
new.name = schedule.Name or "Unnamed"
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
new.identification = schedule.DocumentId
|
||||
else:
|
||||
new.identification = schedule.Identification
|
||||
new.identification = tool.Document.get_document_information_id(schedule) or ""
|
||||
|
||||
@classmethod
|
||||
def get_sheet_identification(cls, sheet: ifcopenshell.entity_instance) -> str:
|
||||
@@ -1184,10 +1208,7 @@ class Drawing(bonsai.core.tool.Drawing):
|
||||
new.ifc_definition_id = reference.id()
|
||||
new.is_sheet = False
|
||||
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
new.identification = reference.ItemReference or ""
|
||||
else:
|
||||
new.identification = reference.Identification or ""
|
||||
new.identification = tool.Document.get_external_reference_id(reference) or ""
|
||||
|
||||
new.name = os.path.basename(reference.Location)
|
||||
new.reference_type = reference_description
|
||||
@@ -1582,7 +1603,20 @@ class Drawing(bonsai.core.tool.Drawing):
|
||||
|
||||
@classmethod
|
||||
def is_auto_annotation(cls, element: ifcopenshell.entity_instance):
|
||||
return element.is_a("IfcAnnotation") and element.ObjectType in ("GRID", "SECTION", "ELEVATION", "SECTION_LEVEL")
|
||||
if not element.is_a("IfcAnnotation"):
|
||||
return False
|
||||
if element.ObjectType in ("GRID", "SECTION", "ELEVATION"):
|
||||
# These types only ever exist as system-generated drawing references.
|
||||
return True
|
||||
if element.ObjectType == "SECTION_LEVEL":
|
||||
# SECTION_LEVEL is also a regular, manually creatable annotation type
|
||||
# ("Level (Section)" in the Annotation tool), unlike GRID/SECTION/ELEVATION.
|
||||
# Only treat it as a system-managed reference annotation if it is actually
|
||||
# tied to a referenced product, otherwise a manually authored Level (Section)
|
||||
# annotation would be wrongly swept up as an "orphaned" auto reference and
|
||||
# deleted by sync_references(), or blocked from being deleted directly.
|
||||
return cls.get_assigned_product(element) is not None
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def get_drawing_reference_annotation(
|
||||
@@ -2423,9 +2457,8 @@ class Drawing(bonsai.core.tool.Drawing):
|
||||
def get_reference_document(
|
||||
cls, reference: ifcopenshell.entity_instance
|
||||
) -> Union[ifcopenshell.entity_instance, None]:
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
return reference.ReferenceToDocument[0]
|
||||
return reference.ReferencedDocument
|
||||
# TODO: migrate to document.get_reference_document.
|
||||
return tool.Document.get_reference_document(reference)
|
||||
|
||||
@classmethod
|
||||
def select_assigned_product(cls, context: bpy.types.Context) -> None:
|
||||
|
||||
@@ -33,7 +33,6 @@ from typing import (
|
||||
Optional,
|
||||
TypeGuard,
|
||||
Union,
|
||||
cast,
|
||||
get_args,
|
||||
)
|
||||
|
||||
@@ -2187,7 +2186,7 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
setattr(item, attribute.name, attribute.get_value())
|
||||
|
||||
if item.is_a("IfcSweptAreaSolid"):
|
||||
item_profile = cast(str, props.item_profile)
|
||||
item_profile = props.item_profile
|
||||
profile = item.SweptArea
|
||||
profile_name: Union[str, None] = profile.ProfileName
|
||||
if item_profile == "-":
|
||||
|
||||
@@ -29,6 +29,7 @@ from typing import TYPE_CHECKING, Any, Union
|
||||
|
||||
import bpy
|
||||
|
||||
import bonsai.core.tool
|
||||
import bonsai.tool as tool
|
||||
from bonsai.bim import import_ifc
|
||||
from bonsai.bim.ifc import IfcStore
|
||||
@@ -50,7 +51,7 @@ if TYPE_CHECKING:
|
||||
from bonsai.bim.module.ifcgit.prop import IfcGitProperties
|
||||
|
||||
|
||||
class IfcGit:
|
||||
class IfcGit(bonsai.core.tool.IfcGit):
|
||||
STEP_IDS = dict[str, set[int]]
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -197,7 +197,6 @@ class Loader(bonsai.core.tool.Loader):
|
||||
cls, blender_material: bpy.types.Material, surface_style: ifcopenshell.entity_instance
|
||||
) -> None:
|
||||
surface_style = cls.surface_style_to_dict(surface_style)
|
||||
surface_style: dict[str, Any]
|
||||
|
||||
cls.create_surface_style_shading(blender_material, surface_style)
|
||||
|
||||
|
||||
@@ -112,10 +112,14 @@ class Misc(bonsai.core.tool.Misc):
|
||||
reading data and never writing, to avoid the possibility of corrupting user preferences.
|
||||
"""
|
||||
|
||||
# Byte offset of UserDef.user_menus within the UserDef C struct, per (major, minor)
|
||||
# Blender version. Shifts whenever UserDef's fields change, so must be re-derived
|
||||
# per version (e.g. from that Blender build's SDNA).
|
||||
OFFSET_USER_MENUS: dict[tuple[int, int], int] = {
|
||||
(4, 5): 10032,
|
||||
(5, 0): 10032,
|
||||
(5, 1): 10032,
|
||||
(5, 2): 10800,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -232,7 +232,7 @@ class Raycast(bonsai.core.tool.Raycast):
|
||||
return final_2d, v2
|
||||
|
||||
@classmethod
|
||||
def intersect_mouse_2d_bounding_box(cls, mouse_pos: tuple[int, int], bbox: list[float, float, float, float]):
|
||||
def intersect_mouse_2d_bounding_box(cls, mouse_pos: tuple[int, int], bbox: list[float]):
|
||||
x, y = mouse_pos
|
||||
xmin, xmax, ymin, ymax = bbox
|
||||
|
||||
|
||||
+2
-2
@@ -38,8 +38,8 @@ Hope your day's going well. :)
|
||||
<script>
|
||||
// Define the mapping of versions to URLs
|
||||
const versionURLs = {
|
||||
stable: 'http://docs.bonsaibim.org/',
|
||||
unstable: 'http://docs-unstable.bonsaibim.org/',
|
||||
stable: 'https://docs.bonsaibim.org/',
|
||||
unstable: 'https://docs-unstable.bonsaibim.org/',
|
||||
// Add more versions here as needed
|
||||
};
|
||||
|
||||
|
||||
@@ -44,8 +44,6 @@ When a new Blender version is released and supported:
|
||||
|
||||
* - File
|
||||
- What to update
|
||||
* - ``.github/workflows/ci-bonsai.yml``
|
||||
- ``pyver`` matrix
|
||||
* - ``.github/workflows/ci-bonsai-daily.yml``
|
||||
- Blender download URL
|
||||
|
||||
@@ -61,6 +59,10 @@ When Blender ships with a new Python version:
|
||||
- What to update
|
||||
* - ``.github/workflows/ci-lint.yaml``
|
||||
- ``MIN_BLENDER_PY_VERSION``
|
||||
* - ``.github/workflows/ci-bonsai.yml``
|
||||
- ``pyver`` matrix
|
||||
* - ``.github/workflows/ci-bonsai-daily.yml``
|
||||
- ``pyver`` matrix
|
||||
* - ``.github/scripts/publish-bonsai-releases.py``
|
||||
- ``CURRENT_PYTHON_VERSION``
|
||||
* - ``src/bonsai/Makefile``
|
||||
|
||||
@@ -77,18 +77,3 @@ the image below. Three simple open source online viewers you can test with are
|
||||
<https://3dviewer.net/>`__.
|
||||
|
||||
.. image:: images/ifc-pipeline.png
|
||||
|
||||
Placing occurrences of an element type
|
||||
--------------------------------------
|
||||
|
||||
TODO
|
||||
|
||||
Changing the locations of elements
|
||||
----------------------------------
|
||||
|
||||
TODO
|
||||
|
||||
Modeling a simple building
|
||||
--------------------------
|
||||
|
||||
TODO
|
||||
|
||||
@@ -18,12 +18,6 @@ dependencies = [
|
||||
"ifcopenshell",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"pytest-blender",
|
||||
"pytest-bdd",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
Homepage = "http://bonsaibim.org"
|
||||
Documentation = "https://docs.bonsaibim.org"
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
pytest
|
||||
pytest-blender
|
||||
pytest-bdd
|
||||
Regular → Executable
+3
-1
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Setup Bonsai Development Environment.
|
||||
|
||||
Script links existing Bonsai installation to the provided IfcOpenShell repository.
|
||||
@@ -78,7 +79,8 @@ BONSAI_PATH = find_bonsai_path()
|
||||
# ---------------------------
|
||||
|
||||
# Never changed by user.
|
||||
PYTHON_VERSION = "3.13" if BLENDER_VERSION == "5.1" else "3.11"
|
||||
BLENDER_VERSION_INT = tuple(map(int, BLENDER_VERSION.split(".")))
|
||||
PYTHON_VERSION = "3.13" if BLENDER_VERSION_INT >= (5, 1) else "3.11"
|
||||
PACKAGE_PATH = BLENDER_PATH / rf"extensions/.local/lib/python{PYTHON_VERSION}/site-packages"
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ Scenario: Ensure added booleans are marked as manual
|
||||
And I click "OK"
|
||||
And the object "IfcFurniture/Unnamed" exists
|
||||
And I toggle edit mode
|
||||
And the object "Item/IfcExtrudedAreaSolid/77" exists
|
||||
And the object "Item/IfcExtrudedAreaSolid/73" exists
|
||||
And I open the "Add Item" menu
|
||||
When I click "Half Space Solid"
|
||||
And the object "Item/IfcHalfSpaceSolid/90" exists
|
||||
@@ -33,7 +33,7 @@ Scenario: Ensure removed booleans are unmarked as manual
|
||||
And I click "OK"
|
||||
And the object "IfcFurniture/Unnamed" exists
|
||||
And I toggle edit mode
|
||||
And the object "Item/IfcExtrudedAreaSolid/77" exists
|
||||
And the object "Item/IfcExtrudedAreaSolid/73" exists
|
||||
And I open the "Add Item" menu
|
||||
And I click "Half Space Solid"
|
||||
And I deselect all objects
|
||||
|
||||
@@ -24,7 +24,7 @@ Scenario: Add element - an element with no geometry
|
||||
When I click "OK"
|
||||
And I select the object "IfcFurniture/Unnamed"
|
||||
And I toggle edit mode
|
||||
Then the object "Item/IfcExtrudedAreaSolid/77" exists
|
||||
Then the object "Item/IfcExtrudedAreaSolid/73" exists
|
||||
|
||||
Scenario: Add element - an element with extrusion geometry
|
||||
Given an empty IFC project
|
||||
@@ -36,7 +36,7 @@ Scenario: Add element - an element with extrusion geometry
|
||||
When I click "OK"
|
||||
And I select the object "IfcFurniture/Unnamed"
|
||||
And I toggle edit mode
|
||||
Then the object "Item/IfcExtrudedAreaSolid/77" exists
|
||||
Then the object "Item/IfcExtrudedAreaSolid/73" exists
|
||||
|
||||
Scenario: Add element - an element with custom tessellation geometry
|
||||
Given an empty IFC project
|
||||
@@ -48,7 +48,7 @@ Scenario: Add element - an element with custom tessellation geometry
|
||||
When I click "OK"
|
||||
And I select the object "IfcFurniture/Unnamed"
|
||||
And I toggle edit mode
|
||||
Then the object "Item/IfcPolygonalFaceSet/76" exists
|
||||
Then the object "Item/IfcPolygonalFaceSet/72" exists
|
||||
|
||||
Scenario: Add element - an element with tessellation geometry from an object
|
||||
Given an empty IFC project
|
||||
@@ -62,8 +62,8 @@ Scenario: Add element - an element with tessellation geometry from an object
|
||||
When I click "OK"
|
||||
And I select the object "IfcFurniture/Unnamed"
|
||||
And I toggle edit mode
|
||||
Then the object "Item/IfcPolygonalFaceSet/76" exists
|
||||
And the object "Item/IfcPolygonalFaceSet/76" dimensions are "2,2,2"
|
||||
Then the object "Item/IfcPolygonalFaceSet/72" exists
|
||||
And the object "Item/IfcPolygonalFaceSet/72" dimensions are "2,2,2"
|
||||
|
||||
Scenario: Reassign class
|
||||
Given an empty IFC project
|
||||
|
||||
@@ -12,7 +12,7 @@ Scenario: Add element - a structural point connection
|
||||
And I make the collection "IfcStructuralItem" visible
|
||||
And I select the object "IfcStructuralPointConnection/Foo"
|
||||
And I toggle edit mode
|
||||
Then the object "Item/IfcVertexPoint/69" exists
|
||||
Then the object "Item/IfcVertexPoint/65" exists
|
||||
|
||||
Scenario: Add element - a structural curve member
|
||||
Given an empty IFC project
|
||||
@@ -25,7 +25,7 @@ Scenario: Add element - a structural curve member
|
||||
And I make the collection "IfcStructuralItem" visible
|
||||
And I select the object "IfcStructuralCurveMember/Foo"
|
||||
And I toggle edit mode
|
||||
Then the object "Item/IfcEdge/72" exists
|
||||
Then the object "Item/IfcEdge/68" exists
|
||||
|
||||
Scenario: Add element - a structural surface member
|
||||
Given an empty IFC project
|
||||
@@ -38,7 +38,7 @@ Scenario: Add element - a structural surface member
|
||||
And I make the collection "IfcStructuralItem" visible
|
||||
And I select the object "IfcStructuralSurfaceMember/Foo"
|
||||
And I toggle edit mode
|
||||
Then the object "Item/IfcFace/74" exists
|
||||
Then the object "Item/IfcFace/70" exists
|
||||
|
||||
Scenario: Load structural analysis models
|
||||
Given an empty IFC project
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
# Bonsai - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2026
|
||||
#
|
||||
# This file is part of Bonsai.
|
||||
#
|
||||
# Bonsai is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Bonsai is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# This file was generated with the assistance of an AI coding tool.
|
||||
|
||||
import os
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from bonsai.tool.autosave import AUTOSAVED_SUFFIX, AUTOSAVING_SUFFIX, Autosave
|
||||
|
||||
pytestmark = pytest.mark.project
|
||||
|
||||
|
||||
class TestAutosavePaths:
|
||||
def test_get_paths_for_ifc_file(self):
|
||||
main_path, autosaving_path, autosaved_path = Autosave.get_paths("/tmp/myfile.ifc")
|
||||
assert main_path == Path("/tmp/myfile.ifc")
|
||||
assert autosaving_path == Path(f"/tmp/myfile{AUTOSAVING_SUFFIX}")
|
||||
assert autosaved_path == Path(f"/tmp/myfile{AUTOSAVED_SUFFIX}")
|
||||
|
||||
def test_get_newer_autosaved_path_when_missing(self, tmp_path):
|
||||
ifc_path = tmp_path / "myfile.ifc"
|
||||
ifc_path.write_text("ifc")
|
||||
assert Autosave.get_newer_autosaved_path(ifc_path) is None
|
||||
|
||||
def test_get_newer_autosaved_path_when_older(self, tmp_path):
|
||||
ifc_path = tmp_path / "myfile.ifc"
|
||||
autosaved_path = tmp_path / f"myfile{AUTOSAVED_SUFFIX}"
|
||||
ifc_path.write_text("ifc")
|
||||
autosaved_path.write_text("autosaved")
|
||||
past = time.time() - 10
|
||||
os.utime(ifc_path, (past, past))
|
||||
os.utime(autosaved_path, (time.time(), time.time()))
|
||||
assert Autosave.get_newer_autosaved_path(ifc_path) == autosaved_path.as_posix()
|
||||
|
||||
def test_get_newer_autosaved_path_when_not_newer(self, tmp_path):
|
||||
ifc_path = tmp_path / "myfile.ifc"
|
||||
autosaved_path = tmp_path / f"myfile{AUTOSAVED_SUFFIX}"
|
||||
ifc_path.write_text("ifc")
|
||||
autosaved_path.write_text("autosaved")
|
||||
now = time.time()
|
||||
os.utime(ifc_path, (now, now))
|
||||
past = now - 10
|
||||
os.utime(autosaved_path, (past, past))
|
||||
assert Autosave.get_newer_autosaved_path(ifc_path) is None
|
||||
|
||||
def test_get_newer_autosaved_path_ignores_non_ifc(self, tmp_path):
|
||||
path = tmp_path / "myfile.ifczip"
|
||||
path.write_text("zip")
|
||||
assert Autosave.get_newer_autosaved_path(path) is None
|
||||
@@ -30,7 +30,7 @@ from collections.abc import Generator
|
||||
from inspect import signature
|
||||
from math import radians
|
||||
from pathlib import Path
|
||||
from typing import Any, Union
|
||||
from typing import Any, Union, cast
|
||||
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
@@ -140,7 +140,7 @@ class PanelSpy:
|
||||
else:
|
||||
props = kwargs.get("data")
|
||||
name = kwargs.get("property")
|
||||
props: bpy.types.bpy_struct
|
||||
props = cast(bpy.types.bpy_struct, props)
|
||||
text = kwargs.get("text", props.bl_rna.properties[name].name)
|
||||
icon = kwargs.get("icon", None)
|
||||
prop_type = props.bl_rna.properties[name].type
|
||||
|
||||
@@ -347,11 +347,13 @@ class TestAddDrawing:
|
||||
context="context",
|
||||
ifc_representation_class=None,
|
||||
).should_be_called().will_return("element")
|
||||
drawing.ensure_drawings_parent_group().should_be_called().will_return("drawings_parent_group")
|
||||
ifc.run("group.add_group").should_be_called().will_return("group")
|
||||
ifc.run(
|
||||
"group.edit_group", group="group", attributes={"Name": "name", "ObjectType": "DRAWING"}
|
||||
).should_be_called()
|
||||
ifc.run("group.assign_group", group="group", products=["element"]).should_be_called()
|
||||
ifc.run("group.assign_group", group="drawings_parent_group", products=["group"]).should_be_called()
|
||||
collector.assign("obj").should_be_called()
|
||||
ifc.run("pset.add_pset", product="element", name="EPset_Drawing").should_be_called().will_return("pset")
|
||||
drawing.get_default_drawing_resource_path("Stylesheet").should_be_called().will_return("stylesheet.css")
|
||||
@@ -381,8 +383,11 @@ class TestAddDrawing:
|
||||
"CurrentShadingStyle": "Blender Default",
|
||||
},
|
||||
).should_be_called()
|
||||
drawing.ensure_drawings_parent_document().should_be_called().will_return("drawings_parent_document")
|
||||
drawing.get_default_drawing_path("name").should_be_called().will_return("uri")
|
||||
ifc.run("document.add_information").should_be_called().will_return("information")
|
||||
ifc.run("document.add_information", parent="drawings_parent_document").should_be_called().will_return(
|
||||
"information"
|
||||
)
|
||||
ifc.run("document.add_reference", information="information").should_be_called().will_return("reference")
|
||||
ifc.get_schema().should_be_called().will_return("IFC4")
|
||||
ifc.run(
|
||||
@@ -406,11 +411,13 @@ class TestDuplicateDrawing:
|
||||
drawing.set_name("new_drawing", "unique_name").should_be_called()
|
||||
drawing.get_drawing_group("new_drawing").should_be_called().will_return("group")
|
||||
ifc.run("group.unassign_group", group="group", products=["new_drawing"]).should_be_called()
|
||||
drawing.ensure_drawings_parent_group().should_be_called().will_return("drawings_parent_group")
|
||||
ifc.run("group.add_group").should_be_called().will_return("new_group")
|
||||
ifc.run(
|
||||
"group.edit_group", group="new_group", attributes={"Name": "unique_name", "ObjectType": "DRAWING"}
|
||||
).should_be_called()
|
||||
ifc.run("group.assign_group", group="new_group", products=["new_drawing"]).should_be_called()
|
||||
ifc.run("group.assign_group", group="drawings_parent_group", products=["new_group"]).should_be_called()
|
||||
drawing.get_group_elements("group").should_be_called().will_return(["drawing", "annotation"])
|
||||
ifc.get_object("annotation").should_be_called().will_return("annotation_obj")
|
||||
geometry.duplicate_ifc_objects(["annotation_obj"]).should_be_called().will_return(
|
||||
@@ -425,7 +432,10 @@ class TestDuplicateDrawing:
|
||||
drawing.get_drawing_document("new_drawing").should_be_called().will_return("old_reference")
|
||||
ifc.run("document.unassign_document", products=["new_drawing"], document="old_reference").should_be_called()
|
||||
|
||||
ifc.run("document.add_information").should_be_called().will_return("information")
|
||||
drawing.ensure_drawings_parent_document().should_be_called().will_return("drawings_parent_document")
|
||||
ifc.run("document.add_information", parent="drawings_parent_document").should_be_called().will_return(
|
||||
"information"
|
||||
)
|
||||
ifc.run("document.add_reference", information="information").should_be_called().will_return("reference")
|
||||
ifc.get_schema().should_be_called().will_return("IFC4")
|
||||
drawing.get_default_drawing_path("unique_name").should_be_called().will_return("drawing_path")
|
||||
|
||||
@@ -203,6 +203,7 @@ class TestGetDebugInfo(NewFile):
|
||||
"bonsai_version",
|
||||
"bonsai_commit_hash",
|
||||
"bonsai_commit_date",
|
||||
"bonsai_git_branch",
|
||||
"last_actions",
|
||||
"last_error",
|
||||
}
|
||||
|
||||
+22
-1
@@ -21,6 +21,7 @@ import http.server
|
||||
import time
|
||||
import urllib.parse
|
||||
import uuid
|
||||
import warnings
|
||||
import webbrowser
|
||||
from typing import TYPE_CHECKING, Any, Literal, Optional, TypedDict
|
||||
|
||||
@@ -521,7 +522,17 @@ class Client:
|
||||
headers = {"User-Agent": "IfcOpenShell.bSDD.py/0.8.0"}
|
||||
if is_auth_required:
|
||||
headers["Authorization"] = "Bearer " + self.get_access_token()
|
||||
return requests.get(f"{self.baseurl}{endpoint}", timeout=10, headers=headers, params=params or None).json()
|
||||
response = requests.get(f"{self.baseurl}{endpoint}", timeout=10, headers=headers, params=params or None)
|
||||
try:
|
||||
response.raise_for_status()
|
||||
except requests.exceptions.HTTPError as e:
|
||||
try:
|
||||
data = response.json()
|
||||
message = data.get("message", data.get("error", str(e)))
|
||||
except requests.exceptions.JSONDecodeError:
|
||||
message = response.text or str(e)
|
||||
raise requests.exceptions.HTTPError(f"{e}: {message}", response=response) from e
|
||||
return response.json()
|
||||
|
||||
def _get_deprecated(self, endpoint, params=None, is_auth_required=False):
|
||||
headers = {"User-Agent": "IfcOpenShell.bSDD.py/0.8.0"}
|
||||
@@ -769,6 +780,16 @@ class Client:
|
||||
Get Class details
|
||||
this API replaces Classification
|
||||
"""
|
||||
# Not very well documented on bsdd side,
|
||||
# the deprecation note only occurs when you run into rate limit.
|
||||
# See https://github.com/buildingSMART/bSDD/issues/149
|
||||
if include_class_properties:
|
||||
warnings.warn(
|
||||
"include_class_properties=True is deprecated and heavily rate-limited by the bSDD API. "
|
||||
"Use get_class_properties() instead.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
endpoint = f"Class/v{version}"
|
||||
params = {
|
||||
"Uri": class_uri,
|
||||
|
||||
@@ -31,6 +31,7 @@ def test_get_nbs_classes():
|
||||
|
||||
def test_get_class():
|
||||
uri_light_fixture = next(l for l in get_ifc_classes()["classes"] if "IfcLightFixture" == l["code"])["uri"]
|
||||
# TODO: fix deprecation warning.
|
||||
ifc4x3_light_fixture = client.get_class(uri_light_fixture)
|
||||
assert "Maintenance Factor" and "Light Fixture Mounting Type" in [
|
||||
l["name"] for l in ifc4x3_light_fixture["classProperties"]
|
||||
@@ -39,7 +40,7 @@ def test_get_class():
|
||||
|
||||
def test_get_class_relations():
|
||||
uri_light_fixture = next(l for l in get_ifc_classes()["classes"] if "IfcLightFixture" == l["code"])["uri"]
|
||||
ifc4x3_light_fixture_relations = client.get_class_properties(uri_light_fixture, True)
|
||||
ifc4x3_light_fixture_relations = client.get_class_relations(uri_light_fixture, True)
|
||||
assert "Electrical unit for light-line system" and "Tubelight system" in [
|
||||
r["className"] for r in ifc4x3_light_fixture_relations["classRelations"]
|
||||
]
|
||||
|
||||
@@ -28,6 +28,7 @@ class P62Ifc:
|
||||
self.file = None
|
||||
self.work_plan = None
|
||||
self.project = {}
|
||||
self.default_calendar_id = None
|
||||
self.calendars = {}
|
||||
self.wbs = {}
|
||||
self.root_activites = []
|
||||
@@ -89,6 +90,7 @@ class P62Ifc:
|
||||
self.ns = {"pr": root.tag[1:].partition("}")[0]}
|
||||
project = root.find("pr:Project", self.ns)
|
||||
self.project["Name"] = project.findtext("pr:Name") or "Unnamed"
|
||||
self.default_calendar_id = project.findtext("pr:ActivityDefaultCalendarObjectId", namespaces=self.ns)
|
||||
self.parse_calendar_xml(root)
|
||||
self.parse_calendar_xml(project)
|
||||
self.parse_wbs_xml(project)
|
||||
@@ -174,6 +176,9 @@ class P62Ifc:
|
||||
self.wbs[wbs_id]["activities"].append(activity_id)
|
||||
else:
|
||||
self.root_activites.append(activity_id)
|
||||
# CalendarObjectId is optional in the P6 schema: an activity without one
|
||||
# inherits the project's ActivityDefaultCalendarObjectId.
|
||||
calendar_id = activity.findtext("pr:CalendarObjectId", namespaces=self.ns)
|
||||
self.activities[activity_id] = {
|
||||
"Name": activity.find("pr:Name", self.ns).text,
|
||||
"Identification": activity.find("pr:Id", self.ns).text,
|
||||
@@ -181,7 +186,7 @@ class P62Ifc:
|
||||
"FinishDate": datetime.datetime.fromisoformat(activity.find("pr:FinishDate", self.ns).text),
|
||||
"PlannedDuration": activity.find("pr:PlannedDuration", self.ns).text,
|
||||
"Status": activity.find("pr:Status", self.ns).text,
|
||||
"CalendarObjectId": activity.find("pr:CalendarObjectId", self.ns).text,
|
||||
"CalendarObjectId": calendar_id or self.default_calendar_id,
|
||||
"ifc": None,
|
||||
}
|
||||
|
||||
|
||||
@@ -82,6 +82,11 @@ MAIN_CSV_HEADER_COLUMNS.extend(
|
||||
)
|
||||
|
||||
|
||||
class CostRate(TypedDict):
|
||||
Schedule: str | None
|
||||
RateID: str | None
|
||||
|
||||
|
||||
class CostItem(TypedDict):
|
||||
children: list[CostItem]
|
||||
ifc: NotRequired[ifcopenshell.entity_instance]
|
||||
@@ -97,6 +102,7 @@ class CostItem(TypedDict):
|
||||
Property: Union[str, None]
|
||||
Query: Union[str, None]
|
||||
|
||||
CostRate: CostRate | None
|
||||
Formula: Union[str, None]
|
||||
# QuantityClass: Union[str, None]
|
||||
|
||||
@@ -239,7 +245,7 @@ class Csv2Ifc:
|
||||
cost_values = float(cost_values) if cost_values else None
|
||||
|
||||
if self.has_rates:
|
||||
cost_rate = {
|
||||
cost_rate: CostRate = {
|
||||
"Schedule": row[(self.headers["RateSchedule"])] if "RateSchedule" in self.headers else None,
|
||||
"RateID": row[(self.headers["RateID"])] if "RateID" in self.headers else None,
|
||||
}
|
||||
|
||||
@@ -26,7 +26,8 @@ import logging
|
||||
import os
|
||||
import time
|
||||
from collections import Counter
|
||||
from typing import Optional, TypedDict, Union
|
||||
from typing import Optional, Union
|
||||
from typing_extensions import TypedDict
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.cost
|
||||
@@ -35,7 +36,7 @@ import ifcopenshell.util.element
|
||||
import ifcopenshell.util.unit
|
||||
|
||||
|
||||
class CostItem(TypedDict):
|
||||
class CostItem(TypedDict, extra_items=float):
|
||||
# Exported columns.
|
||||
Index: int
|
||||
Hierarchy: str
|
||||
|
||||
@@ -17,6 +17,7 @@ classifiers = [
|
||||
]
|
||||
dependencies = [
|
||||
"ifcopenshell",
|
||||
"typing_extensions",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
||||
@@ -53,6 +53,8 @@ class ClashResult(TypedDict):
|
||||
p1: list[float]
|
||||
p2: list[float]
|
||||
distance: float
|
||||
# Added by `Clasher.smart_group_clashes`.
|
||||
smart_group: NotRequired[int]
|
||||
|
||||
|
||||
class ClashSet(TypedDict):
|
||||
@@ -286,7 +288,8 @@ class Clasher:
|
||||
|
||||
positions = []
|
||||
for clash in clashes.values():
|
||||
positions.append(clash["position"])
|
||||
# Midpoint of p1/p2 as an approximation of the clash location for clustering purposes.
|
||||
positions.append([(a + b) / 2 for a, b in zip(clash["p1"], clash["p2"])])
|
||||
|
||||
data = np.array(positions)
|
||||
|
||||
|
||||
@@ -252,6 +252,10 @@ int main(int argc, char** argv) {
|
||||
("stderr-progress", "output progress to stderr stream")
|
||||
("yes,y", "answer 'yes' automatically to possible confirmation queries (e.g. overwriting an existing output file)")
|
||||
("no-progress", "suppress possible progress bar type of prints that use carriage return")
|
||||
("fail-on-error", "return a non-zero exit code when one or more errors were logged during "
|
||||
"geometry conversion (e.g. an element failed to convert). By default IfcConvert exits "
|
||||
"successfully as long as an output file could be written, even if some elements were "
|
||||
"silently dropped. Enable this flag so scripts and CI can detect partial conversions.")
|
||||
("log-format", po::value<std::string>(&log_format), "log format: plain or json")
|
||||
("log-file", new po::typed_value<path_t, char_t>(&log_file), "redirect log output to file");
|
||||
|
||||
@@ -449,6 +453,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
const bool mmap = vmap.count("mmap") != 0;
|
||||
const bool no_progress = vmap.count("no-progress") != 0;
|
||||
const bool fail_on_error = vmap.count("fail-on-error") != 0;
|
||||
const bool quiet = vmap.count("quiet") != 0;
|
||||
const bool stderr_progress = vmap.count("stderr-progress") != 0;
|
||||
|
||||
@@ -885,6 +890,7 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
if (!serializer->ready()) {
|
||||
logger.Error("SYS", 25, "Unable to open output file '" + IfcUtil::path::to_utf8(output_filename) + "' for writing; check that the directory exists and is writable");
|
||||
IfcUtil::path::delete_file(IfcUtil::path::to_utf8(output_temp_filename));
|
||||
write_log(!quiet);
|
||||
return EXIT_FAILURE;
|
||||
@@ -1220,6 +1226,11 @@ int main(int argc, char** argv) {
|
||||
successful = false;
|
||||
}
|
||||
|
||||
if (fail_on_error && logger.MaxSeverity() >= Logger::LOG_ERROR) {
|
||||
logger.Error("SYS", 26, "Errors encountered during processing, failing due to --fail-on-error.");
|
||||
successful = false;
|
||||
}
|
||||
|
||||
if (logger.Verbosity() == Logger::LOG_PERF) {
|
||||
logger.PrintPerformanceStats();
|
||||
}
|
||||
|
||||
+10
-4
@@ -51,8 +51,10 @@ class IfcDiff:
|
||||
|
||||
:param old: IFC file object for the old model
|
||||
:param new: IFC file object for the new model
|
||||
:param relationships: List of relationships to check. None means that only
|
||||
geometry is compared. See RELATIONSHIP_TYPE for available relationships.
|
||||
:param relationships: List of relationships to check. None means that
|
||||
attributes and geometry are compared, so changes such as a modified or
|
||||
removed PredefinedType are reported. See RELATIONSHIP_TYPE for available
|
||||
relationships.
|
||||
:param is_shallow: True if you want only the first difference to be listed.
|
||||
False if you want all differences to be checked. Choosing False means
|
||||
that comparisons will take longer.
|
||||
@@ -86,7 +88,7 @@ class IfcDiff:
|
||||
self.new = new
|
||||
self.change_register = {}
|
||||
self.representation_ids = {}
|
||||
self.relationships = relationships or ["geometry"]
|
||||
self.relationships = relationships or ["attributes", "geometry"]
|
||||
self.precision = 1e-4
|
||||
self.is_shallow = is_shallow
|
||||
self.filter_elements = filter_elements
|
||||
@@ -435,7 +437,11 @@ if __name__ == "__main__":
|
||||
"-r",
|
||||
"--relationships",
|
||||
type=str,
|
||||
help='A list of space-separated relationships, chosen from "type", "property", "container", "aggregate", "classification"',
|
||||
help=(
|
||||
'A list of space-separated relationships, chosen from "attributes", "geometry", '
|
||||
'"type", "property", "container", "aggregate", "classification". '
|
||||
'Defaults to "attributes geometry" when omitted.'
|
||||
),
|
||||
default="",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
@@ -77,6 +77,23 @@ class TestIfcDiff:
|
||||
assert ifc_diff.deleted_elements == set()
|
||||
assert ifc_diff.change_register == {wall.GlobalId: {"attributes_changed": True}}
|
||||
|
||||
def test_changed_predefined_type_is_caught_by_default(self):
|
||||
# Regression test for #8214: a plain diff (no relationships specified)
|
||||
# must report a modified or removed PredefinedType. Previously the
|
||||
# default only compared geometry, so attribute-only edits were missed.
|
||||
ifc_file = setup_project()
|
||||
wall = ifcopenshell.api.root.create_entity(ifc_file, ifc_class="IfcWall", name="Foo")
|
||||
wall.PredefinedType = "SOLIDWALL"
|
||||
|
||||
new_file = ifc_file.from_string(ifc_file.to_string())
|
||||
new_file.by_id(wall.id()).PredefinedType = "NOTDEFINED"
|
||||
|
||||
ifc_diff = ifcdiff.IfcDiff(ifc_file, new_file)
|
||||
ifc_diff.diff()
|
||||
assert ifc_diff.added_elements == set()
|
||||
assert ifc_diff.deleted_elements == set()
|
||||
assert ifc_diff.change_register == {wall.GlobalId: {"attributes_changed": True}}
|
||||
|
||||
def test_changed_geometry(self):
|
||||
ifc_file = setup_project()
|
||||
wall = ifcopenshell.api.root.create_entity(ifc_file, ifc_class="IfcWall", name="Foo")
|
||||
|
||||
@@ -258,7 +258,7 @@ ifcedit quantify run model.ifc IFC4QtoBaseQuantities -o model_qto.ifc
|
||||
|
||||
Options:
|
||||
|
||||
- `--selector <query>` -- ifcopenshell selector to restrict elements (default: all `IfcElement`)
|
||||
- `--selector <query>` -- ifcopenshell selector to restrict elements (default: all `IfcElement` and `IfcSpace`)
|
||||
- `-o, --output <path>` -- write to a different file instead of overwriting the input
|
||||
|
||||
Note: `quantify run` writes geometry-based measurements and requires the
|
||||
|
||||
@@ -244,7 +244,9 @@ def main():
|
||||
qrun_parser = quantify_sub.add_parser("run", help="Run QTO on an IFC file")
|
||||
qrun_parser.add_argument("ifc_file", help="Path to the IFC file")
|
||||
qrun_parser.add_argument("rule_name", help="QTO rule name (e.g. IFC4QtoBaseQuantities)")
|
||||
qrun_parser.add_argument("--selector", help="ifcopenshell selector to restrict elements (default: all IfcElement)")
|
||||
qrun_parser.add_argument(
|
||||
"--selector", help="ifcopenshell selector to restrict elements (default: all IfcElement and IfcSpace)"
|
||||
)
|
||||
qrun_parser.add_argument("-o", "--output", help="Output file path (default: overwrite input)")
|
||||
|
||||
args, extra = parser.parse_known_args()
|
||||
|
||||
@@ -60,9 +60,11 @@ def coerce_value(
|
||||
# Union / Optional
|
||||
if origin is typing.Union:
|
||||
non_none_types = [a for a in args if a is not type(None)]
|
||||
if value_str.lower() == "none":
|
||||
if isinstance(value_str, str) and value_str.lower() == "none":
|
||||
if type(None) in args:
|
||||
return None
|
||||
if value_str is None and type(None) in args:
|
||||
return None
|
||||
# Try each non-None type in order
|
||||
for t in non_none_types:
|
||||
try:
|
||||
|
||||
@@ -30,7 +30,7 @@ def run_quantify(model: ifcopenshell.file, rule: str, selector: str | None = Non
|
||||
if selector:
|
||||
elements = set(ifcopenshell.util.selector.filter_elements(model, selector))
|
||||
else:
|
||||
elements = set(model.by_type("IfcElement"))
|
||||
elements = set(model.by_type("IfcElement")) | set(model.by_type("IfcSpace"))
|
||||
|
||||
results = quantify(model, elements, rule_sets[rule])
|
||||
edit_qtos(model, results)
|
||||
|
||||
@@ -57,6 +57,16 @@ class TestOptionalCoercion:
|
||||
def test_optional_int(self):
|
||||
assert coerce_value("42", Optional[int]) == 42
|
||||
|
||||
def test_optional_entity_native_int(self, model):
|
||||
# MCP callers pass JSON-decoded native types (int), not CLI strings.
|
||||
wall = model.by_type("IfcWall")[0]
|
||||
result = coerce_value(wall.id(), Optional[ifcopenshell.entity_instance], model)
|
||||
assert result == wall
|
||||
|
||||
def test_optional_entity_native_none(self, model):
|
||||
# JSON null decodes to Python None, not the string "none".
|
||||
assert coerce_value(None, Optional[ifcopenshell.entity_instance], model) is None
|
||||
|
||||
|
||||
class TestUnionCoercion:
|
||||
def test_union_str_int(self):
|
||||
|
||||
@@ -85,3 +85,20 @@ class TestRunQuantify:
|
||||
def test_empty_selector_runs_on_all(self, quantify_model):
|
||||
result = run_quantify(quantify_model, "IFC4QtoBaseQuantities", selector=None)
|
||||
assert result["ok"] is True
|
||||
|
||||
def test_default_selector_includes_spaces(self, quantify_model, monkeypatch):
|
||||
"""IfcSpace is not a subtype of IfcElement, so the default scope must add it explicitly."""
|
||||
import ifc5d.qto
|
||||
|
||||
seen_elements = {}
|
||||
|
||||
def fake_quantify(ifc_file, elements, rules):
|
||||
seen_elements["elements"] = elements
|
||||
return {}
|
||||
|
||||
monkeypatch.setattr(ifc5d.qto, "quantify", fake_quantify)
|
||||
|
||||
space = ifcopenshell.api.root.create_entity(quantify_model, ifc_class="IfcSpace", name="TestSpace")
|
||||
run_quantify(quantify_model, "IFC4QtoBaseQuantities")
|
||||
|
||||
assert space in seen_elements["elements"]
|
||||
|
||||
@@ -28,6 +28,7 @@ import ifcopenshell.util.fm
|
||||
import ifcopenshell.util.placement
|
||||
import ifcopenshell.util.shape
|
||||
import ifcopenshell.util.system
|
||||
import ifcopenshell.util.unit
|
||||
from ifcopenshell.util.shape_builder import np_matrix_to_euler
|
||||
|
||||
# The original BIMServer plugin has a function called ifcToCOBie:
|
||||
@@ -920,6 +921,11 @@ def get_coordinate_data_(element: ifcopenshell.entity_instance) -> Generator[dic
|
||||
verts = ifcopenshell.util.shape.get_shape_vertices(shape, shape.geometry)
|
||||
categories = ("box-lowerleft", "box-upperright")
|
||||
bbox = ifcopenshell.util.shape.get_bbox(verts)
|
||||
# Geometry vertices are in SI metres, but Floor rows use the raw placement in
|
||||
# project length units. Convert space points to project units so the whole
|
||||
# Coordinate sheet is consistent with the Facility LinearUnits.
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(element.file)
|
||||
bbox = [point / unit_scale for point in bbox]
|
||||
base_data = base_data | {
|
||||
"Category": "point",
|
||||
"SheetName": "Space",
|
||||
|
||||
@@ -361,8 +361,8 @@ namespace ifcopenshell {
|
||||
|
||||
struct CircleSegments : public SettingBase<CircleSegments, int> {
|
||||
static constexpr const char* const name = "circle-segments";
|
||||
static constexpr const char* const description = "Number of segments to approximate full circles in CGAL kernel.";
|
||||
static constexpr int defaultvalue = 16;
|
||||
static constexpr const char* const description = "Number of segments to approximate full circles in the CGAL kernel. When 0 (the default) the segment count is derived from mesher-linear-deflection instead, so curves stay within the deflection tolerance regardless of radius.";
|
||||
static constexpr int defaultvalue = 0;
|
||||
};
|
||||
|
||||
struct CgalSmoothAngleDegrees : public SettingBase<CgalSmoothAngleDegrees, double> {
|
||||
|
||||
@@ -391,6 +391,11 @@ namespace {
|
||||
}
|
||||
};
|
||||
|
||||
// Representative radius used to size the polygonal approximation of a conic.
|
||||
// For an ellipse the larger semi-axis is the conservative choice.
|
||||
inline double conic_radius(const taxonomy::circle::ptr& c) { return c->radius; }
|
||||
inline double conic_radius(const taxonomy::ellipse::ptr& e) { return e->radius > e->radius2 ? e->radius : e->radius2; }
|
||||
|
||||
struct cgal_curve_creation_visitor {
|
||||
Settings& settings_;
|
||||
parameter_range param;
|
||||
@@ -425,7 +430,36 @@ namespace {
|
||||
if (b <= a) {
|
||||
b += 2 * M_PI;
|
||||
}
|
||||
int num_segments = (int)std::ceil(std::fabs(a - b) / (2 * M_PI) * settings_.get<settings::CircleSegments>().get());
|
||||
const double span = std::fabs(a - b);
|
||||
// CircleSegments controls how conics (circles, ellipses, arcs) are approximated
|
||||
// in the CGAL kernel. Two modes, one or the other:
|
||||
// - CircleSegments == 0 (the default): the segment count is derived from
|
||||
// MesherLinearDeflection, so the chord deviation stays within the mesher's
|
||||
// linear deflection regardless of radius. This matches the deflection based
|
||||
// meshing the OpenCascade kernel already does and fixes issue #8051, where
|
||||
// large radius arcs (curved curtain wall mullions) collapsed to straight chords
|
||||
// because a fixed segment count is radius agnostic.
|
||||
// - CircleSegments > 0: it is used directly as the number of segments for a full
|
||||
// circle, giving deterministic, radius independent output.
|
||||
int num_segments;
|
||||
const int circle_segments = settings_.get<settings::CircleSegments>().get();
|
||||
if (circle_segments > 0) {
|
||||
num_segments = (int)std::ceil(span / (2 * M_PI) * circle_segments);
|
||||
} else {
|
||||
const double radius = conic_radius(t);
|
||||
const double deflection = settings_.get<settings::MesherLinearDeflection>().get();
|
||||
if (deflection > 0. && radius > deflection) {
|
||||
const double max_segment_angle = 2.0 * std::acos(1.0 - deflection / radius);
|
||||
num_segments = (int)std::ceil(span / max_segment_angle);
|
||||
} else {
|
||||
// Radius within the deflection tolerance (or no deflection set): a chord per
|
||||
// quarter turn already keeps the deviation within tolerance.
|
||||
num_segments = (int)std::ceil(span / (M_PI / 2.));
|
||||
}
|
||||
}
|
||||
if (num_segments < 1) {
|
||||
num_segments = 1;
|
||||
}
|
||||
double du = (b - a) / num_segments;
|
||||
taxonomy::point3 P;
|
||||
// @nb for loop is not inclusive of the both end points
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <ShapeFix_Shape.hxx>
|
||||
#include <ShapeFix_ShapeTolerance.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRepExtrema_DistShapeShape.hxx>
|
||||
|
||||
#include <Standard_Macro.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
@@ -356,6 +357,27 @@ bool OpenCascadeKernel::convert(const taxonomy::face::ptr face, TopoDS_Shape& re
|
||||
return false;
|
||||
}
|
||||
|
||||
// #527: A face whose inner boundary intersects the outer boundary (or
|
||||
// another inner boundary) is invalid per the schema. Open Cascade heals or
|
||||
// drops such a face silently, so the intended hole is lost with no
|
||||
// diagnostic. The distance between two non-intersecting loops is strictly
|
||||
// positive; a distance at (or below) the modelling precision means the
|
||||
// boundaries touch or cross. Emit a clear warning so the invalid input is
|
||||
// not silently lost. wires() is ordered outer-first, inner-bounds after.
|
||||
if (fd.wires().size() > 1) {
|
||||
const auto& fwires = fd.wires();
|
||||
bool reported = false;
|
||||
for (size_t i = 1; i < fwires.size() && !reported; ++i) {
|
||||
for (size_t j = 0; j < i && !reported; ++j) {
|
||||
BRepExtrema_DistShapeShape dss(fwires[i], fwires[j]);
|
||||
if (dss.IsDone() && dss.Value() < precision_) {
|
||||
logger().Warning("GEO", 402, "Face inner boundary intersects another face boundary", face->instance);
|
||||
reported = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fd.surface().IsNull()) {
|
||||
// Use the first wire to find a plane manually for polygonal wires
|
||||
const TopoDS_Wire& wire = fd.wires().front();
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
// This file was generated with the assistance of an AI coding tool.
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "mapping.h"
|
||||
#define mapping POSTFIX_SCHEMA(mapping)
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
#include "../profile_helper.h"
|
||||
|
||||
// In IFC2X3 IfcAsymmetricIShapeProfileDef is a subtype of IfcIShapeProfileDef and is
|
||||
// therefore dispatched (and handled) by the IfcIShapeProfileDef mapping. From IFC4
|
||||
// onwards it is a standalone subtype of IfcParameterizedProfileDef with its own
|
||||
// Bottom*/Top* attributes, so nothing mapped it and the extrusion came out empty.
|
||||
// The presence of the standalone BottomFlangeWidth attribute is the discriminator:
|
||||
// it is only defined in the schemas where the type is standalone (IFC4 / IFC4X3).
|
||||
#ifdef SCHEMA_IfcAsymmetricIShapeProfileDef_HAS_BottomFlangeWidth
|
||||
|
||||
taxonomy::ptr mapping::map_impl(const IfcSchema::IfcAsymmetricIShapeProfileDef* inst) {
|
||||
// Bottom flange (half width), overall depth (half), web (half thickness).
|
||||
const double xb = inst->BottomFlangeWidth() / 2.0 * length_unit_;
|
||||
const double xt = inst->TopFlangeWidth() / 2.0 * length_unit_;
|
||||
const double y = inst->OverallDepth() / 2.0 * length_unit_;
|
||||
const double d1 = inst->WebThickness() / 2.0 * length_unit_;
|
||||
|
||||
// Bottom flange thickness; top flange thickness defaults to the bottom one.
|
||||
const double ftb = inst->BottomFlangeThickness() * length_unit_;
|
||||
const double ftt = inst->TopFlangeThickness().get_value_or(inst->BottomFlangeThickness()) * length_unit_;
|
||||
|
||||
// Optional fillet radii (web/flange transition) and flange edge radii.
|
||||
const double fb = inst->BottomFlangeFilletRadius().get_value_or(0.) * length_unit_;
|
||||
const double ft_top = inst->TopFlangeFilletRadius().get_value_or(0.) * length_unit_;
|
||||
const double feb = inst->BottomFlangeEdgeRadius().get_value_or(0.) * length_unit_;
|
||||
const double fet = inst->TopFlangeEdgeRadius().get_value_or(0.) * length_unit_;
|
||||
|
||||
// Optional flange slopes: the inner edge of the flange rises towards the web.
|
||||
const double bottomSlope = inst->BottomFlangeSlope().get_value_or(0.) * angle_unit_;
|
||||
const double topSlope = inst->TopFlangeSlope().get_value_or(0.) * angle_unit_;
|
||||
const double dyb = (xb - d1) * tan(bottomSlope);
|
||||
const double dyt = (xt - d1) * tan(topSlope);
|
||||
|
||||
const double tol = settings_.get<settings::Precision>().get();
|
||||
|
||||
if (xb < tol || xt < tol || y < tol || d1 < tol || ftb < tol || ftt < tol) {
|
||||
logger_.Message(Logger::LOG_NOTICE, "GEO", 264, "Skipping zero sized profile:", inst);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
taxonomy::matrix4::ptr m4;
|
||||
bool has_position = true;
|
||||
#ifdef SCHEMA_IfcParameterizedProfileDef_Position_IS_OPTIONAL
|
||||
has_position = !!inst->Position();
|
||||
#endif
|
||||
if (has_position) {
|
||||
m4 = taxonomy::cast<taxonomy::matrix4>(map(inst->Position()));
|
||||
}
|
||||
|
||||
// Twelve corner points, running counter-clockwise from the bottom-left, with the
|
||||
// bottom flange (xb) possibly wider than the top flange (xt). Fillet/edge radii are
|
||||
// attached to the corner they round, matching the symmetric IfcIShapeProfileDef.
|
||||
return profile_helper(m4, {
|
||||
{{-xb,-y}},
|
||||
{{xb,-y}},
|
||||
{{xb,-y + ftb}, {feb}},
|
||||
{{d1,-y + ftb + dyb},{fb} },
|
||||
{{d1,y - ftt - dyt},{ft_top} },
|
||||
{{xt,y - ftt}, {fet}},
|
||||
{{xt,y}},
|
||||
{{-xt,y}},
|
||||
{{-xt,y - ftt}, {fet}},
|
||||
{{-d1,y - ftt - dyt},{ft_top} },
|
||||
{{-d1,-y + ftb + dyb},{fb} },
|
||||
{{-xb,-y + ftb}, {feb}}
|
||||
});
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -39,8 +39,25 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcPolygonalFaceSet* inst) {
|
||||
|
||||
int max_index = (int)points.size();
|
||||
|
||||
// When the optional PnIndex is present, CoordIndex values do not index into
|
||||
// CoordList directly but into PnIndex, which in turn remaps to CoordList.
|
||||
// Both index levels are 1-based per the IFC specification.
|
||||
auto pn_index = inst->PnIndex();
|
||||
auto resolve = [&](int idx) -> const taxonomy::point3::ptr& {
|
||||
if (pn_index) {
|
||||
if (idx < 1 || idx > (int)pn_index->size()) {
|
||||
throw IfcParse::IfcException("IfcPolygonalFaceSet PnIndex out of bounds for index " + boost::lexical_cast<std::string>(idx));
|
||||
}
|
||||
idx = (*pn_index)[idx - 1];
|
||||
}
|
||||
if (idx < 1 || idx > max_index) {
|
||||
throw IfcParse::IfcException("IfcPolygonalFaceSet index out of bounds for index " + boost::lexical_cast<std::string>(idx));
|
||||
}
|
||||
return points[idx - 1];
|
||||
};
|
||||
|
||||
auto shell = taxonomy::make<taxonomy::shell>();
|
||||
|
||||
|
||||
for (auto& f : *polygonal_faces) {
|
||||
auto fa = taxonomy::make<taxonomy::face>();
|
||||
shell->children.push_back(fa);
|
||||
@@ -52,17 +69,14 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcPolygonalFaceSet* inst) {
|
||||
auto indices = f->CoordIndex();
|
||||
taxonomy::point3::ptr previous;
|
||||
for (std::vector<int>::const_iterator jt = indices.begin(); jt != indices.end(); ++jt) {
|
||||
if (*jt < 1 || *jt > max_index) {
|
||||
throw IfcParse::IfcException("IfcPolygonalFaceSet index out of bounds for index " + boost::lexical_cast<std::string>(*jt));
|
||||
}
|
||||
auto current = points[(*jt) - 1];
|
||||
auto current = resolve(*jt);
|
||||
if (jt != indices.begin()) {
|
||||
loop->children.push_back(taxonomy::make<taxonomy::edge>(previous, current));
|
||||
}
|
||||
previous = current;
|
||||
}
|
||||
if (!indices.empty()) {
|
||||
auto current = points[indices.front() - 1];
|
||||
auto current = resolve(indices.front());
|
||||
loop->children.push_back(taxonomy::make<taxonomy::edge>(previous, current));
|
||||
}
|
||||
}
|
||||
@@ -77,17 +91,14 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcPolygonalFaceSet* inst) {
|
||||
loop->external = false;
|
||||
|
||||
for (std::vector<int>::const_iterator jt = li.begin(); jt != li.end(); ++jt) {
|
||||
if (*jt < 1 || *jt > max_index) {
|
||||
throw IfcParse::IfcException("IfcPolygonalFaceSet index out of bounds for index " + boost::lexical_cast<std::string>(*jt));
|
||||
}
|
||||
auto current = points[(*jt) - 1];
|
||||
auto current = resolve(*jt);
|
||||
if (jt != li.begin()) {
|
||||
loop->children.push_back(taxonomy::make<taxonomy::edge>(previous, current));
|
||||
}
|
||||
previous = current;
|
||||
}
|
||||
if (!li.empty()) {
|
||||
auto current = points[li.front() - 1];
|
||||
auto current = resolve(li.front());
|
||||
loop->children.push_back(taxonomy::make<taxonomy::edge>(previous, current));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,23 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcTriangulatedFaceSet* inst) {
|
||||
|
||||
int max_index = (int)points.size();
|
||||
|
||||
// When the optional PnIndex is present, CoordIndex values do not index into
|
||||
// CoordList directly but into PnIndex, which in turn remaps to CoordList.
|
||||
// Both index levels are 1-based per the IFC specification.
|
||||
auto pn_index = inst->PnIndex();
|
||||
auto resolve = [&](int idx) -> const taxonomy::point3::ptr& {
|
||||
if (pn_index) {
|
||||
if (idx < 1 || idx > (int)pn_index->size()) {
|
||||
throw IfcParse::IfcException("IfcTriangulatedFaceSet PnIndex out of bounds for index " + boost::lexical_cast<std::string>(idx));
|
||||
}
|
||||
idx = (*pn_index)[idx - 1];
|
||||
}
|
||||
if (idx < 1 || idx > max_index) {
|
||||
throw IfcParse::IfcException("IfcTriangulatedFaceSet index out of bounds for index " + boost::lexical_cast<std::string>(idx));
|
||||
}
|
||||
return points[idx - 1];
|
||||
};
|
||||
|
||||
auto shell = taxonomy::make<taxonomy::shell>();
|
||||
|
||||
for (auto& indices : indices_list) {
|
||||
@@ -51,10 +68,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcTriangulatedFaceSet* inst) {
|
||||
loop->external = true;
|
||||
taxonomy::point3::ptr first, previous;
|
||||
for (std::vector<int>::const_iterator jt = indices.begin(); jt != indices.end(); ++jt) {
|
||||
if (*jt < 1 || *jt > max_index) {
|
||||
throw IfcParse::IfcException("IfcTriangulatedFaceSet index out of bounds for index " + boost::lexical_cast<std::string>(*jt));
|
||||
}
|
||||
const taxonomy::point3::ptr& current = points[(*jt) - 1];
|
||||
const taxonomy::point3::ptr& current = resolve(*jt);
|
||||
if (jt == indices.begin()) {
|
||||
first = current;
|
||||
} else {
|
||||
|
||||
@@ -89,7 +89,11 @@ BIND(IfcRectangleHollowProfileDef);
|
||||
BIND(IfcRectangleProfileDef);
|
||||
BIND(IfcTrapeziumProfileDef);
|
||||
BIND(IfcCShapeProfileDef);
|
||||
// IfcAsymmetricIShapeProfileDef included
|
||||
// In IFC2X3 IfcAsymmetricIShapeProfileDef is a subtype of IfcIShapeProfileDef and is
|
||||
// mapped by it; from IFC4 onwards it is a standalone type and needs its own binding.
|
||||
#ifdef SCHEMA_IfcAsymmetricIShapeProfileDef_HAS_BottomFlangeWidth
|
||||
BIND(IfcAsymmetricIShapeProfileDef);
|
||||
#endif
|
||||
BIND(IfcIShapeProfileDef);
|
||||
BIND(IfcLShapeProfileDef);
|
||||
BIND(IfcTShapeProfileDef);
|
||||
|
||||
@@ -255,7 +255,7 @@ ifc_quantify(rule="IFC4QtoBaseQuantities", selector="IfcWall")
|
||||
Available rules: `IFC4QtoBaseQuantities`, `IFC4X3QtoBaseQuantities`.
|
||||
|
||||
`selector` is an optional ifcopenshell selector to restrict which elements
|
||||
are quantified (default: all `IfcElement`).
|
||||
are quantified (default: all `IfcElement` and `IfcSpace`).
|
||||
|
||||
Returns `{"ok": true, "rule": "...", "elements_quantified": 42}`.
|
||||
|
||||
|
||||
@@ -703,7 +703,7 @@ class IfcSession:
|
||||
"rule": {"type": "string", "description": "QTO rule name, e.g. IFC4QtoBaseQuantities"},
|
||||
"selector": {
|
||||
"type": "string",
|
||||
"description": "ifcopenshell selector to restrict elements (default: all IfcElement)",
|
||||
"description": "ifcopenshell selector to restrict elements (default: all IfcElement and IfcSpace)",
|
||||
},
|
||||
},
|
||||
"required": ["rule"],
|
||||
|
||||
@@ -311,8 +311,12 @@ CLI Manual
|
||||
output.
|
||||
--force-space-transparency arg Overrides transparency of spaces in
|
||||
geometry output.
|
||||
--circle-segments arg (= 16) Number of segments to approximate full
|
||||
circles in CGAL kernel.
|
||||
--circle-segments arg (= 0) Number of segments to approximate full
|
||||
circles in the CGAL kernel. When 0 (the
|
||||
default) the segment count is derived from
|
||||
mesher-linear-deflection instead, so curves
|
||||
stay within the deflection tolerance
|
||||
regardless of radius.
|
||||
--cgal-smooth-angle-degrees arg (= -1)
|
||||
Angle in degrees under which adjacent
|
||||
facets will have averaged vertex
|
||||
|
||||
@@ -72,6 +72,8 @@ Filtering is typically used to select any IFC element or type.
|
||||
|
||||
"``IfcPump, location=""Level 3""``", "Locations bubble up the hierarchy. So if a pump is in a space and that space is on Level 3, then you can say ""all pumps on level 3"" which will include that pump in the space."
|
||||
|
||||
"``IfcElement, query:""parent.Name""=""My Site""``", "Only elements *immediately* under ""My Site"" in the spatial hierarchy. Unlike the ``location`` and ``parent`` filters, which both match at any depth, the ``parent`` query key resolves the direct parent only, so nested storeys (and their contents) are excluded."
|
||||
|
||||
The filter elements syntax works by specifying one or more groups of filters
|
||||
separated by a ``+`` character. Each filter group will return a set of filtered
|
||||
elements, and these are unioned together.
|
||||
@@ -87,6 +89,11 @@ The filters are chained and apply from left to right.
|
||||
|
||||
filter[, filter]*
|
||||
|
||||
Any part of a query may be commented out using a ``/* ... */`` block comment.
|
||||
This lets you temporarily disable part of a query without deleting the text, for
|
||||
example ``IfcWall + /* IfcSlab, material=concrete */`` selects only walls while
|
||||
keeping the slab criteria on hand. Block comments may span multiple lines.
|
||||
|
||||
Below is the table of filters to choose from. Most of these filters will filter
|
||||
previously added elements in your filter group based on their criteria.
|
||||
|
||||
@@ -111,6 +118,15 @@ will search through all IfcTypeProducts and IfcProducts in the IFC project.
|
||||
"Parent", "Filter", "``parent{{=}}{{value}}``", "``parent=Foo`` specifies the criteria that elements must be a direct or indirect child in the spatial hierarchy to an element with a ``Name`` attribute with a value of ``Foo``."
|
||||
"Query", "Filter", "``query:{{keys}}{{=}}{{value}}``", "``query:types.count=0`` specifies the criteria that elements must have zero type occurrences. The query keys corresponds to the syntax used in the `Getting element values`_ section"
|
||||
|
||||
.. note::
|
||||
|
||||
The ``location`` and ``parent`` filters both match at **any depth** in the
|
||||
spatial hierarchy. To match only elements *immediately* contained in (or
|
||||
aggregated under) a spatial element, use the ``parent`` query key, which
|
||||
resolves the direct parent only. For example,
|
||||
``query:"parent.Name"="My Site"`` selects elements directly under ``My
|
||||
Site`` but excludes anything nested inside its sub-storeys or spaces.
|
||||
|
||||
When you specify a filter with a ``{{=}}`` check, you can choose from one of
|
||||
the following comparison checks:
|
||||
|
||||
@@ -191,7 +207,7 @@ Valid keys are:
|
||||
"``storey``", "Gets the first IfcBuildingStorey spatial element that an element is contained in."
|
||||
"``building``", "Gets the first IfcBuilding spatial element that an element is contained in."
|
||||
"``site``", "Gets the first IfcSite spatial element that an element is contained in."
|
||||
"``parent``", "Gets the parent element in the spatial hierarchy."
|
||||
"``parent``", "Gets the **immediate** parent element in the spatial hierarchy (the direct spatial container, or the direct aggregate/nest/fill/void parent). Combine with ``.Name`` in a query filter to match only immediate children, e.g. ``query:""parent.Name""=""My Site""``."
|
||||
"``classification``", "Gets the element's classification reference(s)"
|
||||
"``group``", "Gets the element's group(s)"
|
||||
"``system``", "Gets the element's system(s). This is a subset of group(s)."
|
||||
@@ -206,6 +222,9 @@ Valid keys are:
|
||||
"``easting``", "Gets the map easting of the element's placement"
|
||||
"``northing``", "Gets the map northing of the element's placement"
|
||||
"``elevation``", "Gets the map elevation of the element's placement"
|
||||
"``rotation_x``", "Gets the X Euler rotation of the element's placement in degrees"
|
||||
"``rotation_y``", "Gets the Y Euler rotation of the element's placement in degrees"
|
||||
"``rotation_z``", "Gets the Z Euler rotation of the element's placement in degrees (e.g. plan rotation of a symbol)"
|
||||
"``count``", "If the previous key returns multiple things, count that list. Otherwise, return 1."
|
||||
"``{{number}}``", "If the previous key returns multiple things, fetch the ``{{number}}`` index (e.g. 0, 1, 2, 3, etc) item in that list."
|
||||
|
||||
|
||||
@@ -228,10 +228,10 @@ circle-segments
|
||||
+------+-----------------------+---------+
|
||||
| Type | IfcConvert Option | Default |
|
||||
+======+=======================+=========+
|
||||
| INT | ``--circle-segments`` | 16 |
|
||||
| INT | ``--circle-segments`` | 0 |
|
||||
+------+-----------------------+---------+
|
||||
|
||||
Number of segments to approximate full circles in CGAL kernel.
|
||||
Number of segments to approximate full circles in the CGAL kernel. When 0 (the default) the segment count is derived from mesher-linear-deflection instead, so curves stay within the deflection tolerance regardless of radius.
|
||||
|
||||
context-identifiers
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -90,9 +90,9 @@ def add_boolean(
|
||||
|
||||
booleans = []
|
||||
for second_item in second_items:
|
||||
if first.is_a("IfcTesselatedFaceSet"):
|
||||
if first.is_a("IfcTessellatedFaceSet"):
|
||||
first.Closed = True # For now, trust the user to do the right thing.
|
||||
if second_item.is_a("IfcTesselatedFaceSet"):
|
||||
if second_item.is_a("IfcTessellatedFaceSet"):
|
||||
second_item.Closed = True # For now, trust the user to do the right thing.
|
||||
if (
|
||||
operator == "DIFFERENCE"
|
||||
|
||||
@@ -81,7 +81,7 @@ def assign_resource(
|
||||
"""
|
||||
if related_object.HasAssignments:
|
||||
for assignment in related_object.HasAssignments:
|
||||
if assignment.is_a("IfclRelAssignsToResource") and assignment.RelatingResource == relating_resource:
|
||||
if assignment.is_a("IfcRelAssignsToResource") and assignment.RelatingResource == relating_resource:
|
||||
return assignment
|
||||
|
||||
resource_of = None
|
||||
|
||||
@@ -409,9 +409,9 @@ class entity_instance:
|
||||
@overload
|
||||
def is_a(self) -> str: ...
|
||||
@overload
|
||||
def is_a(self, ifc_class: str) -> bool: ...
|
||||
def is_a(self, ifc_class: str, /) -> bool: ...
|
||||
@overload
|
||||
def is_a(self, with_schema: bool) -> str: ...
|
||||
def is_a(self, with_schema: bool, /) -> str: ...
|
||||
def is_a(self, *args: Union[str, bool]) -> Union[str, bool]:
|
||||
"""Return the IFC class name of an instance, or checks if an instance belongs to a class.
|
||||
|
||||
|
||||
@@ -23,10 +23,7 @@ import itertools
|
||||
|
||||
from pyparsing import *
|
||||
|
||||
try:
|
||||
from functools import reduce
|
||||
except:
|
||||
pass
|
||||
from functools import reduce
|
||||
|
||||
|
||||
class Expression:
|
||||
@@ -97,15 +94,15 @@ PERIOD = Suppress(".")
|
||||
HASH = Suppress("#")
|
||||
|
||||
identifier = Word(alphanums + "_")
|
||||
keyword = Word(alphanums + "_").setParseAction(Keyword)
|
||||
keyword = Word(alphanums + "_").set_parse_action(Keyword)
|
||||
expression = Forward()
|
||||
optional = Group(LBRACK + expression + RBRACK).setParseAction(Optional)
|
||||
repeated = Group(LBRACE + expression + RBRACE).setParseAction(Repeated)
|
||||
terminal = quotedString.setParseAction(Terminal)
|
||||
term = (keyword | terminal | optional | repeated | (LPAREN + expression + RPAREN)).setParseAction(Term)
|
||||
concat = Group(term + OneOrMore(term)).setParseAction(Concat)
|
||||
optional = Group(LBRACK + expression + RBRACK).set_parse_action(Optional)
|
||||
repeated = Group(LBRACE + expression + RBRACE).set_parse_action(Repeated)
|
||||
terminal = quotedString.set_parse_action(Terminal)
|
||||
term = (keyword | terminal | optional | repeated | (LPAREN + expression + RPAREN)).set_parse_action(Term)
|
||||
concat = Group(term + OneOrMore(term)).set_parse_action(Concat)
|
||||
factor = concat | term
|
||||
union = Group(factor + OneOrMore(VBAR + factor)).setParseAction(Union)
|
||||
union = Group(factor + OneOrMore(VBAR + factor)).set_parse_action(Union)
|
||||
rule = identifier + EQUALS + expression + PERIOD
|
||||
|
||||
expression << (union | factor)
|
||||
@@ -113,7 +110,7 @@ expression << (union | factor)
|
||||
grammar = OneOrMore(Group(rule))
|
||||
grammar.ignore(HASH + restOfLine)
|
||||
|
||||
express = grammar.parseFile(os.path.join(os.path.dirname(__file__), "express.bnf"))
|
||||
express = grammar.parse_file(os.path.join(os.path.dirname(__file__), "express.bnf"))
|
||||
|
||||
|
||||
def find_bytype(expr, ty, li=None):
|
||||
@@ -161,6 +158,8 @@ statements = []
|
||||
|
||||
terminals = reduce(lambda x, y: x | y, (find_bytype(e, Terminal) for id, e in express))
|
||||
keywords = list(filter(operator.attrgetter("is_keyword"), terminals))
|
||||
# terminals is identity-ordered (no __eq__/__hash__), so sort for determinism
|
||||
keywords.sort(key=lambda x: repr(x))
|
||||
negated_keywords = map(lambda s: "~%s" % s, keywords)
|
||||
no_action = {
|
||||
"letter",
|
||||
@@ -185,36 +184,36 @@ while True:
|
||||
emitted.add(id)
|
||||
stmt = "(%s)" % expr
|
||||
if id in to_combine:
|
||||
stmt = " + ".join(itertools.chain(negated_keywords, ("originalTextFor(Combine%s)" % stmt,)))
|
||||
stmt = " + ".join(itertools.chain(negated_keywords, ("original_text_for(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
|
||||
stmt = "(original_text_for%s).add_parse_action(token_map(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))
|
||||
stmt = "%s.setParseAction(%s)" % (stmt, action)
|
||||
stmt = "%s.set_parse_action(%s)" % (stmt, action)
|
||||
statements.append('%s = %s("%s")' % (id, stmt, id))
|
||||
to_emit -= emitted_in_loop
|
||||
if not emitted_in_loop:
|
||||
break
|
||||
|
||||
for id in to_emit:
|
||||
for id in sorted(to_emit):
|
||||
statements.append('%s = Forward()("%s")' % (id, id))
|
||||
|
||||
for id in to_emit:
|
||||
for id in sorted(to_emit):
|
||||
expr = [e for k, e in express if k == id][0]
|
||||
stmt = "(%s)" % expr
|
||||
if id in to_combine:
|
||||
stmt = "Suppress%s" % stmt
|
||||
elif id in to_original_text:
|
||||
stmt = "(originalTextFor%s).addParseAction(tokenMap(str.lower))" % stmt
|
||||
stmt = "(original_text_for%s).add_parse_action(token_map(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))
|
||||
node_type = "ListNode" if ("ZeroOrMore" in stmt or has_duplicates) else "Node"
|
||||
action = ".setParseAction(%s)" % (
|
||||
action = ".set_parse_action(%s)" % (
|
||||
actions[id] if id in actions else 'lambda s, loc, t: %s(s, loc, t, rule="%s")' % (node_type, id)
|
||||
)
|
||||
stmt = "(%s)%s" % (stmt, action)
|
||||
@@ -222,7 +221,7 @@ for id in to_emit:
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(r"""
|
||||
# This file is generated by IfcOpenShell ifcexpressparser bootstrap.py
|
||||
# This file is generated by ifcopenshell.express.bootstrap
|
||||
|
||||
from __future__ import annotations
|
||||
import os
|
||||
@@ -240,19 +239,19 @@ def parse(fn: str) -> mapping.Mapping:
|
||||
if os.path.exists(cache_file) and os.path.getmtime(cache_file) >= os.path.getmtime(fn):
|
||||
with open(cache_file, "rb") as f:
|
||||
m = pickle.load(f)
|
||||
else:
|
||||
else:
|
||||
%s
|
||||
|
||||
syntax.ignore("--" + restOfLine)
|
||||
syntax.ignore(Regex(r"\((?:\*(?:[^*]*\*+)+?\))"))
|
||||
ast = syntax.parseFile(fn)
|
||||
ast = syntax.parse_file(fn)
|
||||
s = schema.Schema(ast)
|
||||
m = mapping.Mapping(s)
|
||||
|
||||
with open(cache_file, "wb") as f:
|
||||
pickle.dump(m, f, protocol=0)
|
||||
return m
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
m = parse(sys.argv[1])
|
||||
import importlib
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
import itertools
|
||||
import functools
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def indent(n, s):
|
||||
@@ -36,15 +37,4 @@ class Base:
|
||||
"""
|
||||
|
||||
def emit(self):
|
||||
import platform
|
||||
|
||||
if tuple(map(int, platform.python_version_tuple())) < (2, 8):
|
||||
from io import open as unicode_open
|
||||
|
||||
unicode_type = unicode
|
||||
else:
|
||||
unicode_open = open
|
||||
unicode_type = lambda x, *args, **kwargs: x
|
||||
f = unicode_open(self.file_name, "w", encoding="utf-8")
|
||||
f.write(unicode_type(repr(self), encoding="utf-8", errors="ignore"))
|
||||
f.close()
|
||||
Path(self.file_name).write_text(repr(self), encoding="utf-8")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
# This file is generated by IfcOpenShell ifcexpressparser bootstrap.py
|
||||
# This file is generated by ifcopenshell.express.bootstrap
|
||||
|
||||
from __future__ import annotations
|
||||
import os
|
||||
@@ -17,184 +17,184 @@ def parse(fn: str) -> mapping.Mapping:
|
||||
if os.path.exists(cache_file) and os.path.getmtime(cache_file) >= os.path.getmtime(fn):
|
||||
with open(cache_file, "rb") as f:
|
||||
m = pickle.load(f)
|
||||
else:
|
||||
ABS = (CaselessKeyword("abs")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="ABS"))("ABS")
|
||||
ABSTRACT = (CaselessKeyword("abstract")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="ABSTRACT"))("ABSTRACT")
|
||||
ACOS = (CaselessKeyword("acos")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="ACOS"))("ACOS")
|
||||
AGGREGATE = (CaselessKeyword("aggregate")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="AGGREGATE"))("AGGREGATE")
|
||||
ALIAS = (CaselessKeyword("alias")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="ALIAS"))("ALIAS")
|
||||
AND = (CaselessKeyword("and")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="AND"))("AND")
|
||||
ANDOR = (CaselessKeyword("andor")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="ANDOR"))("ANDOR")
|
||||
ARRAY = (CaselessKeyword("array")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="ARRAY"))("ARRAY")
|
||||
AS = (CaselessKeyword("as")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="AS"))("AS")
|
||||
ASIN = (CaselessKeyword("asin")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="ASIN"))("ASIN")
|
||||
ATAN = (CaselessKeyword("atan")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="ATAN"))("ATAN")
|
||||
BAG = (CaselessKeyword("bag")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="BAG"))("BAG")
|
||||
BASED_ON = (CaselessKeyword("based_on")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="BASED_ON"))("BASED_ON")
|
||||
BEGIN = (CaselessKeyword("begin")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="BEGIN"))("BEGIN")
|
||||
BINARY = (CaselessKeyword("binary")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="BINARY"))("BINARY")
|
||||
BLENGTH = (CaselessKeyword("blength")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="BLENGTH"))("BLENGTH")
|
||||
BOOLEAN = (CaselessKeyword("boolean")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="BOOLEAN"))("BOOLEAN")
|
||||
BY = (CaselessKeyword("by")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="BY"))("BY")
|
||||
CASE = (CaselessKeyword("case")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="CASE"))("CASE")
|
||||
CONSTANT = (CaselessKeyword("constant")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="CONSTANT"))("CONSTANT")
|
||||
CONST_E = (CaselessKeyword("const_e")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="CONST_E"))("CONST_E")
|
||||
COS = (CaselessKeyword("cos")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="COS"))("COS")
|
||||
DERIVE = (CaselessKeyword("derive")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="DERIVE"))("DERIVE")
|
||||
DIV = (CaselessKeyword("div")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="DIV"))("DIV")
|
||||
ELSE = (CaselessKeyword("else")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="ELSE"))("ELSE")
|
||||
END = (CaselessKeyword("end")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="END"))("END")
|
||||
END_ALIAS = (CaselessKeyword("end_alias")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="END_ALIAS"))("END_ALIAS")
|
||||
END_CASE = (CaselessKeyword("end_case")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="END_CASE"))("END_CASE")
|
||||
END_CONSTANT = (CaselessKeyword("end_constant")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="END_CONSTANT"))("END_CONSTANT")
|
||||
END_ENTITY = (CaselessKeyword("end_entity")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="END_ENTITY"))("END_ENTITY")
|
||||
END_FUNCTION = (CaselessKeyword("end_function")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="END_FUNCTION"))("END_FUNCTION")
|
||||
END_IF = (CaselessKeyword("end_if")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="END_IF"))("END_IF")
|
||||
END_LOCAL = (CaselessKeyword("end_local")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="END_LOCAL"))("END_LOCAL")
|
||||
END_PROCEDURE = (CaselessKeyword("end_procedure")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="END_PROCEDURE"))("END_PROCEDURE")
|
||||
END_REPEAT = (CaselessKeyword("end_repeat")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="END_REPEAT"))("END_REPEAT")
|
||||
END_RULE = (CaselessKeyword("end_rule")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="END_RULE"))("END_RULE")
|
||||
END_SCHEMA = (CaselessKeyword("end_schema")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="END_SCHEMA"))("END_SCHEMA")
|
||||
END_SUBTYPE_CONSTRAINT = (CaselessKeyword("end_subtype_constraint")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="END_SUBTYPE_CONSTRAINT"))("END_SUBTYPE_CONSTRAINT")
|
||||
END_TYPE = (CaselessKeyword("end_type")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="END_TYPE"))("END_TYPE")
|
||||
ENTITY = (CaselessKeyword("entity")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="ENTITY"))("ENTITY")
|
||||
ENUMERATION = (CaselessKeyword("enumeration")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="ENUMERATION"))("ENUMERATION")
|
||||
ESCAPE = (CaselessKeyword("escape")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="ESCAPE"))("ESCAPE")
|
||||
EXISTS = (CaselessKeyword("exists")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="EXISTS"))("EXISTS")
|
||||
EXTENSIBLE = (CaselessKeyword("extensible")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="EXTENSIBLE"))("EXTENSIBLE")
|
||||
EXP = (CaselessKeyword("exp")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="EXP"))("EXP")
|
||||
FALSE = (CaselessKeyword("false")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="FALSE"))("FALSE")
|
||||
FIXED = (CaselessKeyword("fixed")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="FIXED"))("FIXED")
|
||||
FOR = (CaselessKeyword("for")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="FOR"))("FOR")
|
||||
FORMAT = (CaselessKeyword("format")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="FORMAT"))("FORMAT")
|
||||
FROM = (CaselessKeyword("from")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="FROM"))("FROM")
|
||||
FUNCTION = (CaselessKeyword("function")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="FUNCTION"))("FUNCTION")
|
||||
GENERIC = (CaselessKeyword("generic")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="GENERIC"))("GENERIC")
|
||||
GENERIC_ENTITY = (CaselessKeyword("generic_entity")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="GENERIC_ENTITY"))("GENERIC_ENTITY")
|
||||
HIBOUND = (CaselessKeyword("hibound")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="HIBOUND"))("HIBOUND")
|
||||
HIINDEX = (CaselessKeyword("hiindex")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="HIINDEX"))("HIINDEX")
|
||||
IF = (CaselessKeyword("if")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="IF"))("IF")
|
||||
IN = (CaselessKeyword("in")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="IN"))("IN")
|
||||
INSERT = (CaselessKeyword("insert")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="INSERT"))("INSERT")
|
||||
INTEGER = (CaselessKeyword("integer")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="INTEGER"))("INTEGER")
|
||||
INVERSE = (CaselessKeyword("inverse")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="INVERSE"))("INVERSE")
|
||||
LENGTH = (CaselessKeyword("length")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="LENGTH"))("LENGTH")
|
||||
LIKE = (CaselessKeyword("like")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="LIKE"))("LIKE")
|
||||
LIST = (CaselessKeyword("list")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="LIST"))("LIST")
|
||||
LOBOUND = (CaselessKeyword("lobound")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="LOBOUND"))("LOBOUND")
|
||||
LOCAL = (CaselessKeyword("local")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="LOCAL"))("LOCAL")
|
||||
LOG = (CaselessKeyword("log")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="LOG"))("LOG")
|
||||
LOG10 = (CaselessKeyword("log10")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="LOG10"))("LOG10")
|
||||
LOG2 = (CaselessKeyword("log2")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="LOG2"))("LOG2")
|
||||
LOGICAL = (CaselessKeyword("logical")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="LOGICAL"))("LOGICAL")
|
||||
LOINDEX = (CaselessKeyword("loindex")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="LOINDEX"))("LOINDEX")
|
||||
MOD = (CaselessKeyword("mod")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="MOD"))("MOD")
|
||||
NOT = (CaselessKeyword("not")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="NOT"))("NOT")
|
||||
NUMBER = (CaselessKeyword("number")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="NUMBER"))("NUMBER")
|
||||
NVL = (CaselessKeyword("nvl")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="NVL"))("NVL")
|
||||
ODD = (CaselessKeyword("odd")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="ODD"))("ODD")
|
||||
OF = (CaselessKeyword("of")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="OF"))("OF")
|
||||
ONEOF = (CaselessKeyword("oneof")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="ONEOF"))("ONEOF")
|
||||
OPTIONAL = (CaselessKeyword("optional")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="OPTIONAL"))("OPTIONAL")
|
||||
OR = (CaselessKeyword("or")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="OR"))("OR")
|
||||
OTHERWISE = (CaselessKeyword("otherwise")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="OTHERWISE"))("OTHERWISE")
|
||||
PI = (CaselessKeyword("pi")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="PI"))("PI")
|
||||
PROCEDURE = (CaselessKeyword("procedure")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="PROCEDURE"))("PROCEDURE")
|
||||
QUERY = (CaselessKeyword("query")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="QUERY"))("QUERY")
|
||||
REAL = (CaselessKeyword("real")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="REAL"))("REAL")
|
||||
REFERENCE = (CaselessKeyword("reference")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="REFERENCE"))("REFERENCE")
|
||||
REMOVE = (CaselessKeyword("remove")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="REMOVE"))("REMOVE")
|
||||
RENAMED = (CaselessKeyword("renamed")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="RENAMED"))("RENAMED")
|
||||
REPEAT = (CaselessKeyword("repeat")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="REPEAT"))("REPEAT")
|
||||
RETURN = (CaselessKeyword("return")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="RETURN"))("RETURN")
|
||||
ROLESOF = (CaselessKeyword("rolesof")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="ROLESOF"))("ROLESOF")
|
||||
RULE = (CaselessKeyword("rule")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="RULE"))("RULE")
|
||||
SCHEMA = (CaselessKeyword("schema")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="SCHEMA"))("SCHEMA")
|
||||
SELECT = (CaselessKeyword("select")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="SELECT"))("SELECT")
|
||||
SELF = (CaselessKeyword("self")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="SELF"))("SELF")
|
||||
SET = (CaselessKeyword("set")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="SET"))("SET")
|
||||
SIN = (CaselessKeyword("sin")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="SIN"))("SIN")
|
||||
SIZEOF = (CaselessKeyword("sizeof")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="SIZEOF"))("SIZEOF")
|
||||
SKIP = (CaselessKeyword("skip")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="SKIP"))("SKIP")
|
||||
SQRT = (CaselessKeyword("sqrt")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="SQRT"))("SQRT")
|
||||
STRING = (CaselessKeyword("string")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="STRING"))("STRING")
|
||||
SUBTYPE = (CaselessKeyword("subtype")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="SUBTYPE"))("SUBTYPE")
|
||||
SUBTYPE_CONSTRAINT = (CaselessKeyword("subtype_constraint")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="SUBTYPE_CONSTRAINT"))("SUBTYPE_CONSTRAINT")
|
||||
SUPERTYPE = (CaselessKeyword("supertype")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="SUPERTYPE"))("SUPERTYPE")
|
||||
TAN = (CaselessKeyword("tan")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="TAN"))("TAN")
|
||||
THEN = (CaselessKeyword("then")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="THEN"))("THEN")
|
||||
TO = (CaselessKeyword("to")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="TO"))("TO")
|
||||
TOTAL_OVER = (CaselessKeyword("total_over")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="TOTAL_OVER"))("TOTAL_OVER")
|
||||
TRUE = (CaselessKeyword("true")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="TRUE"))("TRUE")
|
||||
TYPE = (CaselessKeyword("type")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="TYPE"))("TYPE")
|
||||
TYPEOF = (CaselessKeyword("typeof")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="TYPEOF"))("TYPEOF")
|
||||
UNIQUE = (CaselessKeyword("unique")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="UNIQUE"))("UNIQUE")
|
||||
UNKNOWN = (CaselessKeyword("unknown")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="UNKNOWN"))("UNKNOWN")
|
||||
UNTIL = (CaselessKeyword("until")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="UNTIL"))("UNTIL")
|
||||
USE = (CaselessKeyword("use")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="USE"))("USE")
|
||||
USEDIN = (CaselessKeyword("usedin")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="USEDIN"))("USEDIN")
|
||||
VALUE = (CaselessKeyword("value")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="VALUE"))("VALUE")
|
||||
VALUE_IN = (CaselessKeyword("value_in")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="VALUE_IN"))("VALUE_IN")
|
||||
VALUE_UNIQUE = (CaselessKeyword("value_unique")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="VALUE_UNIQUE"))("VALUE_UNIQUE")
|
||||
VAR = (CaselessKeyword("var")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="VAR"))("VAR")
|
||||
WHERE = (CaselessKeyword("where")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="WHERE"))("WHERE")
|
||||
WHILE = (CaselessKeyword("while")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="WHILE"))("WHILE")
|
||||
WITH = (CaselessKeyword("with")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="WITH"))("WITH")
|
||||
XOR = (CaselessKeyword("xor")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="XOR"))("XOR")
|
||||
bit = ((CaselessLiteral("0") | CaselessLiteral("1"))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="bit"))("bit")
|
||||
else:
|
||||
ABS = (CaselessKeyword("abs")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="ABS"))("ABS")
|
||||
ABSTRACT = (CaselessKeyword("abstract")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="ABSTRACT"))("ABSTRACT")
|
||||
ACOS = (CaselessKeyword("acos")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="ACOS"))("ACOS")
|
||||
AGGREGATE = (CaselessKeyword("aggregate")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="AGGREGATE"))("AGGREGATE")
|
||||
ALIAS = (CaselessKeyword("alias")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="ALIAS"))("ALIAS")
|
||||
AND = (CaselessKeyword("and")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="AND"))("AND")
|
||||
ANDOR = (CaselessKeyword("andor")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="ANDOR"))("ANDOR")
|
||||
ARRAY = (CaselessKeyword("array")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="ARRAY"))("ARRAY")
|
||||
AS = (CaselessKeyword("as")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="AS"))("AS")
|
||||
ASIN = (CaselessKeyword("asin")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="ASIN"))("ASIN")
|
||||
ATAN = (CaselessKeyword("atan")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="ATAN"))("ATAN")
|
||||
BAG = (CaselessKeyword("bag")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="BAG"))("BAG")
|
||||
BASED_ON = (CaselessKeyword("based_on")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="BASED_ON"))("BASED_ON")
|
||||
BEGIN = (CaselessKeyword("begin")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="BEGIN"))("BEGIN")
|
||||
BINARY = (CaselessKeyword("binary")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="BINARY"))("BINARY")
|
||||
BLENGTH = (CaselessKeyword("blength")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="BLENGTH"))("BLENGTH")
|
||||
BOOLEAN = (CaselessKeyword("boolean")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="BOOLEAN"))("BOOLEAN")
|
||||
BY = (CaselessKeyword("by")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="BY"))("BY")
|
||||
CASE = (CaselessKeyword("case")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="CASE"))("CASE")
|
||||
CONSTANT = (CaselessKeyword("constant")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="CONSTANT"))("CONSTANT")
|
||||
CONST_E = (CaselessKeyword("const_e")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="CONST_E"))("CONST_E")
|
||||
COS = (CaselessKeyword("cos")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="COS"))("COS")
|
||||
DERIVE = (CaselessKeyword("derive")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="DERIVE"))("DERIVE")
|
||||
DIV = (CaselessKeyword("div")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="DIV"))("DIV")
|
||||
ELSE = (CaselessKeyword("else")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="ELSE"))("ELSE")
|
||||
END = (CaselessKeyword("end")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="END"))("END")
|
||||
END_ALIAS = (CaselessKeyword("end_alias")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="END_ALIAS"))("END_ALIAS")
|
||||
END_CASE = (CaselessKeyword("end_case")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="END_CASE"))("END_CASE")
|
||||
END_CONSTANT = (CaselessKeyword("end_constant")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="END_CONSTANT"))("END_CONSTANT")
|
||||
END_ENTITY = (CaselessKeyword("end_entity")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="END_ENTITY"))("END_ENTITY")
|
||||
END_FUNCTION = (CaselessKeyword("end_function")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="END_FUNCTION"))("END_FUNCTION")
|
||||
END_IF = (CaselessKeyword("end_if")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="END_IF"))("END_IF")
|
||||
END_LOCAL = (CaselessKeyword("end_local")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="END_LOCAL"))("END_LOCAL")
|
||||
END_PROCEDURE = (CaselessKeyword("end_procedure")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="END_PROCEDURE"))("END_PROCEDURE")
|
||||
END_REPEAT = (CaselessKeyword("end_repeat")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="END_REPEAT"))("END_REPEAT")
|
||||
END_RULE = (CaselessKeyword("end_rule")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="END_RULE"))("END_RULE")
|
||||
END_SCHEMA = (CaselessKeyword("end_schema")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="END_SCHEMA"))("END_SCHEMA")
|
||||
END_SUBTYPE_CONSTRAINT = (CaselessKeyword("end_subtype_constraint")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="END_SUBTYPE_CONSTRAINT"))("END_SUBTYPE_CONSTRAINT")
|
||||
END_TYPE = (CaselessKeyword("end_type")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="END_TYPE"))("END_TYPE")
|
||||
ENTITY = (CaselessKeyword("entity")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="ENTITY"))("ENTITY")
|
||||
ENUMERATION = (CaselessKeyword("enumeration")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="ENUMERATION"))("ENUMERATION")
|
||||
ESCAPE = (CaselessKeyword("escape")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="ESCAPE"))("ESCAPE")
|
||||
EXISTS = (CaselessKeyword("exists")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="EXISTS"))("EXISTS")
|
||||
EXTENSIBLE = (CaselessKeyword("extensible")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="EXTENSIBLE"))("EXTENSIBLE")
|
||||
EXP = (CaselessKeyword("exp")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="EXP"))("EXP")
|
||||
FALSE = (CaselessKeyword("false")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="FALSE"))("FALSE")
|
||||
FIXED = (CaselessKeyword("fixed")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="FIXED"))("FIXED")
|
||||
FOR = (CaselessKeyword("for")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="FOR"))("FOR")
|
||||
FORMAT = (CaselessKeyword("format")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="FORMAT"))("FORMAT")
|
||||
FROM = (CaselessKeyword("from")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="FROM"))("FROM")
|
||||
FUNCTION = (CaselessKeyword("function")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="FUNCTION"))("FUNCTION")
|
||||
GENERIC = (CaselessKeyword("generic")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="GENERIC"))("GENERIC")
|
||||
GENERIC_ENTITY = (CaselessKeyword("generic_entity")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="GENERIC_ENTITY"))("GENERIC_ENTITY")
|
||||
HIBOUND = (CaselessKeyword("hibound")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="HIBOUND"))("HIBOUND")
|
||||
HIINDEX = (CaselessKeyword("hiindex")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="HIINDEX"))("HIINDEX")
|
||||
IF = (CaselessKeyword("if")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="IF"))("IF")
|
||||
IN = (CaselessKeyword("in")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="IN"))("IN")
|
||||
INSERT = (CaselessKeyword("insert")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="INSERT"))("INSERT")
|
||||
INTEGER = (CaselessKeyword("integer")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="INTEGER"))("INTEGER")
|
||||
INVERSE = (CaselessKeyword("inverse")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="INVERSE"))("INVERSE")
|
||||
LENGTH = (CaselessKeyword("length")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="LENGTH"))("LENGTH")
|
||||
LIKE = (CaselessKeyword("like")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="LIKE"))("LIKE")
|
||||
LIST = (CaselessKeyword("list")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="LIST"))("LIST")
|
||||
LOBOUND = (CaselessKeyword("lobound")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="LOBOUND"))("LOBOUND")
|
||||
LOCAL = (CaselessKeyword("local")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="LOCAL"))("LOCAL")
|
||||
LOG = (CaselessKeyword("log")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="LOG"))("LOG")
|
||||
LOG10 = (CaselessKeyword("log10")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="LOG10"))("LOG10")
|
||||
LOG2 = (CaselessKeyword("log2")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="LOG2"))("LOG2")
|
||||
LOGICAL = (CaselessKeyword("logical")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="LOGICAL"))("LOGICAL")
|
||||
LOINDEX = (CaselessKeyword("loindex")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="LOINDEX"))("LOINDEX")
|
||||
MOD = (CaselessKeyword("mod")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="MOD"))("MOD")
|
||||
NOT = (CaselessKeyword("not")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="NOT"))("NOT")
|
||||
NUMBER = (CaselessKeyword("number")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="NUMBER"))("NUMBER")
|
||||
NVL = (CaselessKeyword("nvl")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="NVL"))("NVL")
|
||||
ODD = (CaselessKeyword("odd")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="ODD"))("ODD")
|
||||
OF = (CaselessKeyword("of")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="OF"))("OF")
|
||||
ONEOF = (CaselessKeyword("oneof")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="ONEOF"))("ONEOF")
|
||||
OPTIONAL = (CaselessKeyword("optional")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="OPTIONAL"))("OPTIONAL")
|
||||
OR = (CaselessKeyword("or")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="OR"))("OR")
|
||||
OTHERWISE = (CaselessKeyword("otherwise")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="OTHERWISE"))("OTHERWISE")
|
||||
PI = (CaselessKeyword("pi")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="PI"))("PI")
|
||||
PROCEDURE = (CaselessKeyword("procedure")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="PROCEDURE"))("PROCEDURE")
|
||||
QUERY = (CaselessKeyword("query")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="QUERY"))("QUERY")
|
||||
REAL = (CaselessKeyword("real")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="REAL"))("REAL")
|
||||
REFERENCE = (CaselessKeyword("reference")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="REFERENCE"))("REFERENCE")
|
||||
REMOVE = (CaselessKeyword("remove")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="REMOVE"))("REMOVE")
|
||||
RENAMED = (CaselessKeyword("renamed")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="RENAMED"))("RENAMED")
|
||||
REPEAT = (CaselessKeyword("repeat")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="REPEAT"))("REPEAT")
|
||||
RETURN = (CaselessKeyword("return")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="RETURN"))("RETURN")
|
||||
ROLESOF = (CaselessKeyword("rolesof")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="ROLESOF"))("ROLESOF")
|
||||
RULE = (CaselessKeyword("rule")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="RULE"))("RULE")
|
||||
SCHEMA = (CaselessKeyword("schema")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="SCHEMA"))("SCHEMA")
|
||||
SELECT = (CaselessKeyword("select")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="SELECT"))("SELECT")
|
||||
SELF = (CaselessKeyword("self")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="SELF"))("SELF")
|
||||
SET = (CaselessKeyword("set")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="SET"))("SET")
|
||||
SIN = (CaselessKeyword("sin")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="SIN"))("SIN")
|
||||
SIZEOF = (CaselessKeyword("sizeof")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="SIZEOF"))("SIZEOF")
|
||||
SKIP = (CaselessKeyword("skip")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="SKIP"))("SKIP")
|
||||
SQRT = (CaselessKeyword("sqrt")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="SQRT"))("SQRT")
|
||||
STRING = (CaselessKeyword("string")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="STRING"))("STRING")
|
||||
SUBTYPE = (CaselessKeyword("subtype")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="SUBTYPE"))("SUBTYPE")
|
||||
SUBTYPE_CONSTRAINT = (CaselessKeyword("subtype_constraint")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="SUBTYPE_CONSTRAINT"))("SUBTYPE_CONSTRAINT")
|
||||
SUPERTYPE = (CaselessKeyword("supertype")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="SUPERTYPE"))("SUPERTYPE")
|
||||
TAN = (CaselessKeyword("tan")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="TAN"))("TAN")
|
||||
THEN = (CaselessKeyword("then")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="THEN"))("THEN")
|
||||
TO = (CaselessKeyword("to")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="TO"))("TO")
|
||||
TOTAL_OVER = (CaselessKeyword("total_over")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="TOTAL_OVER"))("TOTAL_OVER")
|
||||
TRUE = (CaselessKeyword("true")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="TRUE"))("TRUE")
|
||||
TYPE = (CaselessKeyword("type")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="TYPE"))("TYPE")
|
||||
TYPEOF = (CaselessKeyword("typeof")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="TYPEOF"))("TYPEOF")
|
||||
UNIQUE = (CaselessKeyword("unique")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="UNIQUE"))("UNIQUE")
|
||||
UNKNOWN = (CaselessKeyword("unknown")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="UNKNOWN"))("UNKNOWN")
|
||||
UNTIL = (CaselessKeyword("until")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="UNTIL"))("UNTIL")
|
||||
USE = (CaselessKeyword("use")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="USE"))("USE")
|
||||
USEDIN = (CaselessKeyword("usedin")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="USEDIN"))("USEDIN")
|
||||
VALUE = (CaselessKeyword("value")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="VALUE"))("VALUE")
|
||||
VALUE_IN = (CaselessKeyword("value_in")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="VALUE_IN"))("VALUE_IN")
|
||||
VALUE_UNIQUE = (CaselessKeyword("value_unique")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="VALUE_UNIQUE"))("VALUE_UNIQUE")
|
||||
VAR = (CaselessKeyword("var")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="VAR"))("VAR")
|
||||
WHERE = (CaselessKeyword("where")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="WHERE"))("WHERE")
|
||||
WHILE = (CaselessKeyword("while")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="WHILE"))("WHILE")
|
||||
WITH = (CaselessKeyword("with")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="WITH"))("WITH")
|
||||
XOR = (CaselessKeyword("xor")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="XOR"))("XOR")
|
||||
bit = ((CaselessLiteral("0") | CaselessLiteral("1"))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="bit"))("bit")
|
||||
digit = ((CaselessLiteral("0") | CaselessLiteral("1") | CaselessLiteral("2") | CaselessLiteral("3") | CaselessLiteral("4") | CaselessLiteral("5") | CaselessLiteral("6") | CaselessLiteral("7") | CaselessLiteral("8") | CaselessLiteral("9")))("digit")
|
||||
digits = ((digit + ZeroOrMore(digit)))("digits")
|
||||
hex_digit = ((digit | CaselessLiteral("a") | CaselessLiteral("b") | CaselessLiteral("c") | CaselessLiteral("d") | CaselessLiteral("e") | CaselessLiteral("f"))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="hex_digit"))("hex_digit")
|
||||
hex_digit = ((digit | CaselessLiteral("a") | CaselessLiteral("b") | CaselessLiteral("c") | CaselessLiteral("d") | CaselessLiteral("e") | CaselessLiteral("f"))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="hex_digit"))("hex_digit")
|
||||
letter = ((CaselessLiteral("a") | CaselessLiteral("b") | CaselessLiteral("c") | CaselessLiteral("d") | CaselessLiteral("e") | CaselessLiteral("f") | CaselessLiteral("g") | CaselessLiteral("h") | CaselessLiteral("i") | CaselessLiteral("j") | CaselessLiteral("k") | CaselessLiteral("l") | CaselessLiteral("m") | CaselessLiteral("n") | CaselessLiteral("o") | CaselessLiteral("p") | CaselessLiteral("q") | CaselessLiteral("r") | CaselessLiteral("s") | CaselessLiteral("t") | CaselessLiteral("u") | CaselessLiteral("v") | CaselessLiteral("w") | CaselessLiteral("x") | CaselessLiteral("y") | CaselessLiteral("z")))("letter")
|
||||
not_paren_star_quote_special = ((CaselessLiteral("!") | CaselessLiteral("#") | CaselessLiteral("$") | CaselessLiteral("%") | CaselessLiteral("&") | CaselessLiteral("+") | CaselessLiteral(",") | CaselessLiteral("-") | CaselessLiteral(".") | CaselessLiteral("/") | CaselessLiteral(":") | CaselessLiteral(";") | CaselessLiteral("<") | CaselessLiteral("=") | CaselessLiteral(">") | CaselessLiteral("?") | CaselessLiteral("@") | CaselessLiteral("[") | CaselessLiteral("\\") | CaselessLiteral("]") | CaselessLiteral("^") | CaselessLiteral("_") | CaselessLiteral("{") | CaselessLiteral("|") | CaselessLiteral("}") | CaselessLiteral("~")))("not_paren_star_quote_special")
|
||||
not_paren_star_special = ((not_paren_star_quote_special | CaselessLiteral("\"\""))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="not_paren_star_special"))("not_paren_star_special")
|
||||
not_paren_star_special = ((not_paren_star_quote_special | CaselessLiteral("\"\""))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="not_paren_star_special"))("not_paren_star_special")
|
||||
not_quote = ((not_paren_star_quote_special | letter | digit | CaselessLiteral("(") | CaselessLiteral(")") | CaselessLiteral("*")))("not_quote")
|
||||
octet = ((hex_digit + hex_digit)).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="octet"))("octet")
|
||||
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")
|
||||
octet = ((hex_digit + hex_digit)).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="octet"))("octet")
|
||||
special = ((not_paren_star_quote_special | CaselessLiteral("(") | CaselessLiteral(")") | CaselessLiteral("*") | CaselessLiteral("\"\""))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="special"))("special")
|
||||
binary_literal = ((CaselessLiteral("%") + bit + ZeroOrMore(bit))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="binary_literal"))("binary_literal")
|
||||
integer_literal = (digits)("integer_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")
|
||||
simple_id = ~CaselessKeyword("abs") + ~CaselessKeyword("abstract") + ~CaselessKeyword("acos") + ~CaselessKeyword("aggregate") + ~CaselessKeyword("alias") + ~CaselessKeyword("and") + ~CaselessKeyword("andor") + ~CaselessKeyword("array") + ~CaselessKeyword("as") + ~CaselessKeyword("asin") + ~CaselessKeyword("atan") + ~CaselessKeyword("bag") + ~CaselessKeyword("based_on") + ~CaselessKeyword("begin") + ~CaselessKeyword("binary") + ~CaselessKeyword("blength") + ~CaselessKeyword("boolean") + ~CaselessKeyword("by") + ~CaselessKeyword("case") + ~CaselessKeyword("const_e") + ~CaselessKeyword("constant") + ~CaselessKeyword("cos") + ~CaselessKeyword("derive") + ~CaselessKeyword("div") + ~CaselessKeyword("else") + ~CaselessKeyword("end") + ~CaselessKeyword("end_alias") + ~CaselessKeyword("end_case") + ~CaselessKeyword("end_constant") + ~CaselessKeyword("end_entity") + ~CaselessKeyword("end_function") + ~CaselessKeyword("end_if") + ~CaselessKeyword("end_local") + ~CaselessKeyword("end_procedure") + ~CaselessKeyword("end_repeat") + ~CaselessKeyword("end_rule") + ~CaselessKeyword("end_schema") + ~CaselessKeyword("end_subtype_constraint") + ~CaselessKeyword("end_type") + ~CaselessKeyword("entity") + ~CaselessKeyword("enumeration") + ~CaselessKeyword("escape") + ~CaselessKeyword("exists") + ~CaselessKeyword("exp") + ~CaselessKeyword("extensible") + ~CaselessKeyword("false") + ~CaselessKeyword("fixed") + ~CaselessKeyword("for") + ~CaselessKeyword("format") + ~CaselessKeyword("from") + ~CaselessKeyword("function") + ~CaselessKeyword("generic") + ~CaselessKeyword("generic_entity") + ~CaselessKeyword("hibound") + ~CaselessKeyword("hiindex") + ~CaselessKeyword("if") + ~CaselessKeyword("in") + ~CaselessKeyword("insert") + ~CaselessKeyword("integer") + ~CaselessKeyword("inverse") + ~CaselessKeyword("length") + ~CaselessKeyword("like") + ~CaselessKeyword("list") + ~CaselessKeyword("lobound") + ~CaselessKeyword("local") + ~CaselessKeyword("log") + ~CaselessKeyword("log10") + ~CaselessKeyword("log2") + ~CaselessKeyword("logical") + ~CaselessKeyword("loindex") + ~CaselessKeyword("mod") + ~CaselessKeyword("not") + ~CaselessKeyword("number") + ~CaselessKeyword("nvl") + ~CaselessKeyword("odd") + ~CaselessKeyword("of") + ~CaselessKeyword("oneof") + ~CaselessKeyword("optional") + ~CaselessKeyword("or") + ~CaselessKeyword("otherwise") + ~CaselessKeyword("pi") + ~CaselessKeyword("procedure") + ~CaselessKeyword("query") + ~CaselessKeyword("real") + ~CaselessKeyword("reference") + ~CaselessKeyword("remove") + ~CaselessKeyword("renamed") + ~CaselessKeyword("repeat") + ~CaselessKeyword("return") + ~CaselessKeyword("rolesof") + ~CaselessKeyword("rule") + ~CaselessKeyword("schema") + ~CaselessKeyword("select") + ~CaselessKeyword("self") + ~CaselessKeyword("set") + ~CaselessKeyword("sin") + ~CaselessKeyword("sizeof") + ~CaselessKeyword("skip") + ~CaselessKeyword("sqrt") + ~CaselessKeyword("string") + ~CaselessKeyword("subtype") + ~CaselessKeyword("subtype_constraint") + ~CaselessKeyword("supertype") + ~CaselessKeyword("tan") + ~CaselessKeyword("then") + ~CaselessKeyword("to") + ~CaselessKeyword("total_over") + ~CaselessKeyword("true") + ~CaselessKeyword("type") + ~CaselessKeyword("typeof") + ~CaselessKeyword("unique") + ~CaselessKeyword("unknown") + ~CaselessKeyword("until") + ~CaselessKeyword("use") + ~CaselessKeyword("usedin") + ~CaselessKeyword("value") + ~CaselessKeyword("value_in") + ~CaselessKeyword("value_unique") + ~CaselessKeyword("var") + ~CaselessKeyword("where") + ~CaselessKeyword("while") + ~CaselessKeyword("with") + ~CaselessKeyword("xor") + original_text_for(Combine((letter + ZeroOrMore((letter | digit | CaselessLiteral("_"))))))("simple_id")
|
||||
simple_string_literal = (original_text_for((CaselessLiteral("'") + ZeroOrMore(((CaselessLiteral("'") + CaselessLiteral("'")) | not_quote)) + CaselessLiteral("'")))).add_parse_action(token_map(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")
|
||||
abstract_supertype = ((ABSTRACT + SUPERTYPE + CaselessLiteral(";"))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="abstract_supertype"))("abstract_supertype")
|
||||
add_like_op = ((CaselessLiteral("+") | CaselessLiteral("-") | OR | XOR)).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="add_like_op"))("add_like_op")
|
||||
attribute_id = (simple_id)("attribute_id")
|
||||
boolean_type = (BOOLEAN)("boolean_type")
|
||||
built_in_constant = ((CONST_E | PI | SELF | CaselessLiteral("?"))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="built_in_constant"))("built_in_constant")
|
||||
built_in_function = ((ABS | ACOS | ASIN | ATAN | BLENGTH | COS | EXISTS | EXP | FORMAT | HIBOUND | HIINDEX | LENGTH | LOBOUND | LOINDEX | LOG | LOG2 | LOG10 | NVL | ODD | ROLESOF | SIN | SIZEOF | SQRT | TAN | TYPEOF | USEDIN | VALUE | VALUE_IN | VALUE_UNIQUE)).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="built_in_function"))("built_in_function")
|
||||
built_in_procedure = ((INSERT | REMOVE)).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="built_in_procedure"))("built_in_procedure")
|
||||
built_in_constant = ((CONST_E | PI | SELF | CaselessLiteral("?"))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="built_in_constant"))("built_in_constant")
|
||||
built_in_function = ((ABS | ACOS | ASIN | ATAN | BLENGTH | COS | EXISTS | EXP | FORMAT | HIBOUND | HIINDEX | LENGTH | LOBOUND | LOINDEX | LOG | LOG2 | LOG10 | NVL | ODD | ROLESOF | SIN | SIZEOF | SQRT | TAN | TYPEOF | USEDIN | VALUE | VALUE_IN | VALUE_UNIQUE)).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="built_in_function"))("built_in_function")
|
||||
built_in_procedure = ((INSERT | REMOVE)).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="built_in_procedure"))("built_in_procedure")
|
||||
constant_id = (simple_id)("constant_id")
|
||||
entity_id = (simple_id)("entity_id")
|
||||
enumeration_id = (simple_id)("enumeration_id")
|
||||
enumeration_items = ((CaselessLiteral("(") + enumeration_id + ZeroOrMore((CaselessLiteral(",") + enumeration_id)) + CaselessLiteral(")"))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="enumeration_items"))("enumeration_items")
|
||||
escape_stmt = ((ESCAPE + CaselessLiteral(";"))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="escape_stmt"))("escape_stmt")
|
||||
enumeration_items = ((CaselessLiteral("(") + enumeration_id + ZeroOrMore((CaselessLiteral(",") + enumeration_id)) + CaselessLiteral(")"))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="enumeration_items"))("enumeration_items")
|
||||
escape_stmt = ((ESCAPE + CaselessLiteral(";"))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="escape_stmt"))("escape_stmt")
|
||||
function_id = (simple_id)("function_id")
|
||||
integer_type = (INTEGER)("integer_type")
|
||||
interval_op = ((CaselessLiteral("<=") | CaselessLiteral("<"))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="interval_op"))("interval_op")
|
||||
logical_literal = ((FALSE | TRUE | UNKNOWN)).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="logical_literal"))("logical_literal")
|
||||
interval_op = ((CaselessLiteral("<=") | CaselessLiteral("<"))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="interval_op"))("interval_op")
|
||||
logical_literal = ((FALSE | TRUE | UNKNOWN)).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="logical_literal"))("logical_literal")
|
||||
logical_type = (LOGICAL)("logical_type")
|
||||
multiplication_like_op = ((CaselessLiteral("*") | CaselessLiteral("/") | DIV | MOD | AND | CaselessLiteral("||"))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="multiplication_like_op"))("multiplication_like_op")
|
||||
null_stmt = (CaselessLiteral(";")).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="null_stmt"))("null_stmt")
|
||||
multiplication_like_op = ((CaselessLiteral("*") | CaselessLiteral("/") | DIV | MOD | AND | CaselessLiteral("||"))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="multiplication_like_op"))("multiplication_like_op")
|
||||
null_stmt = (CaselessLiteral(";")).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="null_stmt"))("null_stmt")
|
||||
number_type = (NUMBER)("number_type")
|
||||
parameter_id = (simple_id)("parameter_id")
|
||||
procedure_id = (simple_id)("procedure_id")
|
||||
rel_op = ((CaselessLiteral("<=") | CaselessLiteral(">=") | CaselessLiteral("<>") | CaselessLiteral("=") | CaselessLiteral(":<>:") | CaselessLiteral(":=:") | CaselessLiteral("<") | CaselessLiteral(">"))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="rel_op"))("rel_op")
|
||||
rel_op_extended = ((rel_op | IN | LIKE)).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="rel_op_extended"))("rel_op_extended")
|
||||
rel_op = ((CaselessLiteral("<=") | CaselessLiteral(">=") | CaselessLiteral("<>") | CaselessLiteral("=") | CaselessLiteral(":<>:") | CaselessLiteral(":=:") | CaselessLiteral("<") | CaselessLiteral(">"))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="rel_op"))("rel_op")
|
||||
rel_op_extended = ((rel_op | IN | LIKE)).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="rel_op_extended"))("rel_op_extended")
|
||||
rule_id = (simple_id)("rule_id")
|
||||
rule_label_id = (simple_id)("rule_label_id")
|
||||
schema_id = (simple_id)("schema_id")
|
||||
sign = ((CaselessLiteral("+") | CaselessLiteral("-"))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="sign"))("sign")
|
||||
skip_stmt = ((SKIP + CaselessLiteral(";"))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="skip_stmt"))("skip_stmt")
|
||||
sign = ((CaselessLiteral("+") | CaselessLiteral("-"))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="sign"))("sign")
|
||||
skip_stmt = ((SKIP + CaselessLiteral(";"))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="skip_stmt"))("skip_stmt")
|
||||
subtype_constraint_id = (simple_id)("subtype_constraint_id")
|
||||
type_id = (simple_id)("type_id")
|
||||
type_label_id = (simple_id)("type_label_id")
|
||||
unary_op = ((CaselessLiteral("+") | CaselessLiteral("-") | NOT)).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="unary_op"))("unary_op")
|
||||
unary_op = ((CaselessLiteral("+") | CaselessLiteral("-") | NOT)).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="unary_op"))("unary_op")
|
||||
variable_id = (simple_id)("variable_id")
|
||||
encoded_character = ((octet + octet + octet + octet)).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="encoded_character"))("encoded_character")
|
||||
not_paren_star = ((letter | digit | not_paren_star_special)).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="not_paren_star"))("not_paren_star")
|
||||
not_rparen_star = ((not_paren_star | CaselessLiteral("("))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="not_rparen_star"))("not_rparen_star")
|
||||
not_rparen_star_then_rparen = ((not_rparen_star + ZeroOrMore(not_rparen_star) + CaselessLiteral(")") + ZeroOrMore(CaselessLiteral(")")))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="not_rparen_star_then_rparen"))("not_rparen_star_then_rparen")
|
||||
encoded_string_literal = ((CaselessLiteral("\"") + encoded_character + ZeroOrMore(encoded_character) + CaselessLiteral("\""))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="encoded_string_literal"))("encoded_string_literal")
|
||||
encoded_character = ((octet + octet + octet + octet)).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="encoded_character"))("encoded_character")
|
||||
not_paren_star = ((letter | digit | not_paren_star_special)).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="not_paren_star"))("not_paren_star")
|
||||
not_rparen_star = ((not_paren_star | CaselessLiteral("("))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="not_rparen_star"))("not_rparen_star")
|
||||
not_rparen_star_then_rparen = ((not_rparen_star + ZeroOrMore(not_rparen_star) + CaselessLiteral(")") + ZeroOrMore(CaselessLiteral(")")))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="not_rparen_star_then_rparen"))("not_rparen_star_then_rparen")
|
||||
encoded_string_literal = ((CaselessLiteral("\"") + encoded_character + ZeroOrMore(encoded_character) + CaselessLiteral("\""))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="encoded_string_literal"))("encoded_string_literal")
|
||||
real_literal = (((digits + CaselessLiteral(".") + Optional(digits) + Optional((CaselessLiteral("e") + Optional(sign) + digits))) | integer_literal))("real_literal")
|
||||
attribute_ref = (attribute_id)("attribute_ref")
|
||||
constant_ref = (constant_id)("constant_ref")
|
||||
@@ -210,276 +210,276 @@ def parse(fn: str) -> mapping.Mapping:
|
||||
type_label_ref = (type_label_id)("type_label_ref")
|
||||
type_ref = (type_id)("type_ref")
|
||||
variable_ref = (variable_id)("variable_ref")
|
||||
attribute_qualifier = ((CaselessLiteral(".") + attribute_ref)).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="attribute_qualifier"))("attribute_qualifier")
|
||||
constant_factor = ((built_in_constant | constant_ref)).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="constant_factor"))("constant_factor")
|
||||
enumeration_extension = ((BASED_ON + type_ref + Optional((WITH + enumeration_items)))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="enumeration_extension"))("enumeration_extension")
|
||||
enumeration_reference = ((Optional((type_ref + CaselessLiteral("."))) + enumeration_ref)).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="enumeration_reference"))("enumeration_reference")
|
||||
enumeration_type = ((Optional(EXTENSIBLE) + ENUMERATION + Optional(((OF + enumeration_items) | enumeration_extension)))).setParseAction(EnumerationType)("enumeration_type")
|
||||
general_ref = ((parameter_ref | variable_ref)).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="general_ref"))("general_ref")
|
||||
group_qualifier = ((CaselessLiteral("\\") + entity_ref)).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="group_qualifier"))("group_qualifier")
|
||||
named_types = ((entity_ref | type_ref)).setParseAction(NamedType)("named_types")
|
||||
named_type_or_rename = ((named_types + Optional((AS + (entity_id | type_id))))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="named_type_or_rename"))("named_type_or_rename")
|
||||
attribute_qualifier = ((CaselessLiteral(".") + attribute_ref)).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="attribute_qualifier"))("attribute_qualifier")
|
||||
constant_factor = ((built_in_constant | constant_ref)).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="constant_factor"))("constant_factor")
|
||||
enumeration_extension = ((BASED_ON + type_ref + Optional((WITH + enumeration_items)))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="enumeration_extension"))("enumeration_extension")
|
||||
enumeration_reference = ((Optional((type_ref + CaselessLiteral("."))) + enumeration_ref)).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="enumeration_reference"))("enumeration_reference")
|
||||
enumeration_type = ((Optional(EXTENSIBLE) + ENUMERATION + Optional(((OF + enumeration_items) | enumeration_extension)))).set_parse_action(EnumerationType)("enumeration_type")
|
||||
general_ref = ((parameter_ref | variable_ref)).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="general_ref"))("general_ref")
|
||||
group_qualifier = ((CaselessLiteral("\\") + entity_ref)).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="group_qualifier"))("group_qualifier")
|
||||
named_types = ((entity_ref | type_ref)).set_parse_action(NamedType)("named_types")
|
||||
named_type_or_rename = ((named_types + Optional((AS + (entity_id | type_id))))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="named_type_or_rename"))("named_type_or_rename")
|
||||
population = (entity_ref)("population")
|
||||
qualified_attribute = ((SELF + group_qualifier + attribute_qualifier)).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="qualified_attribute"))("qualified_attribute")
|
||||
redeclared_attribute = ((qualified_attribute + Optional((RENAMED + attribute_id)))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="redeclared_attribute"))("redeclared_attribute")
|
||||
referenced_attribute = ((attribute_ref | qualified_attribute)).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="referenced_attribute"))("referenced_attribute")
|
||||
rename_id = ((constant_id | entity_id | function_id | procedure_id | type_id)).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="rename_id"))("rename_id")
|
||||
resource_ref = ((constant_ref | entity_ref | function_ref | procedure_ref | type_ref)).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="resource_ref"))("resource_ref")
|
||||
rule_head = ((RULE + rule_id + FOR + CaselessLiteral("(") + entity_ref + ZeroOrMore((CaselessLiteral(",") + entity_ref)) + CaselessLiteral(")") + CaselessLiteral(";"))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="rule_head"))("rule_head")
|
||||
select_list = ((CaselessLiteral("(") + named_types + ZeroOrMore((CaselessLiteral(",") + named_types)) + CaselessLiteral(")"))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="select_list"))("select_list")
|
||||
qualified_attribute = ((SELF + group_qualifier + attribute_qualifier)).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="qualified_attribute"))("qualified_attribute")
|
||||
redeclared_attribute = ((qualified_attribute + Optional((RENAMED + attribute_id)))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="redeclared_attribute"))("redeclared_attribute")
|
||||
referenced_attribute = ((attribute_ref | qualified_attribute)).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="referenced_attribute"))("referenced_attribute")
|
||||
rename_id = ((constant_id | entity_id | function_id | procedure_id | type_id)).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="rename_id"))("rename_id")
|
||||
resource_ref = ((constant_ref | entity_ref | function_ref | procedure_ref | type_ref)).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="resource_ref"))("resource_ref")
|
||||
rule_head = ((RULE + rule_id + FOR + CaselessLiteral("(") + entity_ref + ZeroOrMore((CaselessLiteral(",") + entity_ref)) + CaselessLiteral(")") + CaselessLiteral(";"))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="rule_head"))("rule_head")
|
||||
select_list = ((CaselessLiteral("(") + named_types + ZeroOrMore((CaselessLiteral(",") + named_types)) + CaselessLiteral(")"))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="select_list"))("select_list")
|
||||
string_literal = ((simple_string_literal | encoded_string_literal))("string_literal")
|
||||
subtype_constraint_head = ((SUBTYPE_CONSTRAINT + subtype_constraint_id + FOR + entity_ref + CaselessLiteral(";"))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="subtype_constraint_head"))("subtype_constraint_head")
|
||||
subtype_declaration = ((SUBTYPE + OF + CaselessLiteral("(") + entity_ref + ZeroOrMore((CaselessLiteral(",") + entity_ref)) + CaselessLiteral(")"))).setParseAction(SubTypeExpression)("subtype_declaration")
|
||||
total_over = ((TOTAL_OVER + CaselessLiteral("(") + entity_ref + ZeroOrMore((CaselessLiteral(",") + entity_ref)) + CaselessLiteral(")") + CaselessLiteral(";"))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="total_over"))("total_over")
|
||||
type_label = ((type_label_id | type_label_ref)).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="type_label"))("type_label")
|
||||
unique_rule = ((Optional((rule_label_id + CaselessLiteral(":"))) + referenced_attribute + ZeroOrMore((CaselessLiteral(",") + referenced_attribute)))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="unique_rule"))("unique_rule")
|
||||
use_clause = ((USE + FROM + schema_ref + Optional((CaselessLiteral("(") + named_type_or_rename + ZeroOrMore((CaselessLiteral(",") + named_type_or_rename)) + CaselessLiteral(")"))) + CaselessLiteral(";"))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="use_clause"))("use_clause")
|
||||
not_lparen_star = ((not_paren_star | CaselessLiteral(")"))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="not_lparen_star"))("not_lparen_star")
|
||||
remark_ref = ((attribute_ref | constant_ref | entity_ref | enumeration_ref | function_ref | parameter_ref | procedure_ref | rule_label_ref | rule_ref | schema_ref | subtype_constraint_ref | type_label_ref | type_ref | variable_ref)).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="remark_ref"))("remark_ref")
|
||||
attribute_decl = ((redeclared_attribute | attribute_id)).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="attribute_decl"))("attribute_decl")
|
||||
generic_entity_type = ((GENERIC_ENTITY + Optional((CaselessLiteral(":") + type_label)))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="generic_entity_type"))("generic_entity_type")
|
||||
generic_type = ((GENERIC + Optional((CaselessLiteral(":") + type_label)))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="generic_type"))("generic_type")
|
||||
literal = ((binary_literal | logical_literal | real_literal | string_literal)).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="literal"))("literal")
|
||||
resource_or_rename = ((resource_ref + Optional((AS + rename_id)))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="resource_or_rename"))("resource_or_rename")
|
||||
subtype_constraint_head = ((SUBTYPE_CONSTRAINT + subtype_constraint_id + FOR + entity_ref + CaselessLiteral(";"))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="subtype_constraint_head"))("subtype_constraint_head")
|
||||
subtype_declaration = ((SUBTYPE + OF + CaselessLiteral("(") + entity_ref + ZeroOrMore((CaselessLiteral(",") + entity_ref)) + CaselessLiteral(")"))).set_parse_action(SubTypeExpression)("subtype_declaration")
|
||||
total_over = ((TOTAL_OVER + CaselessLiteral("(") + entity_ref + ZeroOrMore((CaselessLiteral(",") + entity_ref)) + CaselessLiteral(")") + CaselessLiteral(";"))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="total_over"))("total_over")
|
||||
type_label = ((type_label_id | type_label_ref)).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="type_label"))("type_label")
|
||||
unique_rule = ((Optional((rule_label_id + CaselessLiteral(":"))) + referenced_attribute + ZeroOrMore((CaselessLiteral(",") + referenced_attribute)))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="unique_rule"))("unique_rule")
|
||||
use_clause = ((USE + FROM + schema_ref + Optional((CaselessLiteral("(") + named_type_or_rename + ZeroOrMore((CaselessLiteral(",") + named_type_or_rename)) + CaselessLiteral(")"))) + CaselessLiteral(";"))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="use_clause"))("use_clause")
|
||||
not_lparen_star = ((not_paren_star | CaselessLiteral(")"))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="not_lparen_star"))("not_lparen_star")
|
||||
remark_ref = ((attribute_ref | constant_ref | entity_ref | enumeration_ref | function_ref | parameter_ref | procedure_ref | rule_label_ref | rule_ref | schema_ref | subtype_constraint_ref | type_label_ref | type_ref | variable_ref)).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="remark_ref"))("remark_ref")
|
||||
attribute_decl = ((redeclared_attribute | attribute_id)).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="attribute_decl"))("attribute_decl")
|
||||
generic_entity_type = ((GENERIC_ENTITY + Optional((CaselessLiteral(":") + type_label)))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="generic_entity_type"))("generic_entity_type")
|
||||
generic_type = ((GENERIC + Optional((CaselessLiteral(":") + type_label)))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="generic_type"))("generic_type")
|
||||
literal = ((binary_literal | logical_literal | real_literal | string_literal)).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="literal"))("literal")
|
||||
resource_or_rename = ((resource_ref + Optional((AS + rename_id)))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="resource_or_rename"))("resource_or_rename")
|
||||
schema_version_id = (string_literal)("schema_version_id")
|
||||
select_extension = ((BASED_ON + type_ref + Optional((WITH + select_list)))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="select_extension"))("select_extension")
|
||||
select_type = ((Optional((EXTENSIBLE + Optional(GENERIC_ENTITY))) + SELECT + Optional((select_list | select_extension)))).setParseAction(SelectType)("select_type")
|
||||
unique_clause = ((UNIQUE + unique_rule + CaselessLiteral(";") + ZeroOrMore((unique_rule + CaselessLiteral(";"))))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="unique_clause"))("unique_clause")
|
||||
lparen_then_not_lparen_star = ((CaselessLiteral("(") + ZeroOrMore(CaselessLiteral("(")) + not_lparen_star + ZeroOrMore(not_lparen_star))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="lparen_then_not_lparen_star"))("lparen_then_not_lparen_star")
|
||||
remark_tag = ((CaselessLiteral("\"") + remark_ref + ZeroOrMore((CaselessLiteral(".") + remark_ref)) + CaselessLiteral("\""))).setParseAction(lambda s, loc, t: ListNode(s, loc, t, rule="remark_tag"))("remark_tag")
|
||||
tail_remark = ((CaselessLiteral("--") + Optional(remark_tag))).setParseAction(lambda s, loc, t: Node(s, loc, t, rule="tail_remark"))("tail_remark")
|
||||
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")
|
||||
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")
|
||||
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")
|
||||
interval_item = Forward()("interval_item")
|
||||
stmt = Forward()("stmt")
|
||||
repeat_control = Forward()("repeat_control")
|
||||
select_extension = ((BASED_ON + type_ref + Optional((WITH + select_list)))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="select_extension"))("select_extension")
|
||||
select_type = ((Optional((EXTENSIBLE + Optional(GENERIC_ENTITY))) + SELECT + Optional((select_list | select_extension)))).set_parse_action(SelectType)("select_type")
|
||||
unique_clause = ((UNIQUE + unique_rule + CaselessLiteral(";") + ZeroOrMore((unique_rule + CaselessLiteral(";"))))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="unique_clause"))("unique_clause")
|
||||
lparen_then_not_lparen_star = ((CaselessLiteral("(") + ZeroOrMore(CaselessLiteral("(")) + not_lparen_star + ZeroOrMore(not_lparen_star))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="lparen_then_not_lparen_star"))("lparen_then_not_lparen_star")
|
||||
remark_tag = ((CaselessLiteral("\"") + remark_ref + ZeroOrMore((CaselessLiteral(".") + remark_ref)) + CaselessLiteral("\""))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="remark_tag"))("remark_tag")
|
||||
tail_remark = ((CaselessLiteral("--") + Optional(remark_tag))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="tail_remark"))("tail_remark")
|
||||
constructed_types = ((enumeration_type | select_type)).set_parse_action(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(";"))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="reference_clause"))("reference_clause")
|
||||
interface_specification = ((reference_clause | use_clause)).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="interface_specification"))("interface_specification")
|
||||
abstract_supertype_declaration = Forward()("abstract_supertype_declaration")
|
||||
bound_spec = Forward()("bound_spec")
|
||||
entity_decl = Forward()("entity_decl")
|
||||
actual_parameter_list = Forward()("actual_parameter_list")
|
||||
aggregate_initializer = Forward()("aggregate_initializer")
|
||||
aggregate_source = Forward()("aggregate_source")
|
||||
aggregate_type = Forward()("aggregate_type")
|
||||
aggregation_types = Forward()("aggregation_types")
|
||||
algorithm_head = Forward()("algorithm_head")
|
||||
alias_stmt = Forward()("alias_stmt")
|
||||
array_type = Forward()("array_type")
|
||||
assignment_stmt = Forward()("assignment_stmt")
|
||||
bag_type = Forward()("bag_type")
|
||||
binary_type = Forward()("binary_type")
|
||||
bound_1 = Forward()("bound_1")
|
||||
bound_2 = Forward()("bound_2")
|
||||
bound_spec = Forward()("bound_spec")
|
||||
case_action = Forward()("case_action")
|
||||
case_label = Forward()("case_label")
|
||||
case_stmt = Forward()("case_stmt")
|
||||
compound_stmt = Forward()("compound_stmt")
|
||||
concrete_types = Forward()("concrete_types")
|
||||
constant_body = Forward()("constant_body")
|
||||
constant_decl = Forward()("constant_decl")
|
||||
declaration = Forward()("declaration")
|
||||
derive_clause = Forward()("derive_clause")
|
||||
derived_attr = Forward()("derived_attr")
|
||||
domain_rule = Forward()("domain_rule")
|
||||
element = Forward()("element")
|
||||
embedded_remark = Forward()("embedded_remark")
|
||||
entity_body = Forward()("entity_body")
|
||||
entity_constructor = Forward()("entity_constructor")
|
||||
entity_decl = Forward()("entity_decl")
|
||||
entity_head = Forward()("entity_head")
|
||||
explicit_attr = Forward()("explicit_attr")
|
||||
expression = Forward()("expression")
|
||||
factor = Forward()("factor")
|
||||
formal_parameter = Forward()("formal_parameter")
|
||||
function_call = Forward()("function_call")
|
||||
function_decl = Forward()("function_decl")
|
||||
function_head = Forward()("function_head")
|
||||
general_aggregation_types = Forward()("general_aggregation_types")
|
||||
general_array_type = Forward()("general_array_type")
|
||||
general_bag_type = Forward()("general_bag_type")
|
||||
general_list_type = Forward()("general_list_type")
|
||||
general_set_type = Forward()("general_set_type")
|
||||
generalized_types = Forward()("generalized_types")
|
||||
if_stmt = Forward()("if_stmt")
|
||||
increment = Forward()("increment")
|
||||
increment_control = Forward()("increment_control")
|
||||
index = Forward()("index")
|
||||
index_1 = Forward()("index_1")
|
||||
index_2 = Forward()("index_2")
|
||||
index_qualifier = Forward()("index_qualifier")
|
||||
instantiable_type = Forward()("instantiable_type")
|
||||
interval = Forward()("interval")
|
||||
interval_high = Forward()("interval_high")
|
||||
interval_item = Forward()("interval_item")
|
||||
interval_low = Forward()("interval_low")
|
||||
inverse_attr = Forward()("inverse_attr")
|
||||
inverse_clause = Forward()("inverse_clause")
|
||||
list_type = Forward()("list_type")
|
||||
local_decl = Forward()("local_decl")
|
||||
local_variable = Forward()("local_variable")
|
||||
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")
|
||||
parameter_type = Forward()("parameter_type")
|
||||
precision_spec = Forward()("precision_spec")
|
||||
primary = Forward()("primary")
|
||||
procedure_call_stmt = Forward()("procedure_call_stmt")
|
||||
procedure_decl = Forward()("procedure_decl")
|
||||
procedure_head = Forward()("procedure_head")
|
||||
qualifiable_factor = Forward()("qualifiable_factor")
|
||||
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"))
|
||||
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)
|
||||
query_expression = Forward()("query_expression")
|
||||
real_type = Forward()("real_type")
|
||||
remark = Forward()("remark")
|
||||
repeat_control = Forward()("repeat_control")
|
||||
repeat_stmt = Forward()("repeat_stmt")
|
||||
repetition = Forward()("repetition")
|
||||
return_stmt = Forward()("return_stmt")
|
||||
rule_decl = Forward()("rule_decl")
|
||||
schema_body = Forward()("schema_body")
|
||||
schema_decl = Forward()("schema_decl")
|
||||
selector = Forward()("selector")
|
||||
set_type = Forward()("set_type")
|
||||
simple_expression = Forward()("simple_expression")
|
||||
simple_factor = Forward()("simple_factor")
|
||||
simple_types = Forward()("simple_types")
|
||||
stmt = Forward()("stmt")
|
||||
string_type = Forward()("string_type")
|
||||
subsuper = Forward()("subsuper")
|
||||
subtype_constraint = Forward()("subtype_constraint")
|
||||
subtype_constraint_body = Forward()("subtype_constraint_body")
|
||||
subtype_constraint_decl = Forward()("subtype_constraint_decl")
|
||||
supertype_constraint = Forward()("supertype_constraint")
|
||||
supertype_expression = Forward()("supertype_expression")
|
||||
supertype_factor = Forward()("supertype_factor")
|
||||
supertype_rule = Forward()("supertype_rule")
|
||||
supertype_term = Forward()("supertype_term")
|
||||
syntax = Forward()("syntax")
|
||||
term = Forward()("term")
|
||||
type_decl = Forward()("type_decl")
|
||||
underlying_type = Forward()("underlying_type")
|
||||
until_control = Forward()("until_control")
|
||||
where_clause = Forward()("where_clause")
|
||||
while_control = Forward()("while_control")
|
||||
width = Forward()("width")
|
||||
width_spec = Forward()("width_spec")
|
||||
abstract_supertype_declaration << (((ABSTRACT + SUPERTYPE + Optional(subtype_constraint)))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="abstract_supertype_declaration"))
|
||||
actual_parameter_list << (((CaselessLiteral("(") + Optional(parameter) + ZeroOrMore((CaselessLiteral(",") + parameter)) + CaselessLiteral(")")))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="actual_parameter_list"))
|
||||
aggregate_initializer << (((CaselessLiteral("[") + Optional((element + ZeroOrMore((CaselessLiteral(",") + element)))) + CaselessLiteral("]")))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="aggregate_initializer"))
|
||||
aggregate_source << (simple_expression)
|
||||
aggregate_type << (((AGGREGATE + Optional((CaselessLiteral(":") + type_label)) + OF + parameter_type))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="aggregate_type"))
|
||||
aggregation_types << (((array_type | bag_type | list_type | set_type))).set_parse_action(AggregationType)
|
||||
algorithm_head << (((ZeroOrMore(declaration) + Optional(constant_decl) + Optional(local_decl)))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="algorithm_head"))
|
||||
alias_stmt << (((ALIAS + variable_id + FOR + general_ref + ZeroOrMore(qualifier) + CaselessLiteral(";") + stmt + ZeroOrMore(stmt) + END_ALIAS + CaselessLiteral(";")))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="alias_stmt"))
|
||||
array_type << (((ARRAY + bound_spec + OF + Optional(OPTIONAL) + Optional(UNIQUE) + instantiable_type))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="array_type"))
|
||||
assignment_stmt << (((general_ref + ZeroOrMore(qualifier) + CaselessLiteral(":=") + expression + CaselessLiteral(";")))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="assignment_stmt"))
|
||||
bag_type << (((BAG + Optional(bound_spec) + OF + instantiable_type))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="bag_type"))
|
||||
binary_type << (((BINARY + Optional(width_spec)))).set_parse_action(BinaryType)
|
||||
bound_1 << (numeric_expression)
|
||||
inverse_clause << (((INVERSE + inverse_attr + ZeroOrMore(inverse_attr)))).setParseAction(AttributeList)
|
||||
bound_2 << (numeric_expression)
|
||||
bound_spec << (((CaselessLiteral("[") + bound_1 + CaselessLiteral(":") + bound_2 + CaselessLiteral("]")))).set_parse_action(BoundSpecification)
|
||||
case_action << (((case_label + ZeroOrMore((CaselessLiteral(",") + case_label)) + CaselessLiteral(":") + stmt))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="case_action"))
|
||||
case_label << (expression)
|
||||
case_stmt << (((CASE + selector + OF + ZeroOrMore(case_action) + Optional((OTHERWISE + CaselessLiteral(":") + stmt)) + END_CASE + CaselessLiteral(";")))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="case_stmt"))
|
||||
compound_stmt << (((BEGIN + stmt + ZeroOrMore(stmt) + END + CaselessLiteral(";")))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="compound_stmt"))
|
||||
concrete_types << (((aggregation_types | simple_types | type_ref))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="concrete_types"))
|
||||
constant_body << (((constant_id + CaselessLiteral(":") + instantiable_type + CaselessLiteral(":=") + expression + CaselessLiteral(";")))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="constant_body"))
|
||||
constant_decl << (((CONSTANT + constant_body + ZeroOrMore(constant_body) + END_CONSTANT + CaselessLiteral(";")))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="constant_decl"))
|
||||
declaration << (((entity_decl | function_decl | procedure_decl | subtype_constraint_decl | type_decl))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="declaration"))
|
||||
derive_clause << (((DERIVE + derived_attr + ZeroOrMore(derived_attr)))).set_parse_action(AttributeList)
|
||||
derived_attr << (((attribute_decl + CaselessLiteral(":") + parameter_type + CaselessLiteral(":=") + expression + CaselessLiteral(";")))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="derived_attr"))
|
||||
domain_rule << (((Optional((rule_label_id + CaselessLiteral(":"))) + expression))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="domain_rule"))
|
||||
element << (((expression + Optional((CaselessLiteral(":") + repetition))))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="element"))
|
||||
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("*)")))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="embedded_remark"))
|
||||
entity_body << (((ZeroOrMore(explicit_attr) + Optional(derive_clause) + Optional(inverse_clause) + Optional(unique_clause) + Optional(where_clause)))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="entity_body"))
|
||||
entity_constructor << (((entity_ref + CaselessLiteral("(") + Optional((expression + ZeroOrMore((CaselessLiteral(",") + expression)))) + CaselessLiteral(")")))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="entity_constructor"))
|
||||
entity_decl << (((entity_head + entity_body + END_ENTITY + CaselessLiteral(";")))).set_parse_action(EntityDeclaration)
|
||||
entity_head << (((ENTITY + entity_id + subsuper + CaselessLiteral(";")))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="entity_head"))
|
||||
explicit_attr << (((attribute_decl + ZeroOrMore((CaselessLiteral(",") + attribute_decl)) + CaselessLiteral(":") + Optional(OPTIONAL) + parameter_type + CaselessLiteral(";")))).set_parse_action(ExplicitAttribute)
|
||||
expression << (((simple_expression + Optional((rel_op_extended + simple_expression))))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="expression"))
|
||||
factor << (((simple_factor + Optional((CaselessLiteral("**") + simple_factor))))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="factor"))
|
||||
formal_parameter << (((parameter_id + ZeroOrMore((CaselessLiteral(",") + parameter_id)) + CaselessLiteral(":") + parameter_type))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="formal_parameter"))
|
||||
function_call << ((((built_in_function | function_ref) + actual_parameter_list))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="function_call"))
|
||||
function_decl << (((function_head + algorithm_head + stmt + ZeroOrMore(stmt) + END_FUNCTION + CaselessLiteral(";")))).set_parse_action(FunctionDeclaration)
|
||||
function_head << (((FUNCTION + function_id + Optional((CaselessLiteral("(") + formal_parameter + ZeroOrMore((CaselessLiteral(";") + formal_parameter)) + CaselessLiteral(")"))) + CaselessLiteral(":") + parameter_type + CaselessLiteral(";")))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="function_head"))
|
||||
general_aggregation_types << (((general_array_type | general_bag_type | general_list_type | general_set_type))).set_parse_action(AggregationType)
|
||||
general_array_type << (((ARRAY + Optional(bound_spec) + OF + Optional(OPTIONAL) + Optional(UNIQUE) + parameter_type))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="general_array_type"))
|
||||
general_bag_type << (((BAG + Optional(bound_spec) + OF + parameter_type))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="general_bag_type"))
|
||||
general_list_type << (((LIST + Optional(bound_spec) + OF + Optional(UNIQUE) + parameter_type))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="general_list_type"))
|
||||
general_set_type << (((SET + Optional(bound_spec) + OF + parameter_type))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="general_set_type"))
|
||||
generalized_types << (((aggregate_type | general_aggregation_types | generic_entity_type | generic_type))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="generalized_types"))
|
||||
if_stmt << (((IF + logical_expression + THEN + stmt + ZeroOrMore(stmt) + Optional((ELSE + stmt + ZeroOrMore(stmt))) + END_IF + CaselessLiteral(";")))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="if_stmt"))
|
||||
increment << (numeric_expression)
|
||||
increment_control << (((variable_id + CaselessLiteral(":=") + bound_1 + TO + bound_2 + Optional((BY + increment))))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="increment_control"))
|
||||
index << (numeric_expression)
|
||||
index_1 << (index)
|
||||
index_2 << (index)
|
||||
index_qualifier << (((CaselessLiteral("[") + index_1 + Optional((CaselessLiteral(":") + index_2)) + CaselessLiteral("]")))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="index_qualifier"))
|
||||
instantiable_type << (((concrete_types | entity_ref))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="instantiable_type"))
|
||||
interval << (((CaselessLiteral("{") + interval_low + interval_op + interval_item + interval_op + interval_high + CaselessLiteral("}")))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="interval"))
|
||||
interval_high << (simple_expression)
|
||||
interval_item << (simple_expression)
|
||||
interval_low << (simple_expression)
|
||||
inverse_attr << (((attribute_decl + CaselessLiteral(":") + Optional(((SET | BAG) + Optional(bound_spec) + OF)) + entity_ref + FOR + Optional((entity_ref + CaselessLiteral("."))) + attribute_ref + CaselessLiteral(";")))).set_parse_action(InverseAttribute)
|
||||
inverse_clause << (((INVERSE + inverse_attr + ZeroOrMore(inverse_attr)))).set_parse_action(AttributeList)
|
||||
list_type << (((LIST + Optional(bound_spec) + OF + Optional(UNIQUE) + instantiable_type))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="list_type"))
|
||||
local_decl << (((LOCAL + local_variable + ZeroOrMore(local_variable) + END_LOCAL + CaselessLiteral(";")))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="local_decl"))
|
||||
local_variable << (((variable_id + ZeroOrMore((CaselessLiteral(",") + variable_id)) + CaselessLiteral(":") + parameter_type + Optional((CaselessLiteral(":=") + expression)) + CaselessLiteral(";")))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="local_variable"))
|
||||
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"))
|
||||
one_of << (((ONEOF + CaselessLiteral("(") + supertype_expression + ZeroOrMore((CaselessLiteral(",") + supertype_expression)) + CaselessLiteral(")")))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="one_of"))
|
||||
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"))
|
||||
parameter_type << (((generalized_types | simple_types | named_types))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="parameter_type"))
|
||||
precision_spec << (numeric_expression)
|
||||
primary << (((literal | (qualifiable_factor + ZeroOrMore(qualifier))))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="primary"))
|
||||
procedure_call_stmt << ((((built_in_procedure | procedure_ref) + actual_parameter_list + CaselessLiteral(";")))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="procedure_call_stmt"))
|
||||
procedure_decl << (((procedure_head + algorithm_head + ZeroOrMore(stmt) + END_PROCEDURE + CaselessLiteral(";")))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="procedure_decl"))
|
||||
procedure_head << (((PROCEDURE + procedure_id + Optional((CaselessLiteral("(") + Optional(VAR) + formal_parameter + ZeroOrMore((CaselessLiteral(";") + Optional(VAR) + formal_parameter)) + CaselessLiteral(")"))) + CaselessLiteral(";")))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="procedure_head"))
|
||||
qualifiable_factor << (((function_call | attribute_ref | constant_factor | general_ref | population))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="qualifiable_factor"))
|
||||
qualifier << (((attribute_qualifier | group_qualifier | index_qualifier))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="qualifier"))
|
||||
query_expression << (((QUERY + CaselessLiteral("(") + variable_id + CaselessLiteral("<*") + aggregate_source + CaselessLiteral("|") + logical_expression + CaselessLiteral(")")))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="query_expression"))
|
||||
real_type << (((REAL + Optional((CaselessLiteral("(") + precision_spec + CaselessLiteral(")")))))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="real_type"))
|
||||
remark << (((embedded_remark | tail_remark))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="remark"))
|
||||
repeat_control << (((Optional(increment_control) + Optional(while_control) + Optional(until_control)))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="repeat_control"))
|
||||
repeat_stmt << (((REPEAT + repeat_control + CaselessLiteral(";") + stmt + ZeroOrMore(stmt) + END_REPEAT + CaselessLiteral(";")))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="repeat_stmt"))
|
||||
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"))
|
||||
return_stmt << (((RETURN + Optional((CaselessLiteral("(") + expression + CaselessLiteral(")"))) + CaselessLiteral(";")))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="return_stmt"))
|
||||
rule_decl << (((rule_head + algorithm_head + ZeroOrMore(stmt) + where_clause + END_RULE + CaselessLiteral(";")))).set_parse_action(RuleDeclaration)
|
||||
schema_body << (((ZeroOrMore(interface_specification) + Optional(constant_decl) + ZeroOrMore((declaration | rule_decl))))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="schema_body"))
|
||||
schema_decl << (((SCHEMA + schema_id + Optional(schema_version_id) + CaselessLiteral(";") + schema_body + END_SCHEMA + CaselessLiteral(";")))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="schema_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"))
|
||||
set_type << (((SET + Optional(bound_spec) + OF + instantiable_type))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="set_type"))
|
||||
simple_expression << (((term + ZeroOrMore((add_like_op + term))))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="simple_expression"))
|
||||
simple_factor << (((aggregate_initializer | interval | query_expression | (Optional(unary_op) + ((CaselessLiteral("(") + expression + CaselessLiteral(")")) | primary)) | entity_constructor | enumeration_reference))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="simple_factor"))
|
||||
simple_types << (((binary_type | boolean_type | integer_type | logical_type | number_type | real_type | string_type))).set_parse_action(SimpleType)
|
||||
stmt << (((alias_stmt | assignment_stmt | case_stmt | compound_stmt | escape_stmt | if_stmt | null_stmt | procedure_call_stmt | repeat_stmt | return_stmt | skip_stmt))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="stmt"))
|
||||
string_type << (((STRING + Optional(width_spec)))).set_parse_action(StringType)
|
||||
subsuper << (((Optional(supertype_constraint) + Optional(subtype_declaration)))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="subsuper"))
|
||||
subtype_constraint << (((OF + CaselessLiteral("(") + supertype_expression + CaselessLiteral(")")))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="subtype_constraint"))
|
||||
subtype_constraint_body << (((Optional(abstract_supertype) + Optional(total_over) + Optional((supertype_expression + CaselessLiteral(";")))))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="subtype_constraint_body"))
|
||||
subtype_constraint_decl << (((subtype_constraint_head + subtype_constraint_body + END_SUBTYPE_CONSTRAINT + CaselessLiteral(";")))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="subtype_constraint_decl"))
|
||||
supertype_constraint << (((abstract_supertype_declaration | abstract_entity_declaration | supertype_rule))).set_parse_action(SuperTypeExpression)
|
||||
supertype_expression << (((supertype_factor + ZeroOrMore((ANDOR + supertype_factor))))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="supertype_expression"))
|
||||
supertype_factor << (((supertype_term + ZeroOrMore((AND + supertype_term))))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="supertype_factor"))
|
||||
supertype_rule << (((SUPERTYPE + subtype_constraint))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="supertype_rule"))
|
||||
supertype_term << (((one_of | (CaselessLiteral("(") + supertype_expression + CaselessLiteral(")")) | entity_ref))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="supertype_term"))
|
||||
syntax << (((schema_decl + ZeroOrMore(schema_decl)))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="syntax"))
|
||||
term << (((factor + ZeroOrMore((multiplication_like_op + factor))))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="term"))
|
||||
type_decl << (((TYPE + type_id + CaselessLiteral("=") + underlying_type + CaselessLiteral(";") + Optional(where_clause) + END_TYPE + CaselessLiteral(";")))).set_parse_action(TypeDeclaration)
|
||||
underlying_type << (((constructed_types | concrete_types))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="underlying_type"))
|
||||
until_control << (((UNTIL + logical_expression))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="until_control"))
|
||||
where_clause << (((WHERE + domain_rule + CaselessLiteral(";") + ZeroOrMore((domain_rule + CaselessLiteral(";")))))).set_parse_action(lambda s, loc, t: ListNode(s, loc, t, rule="where_clause"))
|
||||
while_control << (((WHILE + logical_expression))).set_parse_action(lambda s, loc, t: Node(s, loc, t, rule="while_control"))
|
||||
width << (numeric_expression)
|
||||
width_spec << (((CaselessLiteral("(") + width + CaselessLiteral(")") + Optional(FIXED)))).set_parse_action(WidthSpec)
|
||||
|
||||
syntax.ignore("--" + restOfLine)
|
||||
syntax.ignore(Regex(r"\((?:\*(?:[^*]*\*+)+?\))"))
|
||||
ast = syntax.parseFile(fn)
|
||||
ast = syntax.parse_file(fn)
|
||||
s = schema.Schema(ast)
|
||||
m = mapping.Mapping(s)
|
||||
|
||||
with open(cache_file, "wb") as f:
|
||||
pickle.dump(m, f, protocol=0)
|
||||
return m
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
m = parse(sys.argv[1])
|
||||
import importlib
|
||||
|
||||
@@ -11,16 +11,16 @@ ENTITY file_name;
|
||||
time_stamp : time_stamp_text;
|
||||
author : LIST [1:?] OF STRING (256);
|
||||
organization : LIST [1:?] OF STRING (256);
|
||||
preprocessor_version : STRING (256);
|
||||
preprocessor_version : STRING (256);
|
||||
originating_system : STRING (256);
|
||||
authorisation : STRING (256);
|
||||
authorisation : STRING (256);
|
||||
END_ENTITY;
|
||||
|
||||
ENTITY file_description;
|
||||
description : LIST [1:?] OF STRING (256);
|
||||
implementation_level : STRING (256);
|
||||
END_ENTITY;
|
||||
|
||||
|
||||
ENTITY file_schema;
|
||||
schema_identifiers : LIST [1:?] OF UNIQUE schema_name;
|
||||
END_ENTITY;
|
||||
|
||||
@@ -263,7 +263,7 @@ context_class = context
|
||||
|
||||
class codegen_rule:
|
||||
def __init__(self, pattern, fn):
|
||||
self.pattern = tuple(rule.parseString(pattern))
|
||||
self.pattern = tuple(rule.parse_string(pattern))
|
||||
self.fn = fn
|
||||
if not hasattr(codegen_rule, "all_rules"):
|
||||
codegen_rule.all_rules = []
|
||||
@@ -292,7 +292,7 @@ def process_rule_decl(context):
|
||||
class {context.rule_head.rule_id}:
|
||||
SCOPE = "file"
|
||||
|
||||
@staticmethod
|
||||
@staticmethod
|
||||
def __call__(file):
|
||||
{context.rule_head.entity_ref} = file.by_type("{context.rule_head.entity_ref}")
|
||||
{indent(8, context.algorithm_head.local_decl)}
|
||||
@@ -335,7 +335,7 @@ class {class_name}_{domain_rule.rule_label_id}:
|
||||
TYPE_NAME = "{class_name}"
|
||||
RULE_NAME = "{domain_rule.rule_label_id}"
|
||||
|
||||
@staticmethod
|
||||
@staticmethod
|
||||
def __call__(self):
|
||||
{indent(8, (f"{a.lower()} = self.{a}" for a in attributes if re.search(f'{wb}{a.lower()}{wb}', str(domain_rule))))}
|
||||
{indent(8, domain_rule)}
|
||||
@@ -741,7 +741,7 @@ class AttributeGetattrTransformer(ast.NodeTransformer):
|
||||
func=ast.Name(id="express_getattr", ctx=ast.Load()),
|
||||
args=[
|
||||
new_value,
|
||||
ast.Str(s=node.attr),
|
||||
ast.Constant(value=node.attr),
|
||||
ast.Name(id="INDETERMINATE", ctx=ast.Load()),
|
||||
],
|
||||
keywords=[],
|
||||
|
||||
@@ -44,10 +44,10 @@ unknown = 'UNKNOWN'
|
||||
def usedin(inst, ref_name):
|
||||
if inst is None:
|
||||
return []
|
||||
(_, __, attr) = ref_name.split('.')
|
||||
_, __, attr = ref_name.split('.')
|
||||
|
||||
def filter():
|
||||
for (ref, attr_idx) in inst.wrapped_data.file.get_inverse(inst, allow_duplicate=True, with_attribute_indices=True):
|
||||
for ref, attr_idx in inst.wrapped_data.file.get_inverse(inst, allow_duplicate=True, with_attribute_indices=True):
|
||||
if ref.wrapped_data.get_attribute_names()[attr_idx].lower() == attr:
|
||||
yield ref
|
||||
return list(filter())
|
||||
@@ -4618,7 +4618,7 @@ class IfcConstructionMaterialResource_WR2:
|
||||
|
||||
@staticmethod
|
||||
def __call__(self):
|
||||
assert (not exists(lambda : express_getitem(express_getattr(self, 'ResourceOf', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or express_getattr(express_getitem(express_getattr(self, 'ResourceOf', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE), 'RelatedObjectsType', INDETERMINATE) == express_getattr(IfcObjectTypeEnum, 'PRODUCT', INDETERMINATE)) is not False
|
||||
assert (not exists(lambda: express_getitem(express_getattr(self, 'ResourceOf', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or express_getattr(express_getitem(express_getattr(self, 'ResourceOf', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE), 'RelatedObjectsType', INDETERMINATE) == express_getattr(IfcObjectTypeEnum, 'PRODUCT', INDETERMINATE)) is not False
|
||||
|
||||
class IfcConstructionProductResource_WR1:
|
||||
SCOPE = 'entity'
|
||||
@@ -4636,7 +4636,7 @@ class IfcConstructionProductResource_WR2:
|
||||
|
||||
@staticmethod
|
||||
def __call__(self):
|
||||
assert (not exists(lambda : express_getitem(express_getattr(self, 'ResourceOf', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or express_getattr(express_getitem(express_getattr(self, 'ResourceOf', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE), 'RelatedObjectsType', INDETERMINATE) == express_getattr(IfcObjectTypeEnum, 'PRODUCT', INDETERMINATE)) is not False
|
||||
assert (not exists(lambda: express_getitem(express_getattr(self, 'ResourceOf', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or express_getattr(express_getitem(express_getattr(self, 'ResourceOf', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE), 'RelatedObjectsType', INDETERMINATE) == express_getattr(IfcObjectTypeEnum, 'PRODUCT', INDETERMINATE)) is not False
|
||||
|
||||
class IfcCooledBeamType_WR1:
|
||||
SCOPE = 'entity'
|
||||
@@ -4876,7 +4876,7 @@ class IfcDocumentReference_WR1:
|
||||
def __call__(self):
|
||||
name = express_getattr(self, 'Name', INDETERMINATE)
|
||||
referencetodocument = express_getattr(self, 'ReferenceToDocument', INDETERMINATE)
|
||||
assert exists(name) ^ exists(lambda : express_getitem(referencetodocument, 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) is not False
|
||||
assert exists(name) ^ exists(lambda: express_getitem(referencetodocument, 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) is not False
|
||||
|
||||
class IfcDoorLiningProperties_WR31:
|
||||
SCOPE = 'entity'
|
||||
@@ -4929,7 +4929,7 @@ class IfcDoorLiningProperties_WR35:
|
||||
|
||||
@staticmethod
|
||||
def __call__(self):
|
||||
assert (exists(lambda : express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and 'ifc2x3.ifcdoorstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE))) is not False
|
||||
assert (exists(lambda: express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and 'ifc2x3.ifcdoorstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE))) is not False
|
||||
|
||||
class IfcDoorPanelProperties_WR31:
|
||||
SCOPE = 'entity'
|
||||
@@ -4938,7 +4938,7 @@ class IfcDoorPanelProperties_WR31:
|
||||
|
||||
@staticmethod
|
||||
def __call__(self):
|
||||
assert (exists(lambda : express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and 'ifc2x3.ifcdoorstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE))) is not False
|
||||
assert (exists(lambda: express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and 'ifc2x3.ifcdoorstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE))) is not False
|
||||
|
||||
class IfcDraughtingPreDefinedColour_WR31:
|
||||
SCOPE = 'entity'
|
||||
@@ -7195,7 +7195,7 @@ class IfcTypeProduct_WR41:
|
||||
|
||||
@staticmethod
|
||||
def __call__(self):
|
||||
assert (not exists(lambda : express_getitem(express_getattr(self, 'ObjectTypeOf', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or sizeof([temp for temp in express_getattr(express_getitem(express_getattr(self, 'ObjectTypeOf', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE), 'RelatedObjects', INDETERMINATE) if not 'ifc2x3.ifcproduct' in typeof(temp)]) == 0) is not False
|
||||
assert (not exists(lambda: express_getitem(express_getattr(self, 'ObjectTypeOf', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or sizeof([temp for temp in express_getattr(express_getitem(express_getattr(self, 'ObjectTypeOf', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE), 'RelatedObjects', INDETERMINATE) if not 'ifc2x3.ifcproduct' in typeof(temp)]) == 0) is not False
|
||||
|
||||
class IfcUShapeProfileDef_WR21:
|
||||
SCOPE = 'entity'
|
||||
@@ -7331,7 +7331,7 @@ class IfcWindowLiningProperties_WR34:
|
||||
|
||||
@staticmethod
|
||||
def __call__(self):
|
||||
assert (exists(lambda : express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and 'ifc2x3.ifcwindowstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE))) is not False
|
||||
assert (exists(lambda: express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and 'ifc2x3.ifcwindowstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE))) is not False
|
||||
|
||||
class IfcWorkControl_WR1:
|
||||
SCOPE = 'entity'
|
||||
|
||||
@@ -44,10 +44,10 @@ unknown = 'UNKNOWN'
|
||||
def usedin(inst, ref_name):
|
||||
if inst is None:
|
||||
return []
|
||||
(_, __, attr) = ref_name.split('.')
|
||||
_, __, attr = ref_name.split('.')
|
||||
|
||||
def filter():
|
||||
for (ref, attr_idx) in inst.wrapped_data.file.get_inverse(inst, allow_duplicate=True, with_attribute_indices=True):
|
||||
for ref, attr_idx in inst.wrapped_data.file.get_inverse(inst, allow_duplicate=True, with_attribute_indices=True):
|
||||
if ref.wrapped_data.get_attribute_names()[attr_idx].lower() == attr:
|
||||
yield ref
|
||||
return list(filter())
|
||||
@@ -6565,7 +6565,7 @@ class IfcDoorLiningProperties_WR35:
|
||||
|
||||
@staticmethod
|
||||
def __call__(self):
|
||||
assert (exists(lambda : express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and ('ifc4.ifcdoortype' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or 'ifc4.ifcdoorstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)))) is not False
|
||||
assert (exists(lambda: express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and ('ifc4.ifcdoortype' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or 'ifc4.ifcdoorstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)))) is not False
|
||||
|
||||
class IfcDoorPanelProperties_ApplicableToType:
|
||||
SCOPE = 'entity'
|
||||
@@ -6574,7 +6574,7 @@ class IfcDoorPanelProperties_ApplicableToType:
|
||||
|
||||
@staticmethod
|
||||
def __call__(self):
|
||||
assert (exists(lambda : express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and ('ifc4.ifcdoortype' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or 'ifc4.ifcdoorstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)))) is not False
|
||||
assert (exists(lambda: express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and ('ifc4.ifcdoortype' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or 'ifc4.ifcdoorstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)))) is not False
|
||||
|
||||
class IfcDoorType_CorrectPredefinedType:
|
||||
SCOPE = 'entity'
|
||||
@@ -10952,7 +10952,7 @@ class IfcTypeProduct_ApplicableOccurrence:
|
||||
|
||||
@staticmethod
|
||||
def __call__(self):
|
||||
assert (not exists(lambda : express_getitem(express_getattr(self, 'Types', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or sizeof([temp for temp in express_getattr(express_getitem(express_getattr(self, 'Types', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE), 'RelatedObjects', INDETERMINATE) if not 'ifc4.ifcproduct' in typeof(temp)]) == 0) is not False
|
||||
assert (not exists(lambda: express_getitem(express_getattr(self, 'Types', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or sizeof([temp for temp in express_getattr(express_getitem(express_getattr(self, 'Types', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE), 'RelatedObjects', INDETERMINATE) if not 'ifc4.ifcproduct' in typeof(temp)]) == 0) is not False
|
||||
|
||||
class IfcUShapeProfileDef_ValidFlangeThickness:
|
||||
SCOPE = 'entity'
|
||||
@@ -11258,7 +11258,7 @@ class IfcWindowLiningProperties_WR34:
|
||||
|
||||
@staticmethod
|
||||
def __call__(self):
|
||||
assert (exists(lambda : express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and ('ifc4.ifcwindowtype' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or 'ifc4.ifcwindowstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)))) is not False
|
||||
assert (exists(lambda: express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and ('ifc4.ifcwindowtype' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or 'ifc4.ifcwindowstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)))) is not False
|
||||
|
||||
class IfcWindowPanelProperties_ApplicableToType:
|
||||
SCOPE = 'entity'
|
||||
@@ -11267,7 +11267,7 @@ class IfcWindowPanelProperties_ApplicableToType:
|
||||
|
||||
@staticmethod
|
||||
def __call__(self):
|
||||
assert (exists(lambda : express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and ('ifc4.ifcwindowtype' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or 'ifc4.ifcwindowstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)))) is not False
|
||||
assert (exists(lambda: express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and ('ifc4.ifcwindowtype' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or 'ifc4.ifcwindowstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)))) is not False
|
||||
|
||||
class IfcWindowType_CorrectPredefinedType:
|
||||
SCOPE = 'entity'
|
||||
|
||||
@@ -44,10 +44,10 @@ unknown = 'UNKNOWN'
|
||||
def usedin(inst, ref_name):
|
||||
if inst is None:
|
||||
return []
|
||||
(_, __, attr) = ref_name.split('.')
|
||||
_, __, attr = ref_name.split('.')
|
||||
|
||||
def filter():
|
||||
for (ref, attr_idx) in inst.wrapped_data.file.get_inverse(inst, allow_duplicate=True, with_attribute_indices=True):
|
||||
for ref, attr_idx in inst.wrapped_data.file.get_inverse(inst, allow_duplicate=True, with_attribute_indices=True):
|
||||
if ref.wrapped_data.get_attribute_names()[attr_idx].lower() == attr:
|
||||
yield ref
|
||||
return list(filter())
|
||||
@@ -6656,7 +6656,7 @@ class IfcDoorLiningProperties_WR35:
|
||||
|
||||
@staticmethod
|
||||
def __call__(self):
|
||||
assert (exists(lambda : express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and ('ifc4x1.ifcdoortype' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or 'ifc4x1.ifcdoorstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)))) is not False
|
||||
assert (exists(lambda: express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and ('ifc4x1.ifcdoortype' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or 'ifc4x1.ifcdoorstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)))) is not False
|
||||
|
||||
class IfcDoorPanelProperties_ApplicableToType:
|
||||
SCOPE = 'entity'
|
||||
@@ -6665,7 +6665,7 @@ class IfcDoorPanelProperties_ApplicableToType:
|
||||
|
||||
@staticmethod
|
||||
def __call__(self):
|
||||
assert (exists(lambda : express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and ('ifc4x1.ifcdoortype' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or 'ifc4x1.ifcdoorstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)))) is not False
|
||||
assert (exists(lambda: express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and ('ifc4x1.ifcdoortype' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or 'ifc4x1.ifcdoorstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)))) is not False
|
||||
|
||||
class IfcDoorType_CorrectPredefinedType:
|
||||
SCOPE = 'entity'
|
||||
@@ -11103,7 +11103,7 @@ class IfcTypeProduct_ApplicableOccurrence:
|
||||
|
||||
@staticmethod
|
||||
def __call__(self):
|
||||
assert (not exists(lambda : express_getitem(express_getattr(self, 'Types', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or sizeof([temp for temp in express_getattr(express_getitem(express_getattr(self, 'Types', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE), 'RelatedObjects', INDETERMINATE) if not 'ifc4x1.ifcproduct' in typeof(temp)]) == 0) is not False
|
||||
assert (not exists(lambda: express_getitem(express_getattr(self, 'Types', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or sizeof([temp for temp in express_getattr(express_getitem(express_getattr(self, 'Types', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE), 'RelatedObjects', INDETERMINATE) if not 'ifc4x1.ifcproduct' in typeof(temp)]) == 0) is not False
|
||||
|
||||
class IfcUShapeProfileDef_ValidFlangeThickness:
|
||||
SCOPE = 'entity'
|
||||
@@ -11409,7 +11409,7 @@ class IfcWindowLiningProperties_WR34:
|
||||
|
||||
@staticmethod
|
||||
def __call__(self):
|
||||
assert (exists(lambda : express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and ('ifc4x1.ifcwindowtype' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or 'ifc4x1.ifcwindowstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)))) is not False
|
||||
assert (exists(lambda: express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and ('ifc4x1.ifcwindowtype' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or 'ifc4x1.ifcwindowstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)))) is not False
|
||||
|
||||
class IfcWindowPanelProperties_ApplicableToType:
|
||||
SCOPE = 'entity'
|
||||
@@ -11418,7 +11418,7 @@ class IfcWindowPanelProperties_ApplicableToType:
|
||||
|
||||
@staticmethod
|
||||
def __call__(self):
|
||||
assert (exists(lambda : express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and ('ifc4x1.ifcwindowtype' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or 'ifc4x1.ifcwindowstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)))) is not False
|
||||
assert (exists(lambda: express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and ('ifc4x1.ifcwindowtype' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or 'ifc4x1.ifcwindowstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)))) is not False
|
||||
|
||||
class IfcWindowType_CorrectPredefinedType:
|
||||
SCOPE = 'entity'
|
||||
|
||||
@@ -44,10 +44,10 @@ unknown = 'UNKNOWN'
|
||||
def usedin(inst, ref_name):
|
||||
if inst is None:
|
||||
return []
|
||||
(_, __, attr) = ref_name.split('.')
|
||||
_, __, attr = ref_name.split('.')
|
||||
|
||||
def filter():
|
||||
for (ref, attr_idx) in inst.wrapped_data.file.get_inverse(inst, allow_duplicate=True, with_attribute_indices=True):
|
||||
for ref, attr_idx in inst.wrapped_data.file.get_inverse(inst, allow_duplicate=True, with_attribute_indices=True):
|
||||
if ref.wrapped_data.get_attribute_names()[attr_idx].lower() == attr:
|
||||
yield ref
|
||||
return list(filter())
|
||||
@@ -6877,7 +6877,7 @@ class IfcDoorLiningProperties_WR35:
|
||||
|
||||
@staticmethod
|
||||
def __call__(self):
|
||||
assert (exists(lambda : express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and ('ifc4x2.ifcdoortype' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or 'ifc4x2.ifcdoorstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)))) is not False
|
||||
assert (exists(lambda: express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and ('ifc4x2.ifcdoortype' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or 'ifc4x2.ifcdoorstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)))) is not False
|
||||
|
||||
class IfcDoorPanelProperties_ApplicableToType:
|
||||
SCOPE = 'entity'
|
||||
@@ -6886,7 +6886,7 @@ class IfcDoorPanelProperties_ApplicableToType:
|
||||
|
||||
@staticmethod
|
||||
def __call__(self):
|
||||
assert (exists(lambda : express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and ('ifc4x2.ifcdoortype' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or 'ifc4x2.ifcdoorstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)))) is not False
|
||||
assert (exists(lambda: express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and ('ifc4x2.ifcdoortype' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or 'ifc4x2.ifcdoorstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)))) is not False
|
||||
|
||||
class IfcDoorType_CorrectPredefinedType:
|
||||
SCOPE = 'entity'
|
||||
@@ -11365,7 +11365,7 @@ class IfcTypeProduct_ApplicableOccurrence:
|
||||
|
||||
@staticmethod
|
||||
def __call__(self):
|
||||
assert (not exists(lambda : express_getitem(express_getattr(self, 'Types', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or sizeof([temp for temp in express_getattr(express_getitem(express_getattr(self, 'Types', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE), 'RelatedObjects', INDETERMINATE) if not 'ifc4x2.ifcproduct' in typeof(temp)]) == 0) is not False
|
||||
assert (not exists(lambda: express_getitem(express_getattr(self, 'Types', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or sizeof([temp for temp in express_getattr(express_getitem(express_getattr(self, 'Types', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE), 'RelatedObjects', INDETERMINATE) if not 'ifc4x2.ifcproduct' in typeof(temp)]) == 0) is not False
|
||||
|
||||
class IfcUShapeProfileDef_ValidFlangeThickness:
|
||||
SCOPE = 'entity'
|
||||
@@ -11701,7 +11701,7 @@ class IfcWindowLiningProperties_WR34:
|
||||
|
||||
@staticmethod
|
||||
def __call__(self):
|
||||
assert (exists(lambda : express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and ('ifc4x2.ifcwindowtype' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or 'ifc4x2.ifcwindowstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)))) is not False
|
||||
assert (exists(lambda: express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and ('ifc4x2.ifcwindowtype' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or 'ifc4x2.ifcwindowstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)))) is not False
|
||||
|
||||
class IfcWindowPanelProperties_ApplicableToType:
|
||||
SCOPE = 'entity'
|
||||
@@ -11710,7 +11710,7 @@ class IfcWindowPanelProperties_ApplicableToType:
|
||||
|
||||
@staticmethod
|
||||
def __call__(self):
|
||||
assert (exists(lambda : express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and ('ifc4x2.ifcwindowtype' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or 'ifc4x2.ifcwindowstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)))) is not False
|
||||
assert (exists(lambda: express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) and ('ifc4x2.ifcwindowtype' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)) or 'ifc4x2.ifcwindowstyle' in typeof(express_getitem(express_getattr(self, 'DefinesType', INDETERMINATE), 1 - EXPRESS_ONE_BASED_INDEXING, INDETERMINATE)))) is not False
|
||||
|
||||
class IfcWindowType_CorrectPredefinedType:
|
||||
SCOPE = 'entity'
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user