expressir 2.4.3 → 2.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.cargo/config.toml +3 -0
- data/.github/workflows/rust-ext.yml +41 -0
- data/.github/workflows/verify_remarks.yml +33 -0
- data/.gitignore +6 -0
- data/.rubocop.yml +4 -0
- data/.rubocop_todo.yml +1 -0
- data/Cargo.toml +7 -0
- data/README.adoc +65 -0
- data/Rakefile +12 -0
- data/TODO.parity-ee/00-overview.md +58 -0
- data/TODO.parity-ee/01-annex-g-rule-extraction.md +41 -0
- data/TODO.parity-ee/02-eeng-algorithm-inventory.md +8 -0
- data/TODO.parity-ee/03-eeng-oracle-harness.md +33 -0
- data/TODO.parity-ee/04-shtolo-concatenate.md +44 -0
- data/TODO.parity-ee/05-shtolo-longform-flatten.md +53 -0
- data/TODO.parity-ee/06-interface-scheduling-parity.md +47 -0
- data/TODO.parity-ee/07-semantic-checks-port.md +35 -0
- data/TODO.parity-ee/08-pretty-roundtrip-gate.md +27 -0
- data/TODO.parity-ee/09-smrl-index-and-listing.md +22 -0
- data/TODO.parity-ee/10-interface-dot-graph.md +21 -0
- data/TODO.parity-ee/11-import-eeng-tests.md +79 -0
- data/TODO.parity-ee/parity-matrix.md +108 -0
- data/exe/expressir +6 -0
- data/ext/expressir_core/Cargo.toml +24 -0
- data/ext/expressir_core/extconf.rb +30 -0
- data/ext/expressir_core/src/lib.rs +446 -0
- data/lib/expressir/cli.rb +49 -4
- data/lib/expressir/commands/check.rb +56 -0
- data/lib/expressir/commands/expand.rb +26 -0
- data/lib/expressir/commands/fix.rb +33 -0
- data/lib/expressir/commands/flatten.rb +29 -0
- data/lib/expressir/commands/parity_inputs.rb +85 -0
- data/lib/expressir/commands/validate.rb +22 -0
- data/lib/expressir/commands.rb +5 -0
- data/lib/expressir/express/builder_registry.rb +11 -2
- data/lib/expressir/express/builders/entity_decl_builder.rb +17 -7
- data/lib/expressir/express/builders/subtype_constraint_builder.rb +3 -1
- data/lib/expressir/express/builders/type_builder.rb +8 -0
- data/lib/expressir/express/builders/unique_rule_builder.rb +8 -1
- data/lib/expressir/express/checker.rb +458 -0
- data/lib/expressir/express/concatenator.rb +79 -0
- data/lib/expressir/express/core.rb +66 -0
- data/lib/expressir/express/formatter.rb +25 -3
- data/lib/expressir/express/formatters/data_types_formatter.rb +2 -2
- data/lib/expressir/express/formatters/declarations_formatter.rb +1 -0
- data/lib/expressir/express/formatters/remark_formatter.rb +30 -6
- data/lib/expressir/express/formatters/statements_formatter.rb +7 -1
- data/lib/expressir/express/interface_dot.rb +105 -0
- data/lib/expressir/express/listing.rb +174 -0
- data/lib/expressir/express/model_traversal.rb +42 -0
- data/lib/expressir/express/node_position_index.rb +18 -4
- data/lib/expressir/express/parser.rb +242 -4
- data/lib/expressir/express/pretty_gate.rb +61 -0
- data/lib/expressir/express/refs_overlay.rb +47 -0
- data/lib/expressir/express/remark_attacher.rb +122 -10
- data/lib/expressir/express/remark_overlay.rb +86 -0
- data/lib/expressir/express/schema_plain_source_formatter.rb +11 -0
- data/lib/expressir/express/schema_source_formatter.rb +5 -5
- data/lib/expressir/express/self_schema_reference.rb +126 -0
- data/lib/expressir/express/shtolo.rb +522 -0
- data/lib/expressir/express.rb +13 -0
- data/lib/expressir/model/concerns.rb +15 -1
- data/lib/expressir/model/declarations/entity.rb +6 -1
- data/lib/expressir/model/declarations/interface.rb +13 -0
- data/lib/expressir/model/declarations/schema.rb +74 -23
- data/lib/expressir/model/indexes/item_graph.rb +135 -0
- data/lib/expressir/model/indexes.rb +1 -0
- data/lib/expressir/model/model_element.rb +30 -1
- data/lib/expressir/model/remark_info.rb +20 -1
- data/lib/expressir/model/remark_placement.rb +15 -2
- data/lib/expressir/model/repository.rb +8 -2
- data/lib/expressir/model.rb +2 -1
- data/lib/expressir/version.rb +1 -1
- data/lib/tasks/verify_remarks.rake +9 -0
- data/rakelib/verify_remarks.rake +16 -0
- metadata +42 -2
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# 11 — Import the Express Engine test suite
|
|
2
|
+
|
|
3
|
+
**Status: NOT STARTED**
|
|
4
|
+
|
|
5
|
+
## Goal
|
|
6
|
+
|
|
7
|
+
Fully import eeng's tests — their release-suite scripts, the bug
|
|
8
|
+
corpus, and the reference documents that define pass/fail — as
|
|
9
|
+
executable RSpec feature specs and regression fixtures in expressir.
|
|
10
|
+
Nothing in their suite should remain unrepresented.
|
|
11
|
+
|
|
12
|
+
## Inventory (verified 2026-09-21)
|
|
13
|
+
|
|
14
|
+
eeng has no formal test framework (`tests/` is a README describing an
|
|
15
|
+
unrealized Makefile suite); the suite is:
|
|
16
|
+
|
|
17
|
+
### CLI drivers — `scripts/*.sh` (14)
|
|
18
|
+
|
|
19
|
+
| script | drives | our target operation |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| `qual-arm.sh`, `qual-mod.sh` | per-module qualification loop (arm/mim × every qualify.sh op) | 04, 05, 07-10 end-to-end specs |
|
|
22
|
+
| `qual-res.sh` | same over `qualify-res.txt` resources | idem, resource side |
|
|
23
|
+
| `pretty-test.sh` | `--pretty` ap209/ap210/ap242 × {arm,mim} × {shortform,longform} | 08 formatter specs |
|
|
24
|
+
| `ap210.sh` | the 2.5MB long-form giant, pretty × 4 modes | 08 scale spec |
|
|
25
|
+
| `test-tt.sh`, `test-tt1.sh` | `--xml` arm/mim shortform + Saxon HTM conversion + regenerate-exp compare | 09 (XML chain) |
|
|
26
|
+
| `build-xml.sh` | XML builds over the whole `modules.lst` + `resources.lst` | 09 corpus spec |
|
|
27
|
+
| `test.sh` | ad-hoc resource XML/HTM driver (kinematic schema) | 09 |
|
|
28
|
+
| `scan-res.lisp` | resource corpus scan | 07 check corpus |
|
|
29
|
+
| `kevin.sh`, `veronique.sh`, `copy-mod-xml.sh` | person-named scratch drivers | triage: keep as scenarios or drop with rationale |
|
|
30
|
+
|
|
31
|
+
Each script's eeng CLI matrix (`-mode {arm,mim}_{shortform,longform,
|
|
32
|
+
concatenated}` `-stepmod` `-schema` `--pretty/--xml/--flat/--dot
|
|
33
|
+
--check`) maps 1:1 onto our planned operations — the flag matrix
|
|
34
|
+
becomes our spec matrix.
|
|
35
|
+
|
|
36
|
+
### Bug corpus — `docs/issues/`
|
|
37
|
+
|
|
38
|
+
- `bug39-Greedy-Parens.txt` — **shtolo fixture**: contains "results
|
|
39
|
+
of old shtolo and stepcode exppp" vs "results of new shtolo"
|
|
40
|
+
outputs; doubles as a differential vs stepcode exppp.
|
|
41
|
+
- `bug40-Pretty-Expressions.txt` — pretty-printer expression cases.
|
|
42
|
+
Both become regression specs with the literal inputs embedded.
|
|
43
|
+
|
|
44
|
+
### Reference documents — `docs/` (define pass/fail)
|
|
45
|
+
|
|
46
|
+
- `shtolo_converting_STEP_short_listings_to_annotated_listings_libes.pdf`
|
|
47
|
+
— the SHTOLO paper (short listings → annotated listings); required
|
|
48
|
+
reading for 01/05 semantics.
|
|
49
|
+
- BNF grammars: `iso-10303-11--2004{,-raw}.bnf`, `iso-10303-14*.bnf`,
|
|
50
|
+
**`iso-10303-21--{1994,2002}.bnf`** (Part 21!), `xml.bnf`,
|
|
51
|
+
`patch_schema.bnf` — grammar cross-checks (05's 1994 profile; the
|
|
52
|
+
Part 21 BNFs feed the future p21 parser).
|
|
53
|
+
- `express_model.dtd`, `module.dtd` — the DTDs their XML emits (09's
|
|
54
|
+
structural contract).
|
|
55
|
+
- `qualify.txt`, `interfaces.txt`, `interface-notes.pdf` —
|
|
56
|
+
qualification + interface semantics notes.
|
|
57
|
+
- `00check.txt` (repo root) — check.lisp design notes → 07.
|
|
58
|
+
|
|
59
|
+
## Steps
|
|
60
|
+
|
|
61
|
+
1. Copy the durable assets into the repo: scripts verbatim under
|
|
62
|
+
`spec/fixtures/eeng/scripts/` (provenance header), bug corpus under
|
|
63
|
+
`spec/fixtures/eeng/issues/`, DTDs + BNFs under
|
|
64
|
+
`spec/fixtures/eeng/grammar/` (license is MIT-style per eeng
|
|
65
|
+
headers — verify and record attribution).
|
|
66
|
+
2. Translate the CLI matrix into RSpec feature specs
|
|
67
|
+
(`spec/expressir/eeng_parity/`): one describe per driver family,
|
|
68
|
+
one example per (schema × mode × operation), corpus-scaled ones
|
|
69
|
+
tagged `smrl`.
|
|
70
|
+
3. Port bug39/bug40 as literal regression specs now (they need only
|
|
71
|
+
parser + formatter, both of which exist).
|
|
72
|
+
4. Extend 03's oracle harness to emit/refresh the expected outputs
|
|
73
|
+
these specs consume.
|
|
74
|
+
|
|
75
|
+
## Acceptance
|
|
76
|
+
|
|
77
|
+
Every driver row and both bugs have a corresponding spec (or a
|
|
78
|
+
documented drop rationale); `smrl`-tagged parity suite green against
|
|
79
|
+
the 03 golden corpus.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# eeng ↔ expressir parity matrix (2026-09-21)
|
|
2
|
+
|
|
3
|
+
Reference: `~/src/external/exp-engine-engine` (eengine-5.0.20-Beta1).
|
|
4
|
+
Audited files: kernel/{find-declaration,find-entity,find-type,
|
|
5
|
+
resolve-interface,resolve-object,resolve-ref,references,schema-search,
|
|
6
|
+
interfaces,compute-inheritance,supertypes,derive-attrs,
|
|
7
|
+
inverse-attrs,check,compare,dot-graph}.lisp; plugins/p11/{schedule-*
|
|
8
|
+
,resolve-declaration,cleanup-interface,wo-*}.lisp.
|
|
9
|
+
|
|
10
|
+
## 1. Name resolution ladder (kernel/find-declaration.lisp:125-172)
|
|
11
|
+
|
|
12
|
+
eeng's schema-scope restriction ladder for `find-declaration`:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
nil = :use-from
|
|
16
|
+
:local → own declarations + constants only
|
|
17
|
+
:use-from → :local OR :use-only
|
|
18
|
+
:use-only → walk USE FROM interfaces only, transitively, each in
|
|
19
|
+
:use-from scope (so USE visibility is transitive)
|
|
20
|
+
:all-iface → :local OR all interfaces (USE and REFERENCE), transitively
|
|
21
|
+
cycle guard → *schema-path*: schema already on path ⇒ nil
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Per-kind restrictions (`resolve-interface.lisp:30-66`):
|
|
25
|
+
- USE FROM resolves **type + entity only**.
|
|
26
|
+
- REFERENCE FROM resolves constant/entity/function/procedure/type.
|
|
27
|
+
- Unresolved resource ⇒ hard **error** `"Resource '~A' not found"`.
|
|
28
|
+
|
|
29
|
+
**expressir today:** `ModelElement#find` climbs parent scopes through
|
|
30
|
+
`children_by_id`; `Schema#children` = `interfaced_items + safe_children`
|
|
31
|
+
where `interfaced_items` is **single-hop** (own interfaces only, no
|
|
32
|
+
transitivity), and the resolver never errors on unresolved resources.
|
|
33
|
+
Our `find` also treats REFERENCE and USE identically (no visibility
|
|
34
|
+
tiering), and has no cycle guard (schema interface cycles loop until
|
|
35
|
+
the memo fills — the memo makes this safe in practice, not by design).
|
|
36
|
+
|
|
37
|
+
**Gaps:** (a) transitive USE visibility — item visible through a chain
|
|
38
|
+
of USEs is invisible to our single-hop lookup; (b) USE/REFERENCE
|
|
39
|
+
visibility tiering absent; (c) no unresolved-resource diagnostics;
|
|
40
|
+
(d) no cycle guard by construction. Fix tracked in TODO 06.
|
|
41
|
+
|
|
42
|
+
## 2. Load scheduling (plugins/p11/schedule-*.lisp)
|
|
43
|
+
|
|
44
|
+
eeng: `schedule-load` (two-pass parse), `schedule-interfaces`
|
|
45
|
+
(one method per session kind: double-stepmod keeps trl/ref schema
|
|
46
|
+
sets — schema1/schemata1 = trial, schemata2 = reference), recursing
|
|
47
|
+
per interface symbol → find/load the foreign file via the stepmod
|
|
48
|
+
directory layout, then `schedule-resolve` → `resolve-declaration` per
|
|
49
|
+
schema with `*schema?*` dynamic scope (:trl-schema / :ref-schema).
|
|
50
|
+
|
|
51
|
+
**expressir today:** `from_files` (batch + compiled set), repository
|
|
52
|
+
flat over all files; no trl/ref duality (we never compare two
|
|
53
|
+
specification universes); interface targets located by name at resolve
|
|
54
|
+
time through the repository (single-hop, see §1).
|
|
55
|
+
|
|
56
|
+
**Verdict:** structural difference, not a bug — our repository model
|
|
57
|
+
subsumes their session model for everything except `--compare`
|
|
58
|
+
(two-universe schema comparison, kernel/compare.lisp, unported; TODO
|
|
59
|
+
07 candidate).
|
|
60
|
+
|
|
61
|
+
## 3. Entity computations (kernel/compute-inheritance.lisp,
|
|
62
|
+
derive-attrs.lisp, inverse-attrs.lisp, supertypes.lisp,
|
|
63
|
+
explicit-attrs.lisp)
|
|
64
|
+
|
|
65
|
+
eeng **materializes** inherited attributes onto entities:
|
|
66
|
+
explicit attributes from the full supertype closure, derived attrs,
|
|
67
|
+
inverse attrs, subtype/supertype links — used by `--validate`,
|
|
68
|
+
population checks, and SHTOLO's generalized-attribute handling
|
|
69
|
+
(Annex G.2.6 needs exactly these).
|
|
70
|
+
|
|
71
|
+
**expressir today:** nothing materialized; consumers walk the
|
|
72
|
+
supertype closure themselves (our item graph does this for edges, not
|
|
73
|
+
attributes).
|
|
74
|
+
|
|
75
|
+
**Gaps:** inherited-explicit-attribute flattening, derived/inverse
|
|
76
|
+
closures. Needed by 05 (G.2.6 select synthesis) and 07 (checks).
|
|
77
|
+
TODO 05 scope.
|
|
78
|
+
|
|
79
|
+
## 4. Semantic checks (kernel/check.lisp, 835 lines)
|
|
80
|
+
|
|
81
|
+
check-p11 methods per node type: schema-level (interface resource
|
|
82
|
+
existence, per-kind resolution rules), entity (attribute redeclare
|
|
83
|
+
compatibility, inverse target/entity/inverse-attr existence, derive
|
|
84
|
+
aggregation rules), function/procedure/rule parameters, subtype
|
|
85
|
+
constraints, types. Check severity/notes via check-notes.lisp.
|
|
86
|
+
|
|
87
|
+
**expressir today:** `RepositoryValidator` (interface-level only) +
|
|
88
|
+
`validate ascii` CLI. Gap tracked in TODO 07.
|
|
89
|
+
|
|
90
|
+
## 5. Writers (plugins/p11/wo-*.lisp)
|
|
91
|
+
|
|
92
|
+
| eeng | semantics | expressir |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| wo-pretty | normal encoding, 2-space indent | Formatter clean mode — parity specs landed (bug39/40) |
|
|
95
|
+
| wo-flat | `:flat` encoding, downcased symbols, typeof-option banner | 05 (Annex G — note eeng's flat KEEPS 2003 constructs: partial) |
|
|
96
|
+
| wo-list | declaration listing | 09 |
|
|
97
|
+
| wo-smrl-xml | `<concatenated_express_file_content_list>` index for longform/concatenated modes | 09 |
|
|
98
|
+
| wo-lexp | lisp S-expression dump | not planned (internal debugging) |
|
|
99
|
+
|
|
100
|
+
## 6. Bugs found by this audit
|
|
101
|
+
|
|
102
|
+
- **expressir#373** — Ruby parse path corrupts small USE FROM schemas
|
|
103
|
+
(<~70B, non-monotonic; core path correct). Found by the concatenator
|
|
104
|
+
fixtures; `dependency_resolver_spec` failures on main are the same
|
|
105
|
+
root cause. Fixed by the #371/#370 stack.
|
|
106
|
+
- eeng partial Annex G coverage — documented in
|
|
107
|
+
`spec/fixtures/shtolo/annex-g-rules.md` (eeng is a partial oracle;
|
|
108
|
+
the annex is the contract).
|
data/exe/expressir
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
# encoding: UTF-8
|
|
3
3
|
|
|
4
|
+
# Ruby block-buffers stdout when it is not a terminal, so progress from a long
|
|
5
|
+
# run reaches a CI log only when the buffer fills or the process exits. A job
|
|
6
|
+
# that is working then looks hung. Set here rather than in the library, which
|
|
7
|
+
# runs inside other people's processes and does not own their streams.
|
|
8
|
+
$stdout.sync = true
|
|
9
|
+
|
|
4
10
|
require_relative "../lib/expressir"
|
|
5
11
|
Expressir::Cli.start(ARGV)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "expressir_core"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
edition = "2021"
|
|
5
|
+
publish = false
|
|
6
|
+
|
|
7
|
+
[lib]
|
|
8
|
+
name = "expressir_core"
|
|
9
|
+
crate-type = ["cdylib"]
|
|
10
|
+
|
|
11
|
+
[dependencies]
|
|
12
|
+
magnus = { version = "0.9" }
|
|
13
|
+
expressir-rs = { git = "https://github.com/lutaml/expressir-rs", branch = "main" }
|
|
14
|
+
serde_json = "1.0"
|
|
15
|
+
|
|
16
|
+
# Standalone workspace: the repo root workspace owns crates/, the ext
|
|
17
|
+
# is built by rb_sys with its own cargo invocation.
|
|
18
|
+
[workspace]
|
|
19
|
+
|
|
20
|
+
# Same magnus/rb-sys pins as parsanol-ruby (Ruby 4.0 support).
|
|
21
|
+
[patch.crates-io]
|
|
22
|
+
magnus = { git = "https://github.com/matsadler/magnus", rev = "9407bd9" }
|
|
23
|
+
magnus-macros = { git = "https://github.com/matsadler/magnus", rev = "9407bd9" }
|
|
24
|
+
rb-sys = { git = "https://github.com/oxidize-rb/rb-sys.git", rev = "daa12b6521a0c442a705d7f9a929029119aab1d6" }
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "mkmf"
|
|
4
|
+
|
|
5
|
+
# The Rust extension only builds against MRI's C API. Other engines
|
|
6
|
+
# fall back to the pure-Ruby parser path and must install cleanly.
|
|
7
|
+
if RUBY_ENGINE != "ruby" || ENV["EXPRESSIR_CORE"] == "0"
|
|
8
|
+
File.write("Makefile", dummy_makefile("").to_s)
|
|
9
|
+
warn "expressir: skipping the Rust core extension on #{RUBY_ENGINE}"
|
|
10
|
+
exit 0
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Pure-Ruby fallback when no Rust toolchain is available: the gem must
|
|
14
|
+
# install and keep working without the native core
|
|
15
|
+
# (Expressir::Core::NATIVE_AVAILABLE stays false). Prebuilt platform
|
|
16
|
+
# gems are the follow-up so cargo-less MRI installs get binaries too.
|
|
17
|
+
unless find_executable("cargo")
|
|
18
|
+
File.write("Makefile", dummy_makefile("").to_s)
|
|
19
|
+
warn "expressir: cargo not found — skipping the Rust core extension " \
|
|
20
|
+
"(Expressir::Core falls back to the Ruby parser)"
|
|
21
|
+
exit 0
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
require "rb_sys/mkmf"
|
|
25
|
+
|
|
26
|
+
create_rust_makefile("expressir/expressir_core") do |r|
|
|
27
|
+
r.profile = ENV.fetch("RB_SYS_CARGO_PROFILE", :dev).to_sym
|
|
28
|
+
r.use_stable_api_compiled_fallback = true
|
|
29
|
+
r.force_install_rust_toolchain = false
|
|
30
|
+
end
|