expressir 2.4.32 → 2.4.33
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/TODO.eengine/00-overview.md +39 -0
- data/TODO.eengine/01-resolution-diagnostics.md +30 -0
- data/TODO.eengine/02-check-catalog-completion.md +53 -0
- data/TODO.eengine/03-entity-computations.md +22 -0
- data/TODO.eengine/04-shtolo-rule-audit.md +32 -0
- data/TODO.eengine/05-shtolo-longform-flatten.md +12 -0
- data/TODO.eengine/06-population-p21.md +34 -0
- data/TODO.eengine/07-schema-compare-patch.md +25 -0
- data/TODO.eengine/08-official-corpus-gate.md +7 -0
- data/TODO.eengine/09-mim-mapping-parser.md +9 -0
- data/lib/expressir/express/checker.rb +191 -3
- data/lib/expressir/express/schema_compare.rb +194 -0
- data/lib/expressir/express/shtolo.rb +22 -0
- data/lib/expressir/express.rb +2 -0
- data/lib/expressir/model/declarations/entity.rb +132 -0
- data/lib/expressir/model/declarations/schema.rb +37 -6
- data/lib/expressir/p21/builder.rb +92 -0
- data/lib/expressir/p21/grammar.rb +107 -0
- data/lib/expressir/p21/parser.rb +16 -0
- data/lib/expressir/p21/population.rb +35 -0
- data/lib/expressir/p21/validator.rb +213 -0
- data/lib/expressir/p21.rb +17 -0
- data/lib/expressir/version.rb +1 -1
- data/lib/expressir.rb +1 -0
- metadata +19 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 791c09b1ddc6f0ed583b4608c59ec327b7126c7c5b9d12c3a02acbaf236ae4c6
|
|
4
|
+
data.tar.gz: edb97cb53754e74511c9c28926ce4d9235afcd42d3d56fb4cd127017bff58590
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ed1e988f03f3e4f5af1f77872495088c87c49a5247b055850b498b235f5fd1693055fb734441ad9d357cd71548a2692b5a17dceacea10fe9d77d21bb580766a4
|
|
7
|
+
data.tar.gz: f63d8a48e336d00996b90efcc7797877c48a74a049aafcf52ae4e7f417dddbbf189a3d7452fd1daba527d38b17ae8d7a25b054338b64e41efb4ebd484aef669d
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# TODO.eengine — the eengine-parity program
|
|
2
|
+
|
|
3
|
+
Consolidates the remaining eengine-parity tasks (formerly scattered
|
|
4
|
+
across TODO.parity-ee) into one execution-ordered series. The oracle
|
|
5
|
+
is eengine-5.1.0 (GIT eeng-5.1.0) at `~/src/external/exp-engine-engine`; where
|
|
6
|
+
eengine and ISO 10303-11 disagree, the standard wins and the
|
|
7
|
+
divergence is classified in the differential output.
|
|
8
|
+
|
|
9
|
+
## Execution order and status
|
|
10
|
+
|
|
11
|
+
| n | task | folds | status |
|
|
12
|
+
|---|------|-------|--------|
|
|
13
|
+
| 01 | resolution diagnostics + USE/REFERENCE tiering | 06-remainder, 07-part | done |
|
|
14
|
+
| 02 | check-p11 catalog completion | 07, 12 | done (type-resolution tranche; generic unresolved-ref walk covers expression bodies; subtype-constraint supertype refs + SELF redeclaration resolution added; constness has no eeng rule — covered by the generic walk) |
|
|
15
|
+
| 03 | entity computations (inherited/derived/inverse closures) | matrix §3, 05-prereq | done |
|
|
16
|
+
| 04 | SHTOLO rule audit + corpus differential | 14-remainder | done (audit spec live; G.NM.2 + G.1.10 fixed; G.1.6 synthesis remains per annex-g-rules.md) |
|
|
17
|
+
| 05 | SHTOLO longform flatten (Annex G) | 05 | done |
|
|
18
|
+
| 06 | population / Part 21 reader + validation | 13 | done (parsanol reader; schema-mapping validator; Annex H corpus clean; eengine p21 differential blocked — eeng 5.1.0 aborts bare-p11 validate/*PARSE-MODE* NIL, every -MODE demands stepmod context) |
|
|
19
|
+
| 07 | schema compare & patch | 16 | done (SchemaCompare canonical-path deltas + SchemaPatch.apply; oracle differential vs eeng --compare green on add/remove entity/attribute + enum-value changes) |
|
|
20
|
+
| 08 | official corpus CI gate | 17 | done |
|
|
21
|
+
| 09 | MIM mapping parser | 18 | done |
|
|
22
|
+
|
|
23
|
+
## Sources
|
|
24
|
+
|
|
25
|
+
- eengine: `~/src/external/exp-engine-engine` (kernel/*.lisp,
|
|
26
|
+
plugins/p11/*.lisp, plugins/p21/*).
|
|
27
|
+
- ISO 10303-11 clause text: `~/src/mn/iso-10303-11/sources/sections/`.
|
|
28
|
+
- Detached docs: `~/src/mn/iso-10303-detached-docs/sources/` (Part 21
|
|
29
|
+
grammar, Part 28 text).
|
|
30
|
+
|
|
31
|
+
## Standing rules
|
|
32
|
+
|
|
33
|
+
- Semantics land in Ruby; parse-adjacent and graph-scale work lands in
|
|
34
|
+
expressir-rs (TODO.parity-ee 19, option B).
|
|
35
|
+
- Where eengine and the standard disagree, the standard wins; every
|
|
36
|
+
such divergence is classified in the differential output, never
|
|
37
|
+
silently copied.
|
|
38
|
+
- Every ported check keeps its eengine note id for oracle
|
|
39
|
+
cross-referencing, and cites its ISO 10303-11 clause.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# 01 — Resolution diagnostics + USE/REFERENCE tiering
|
|
2
|
+
|
|
3
|
+
Folds the shipped remainder of TODO.parity-ee 06 (transitive USE and
|
|
4
|
+
the cycle guard are in; `interface_visibility_spec.rb` gates them)
|
|
5
|
+
with the tiering half of 07.
|
|
6
|
+
|
|
7
|
+
## Gaps
|
|
8
|
+
|
|
9
|
+
- USE FROM resolves **type + entity only**; REFERENCE FROM resolves
|
|
10
|
+
constant/entity/function/procedure/type (eeng
|
|
11
|
+
resolve-interface.lisp:30-66). Our resolution treats both alike.
|
|
12
|
+
- Unresolved resources: eeng hard-errors `Resource '~A' not found`;
|
|
13
|
+
we warn (severity folded here from 07).
|
|
14
|
+
|
|
15
|
+
## Design
|
|
16
|
+
|
|
17
|
+
- `Schema#interfaced_items(kind:)` filters by interface kind.
|
|
18
|
+
- `Schema#resolve_item(name, kinds:)` walks own declarations then
|
|
19
|
+
interfaces (transitively through USE for :use-from scope),
|
|
20
|
+
cycle-guarded, honoring per-kind restriction.
|
|
21
|
+
- `Expressir::Express::Checker` reports unresolved references as
|
|
22
|
+
errors (`E-RES-001`, the eeng note id family) with schema+name.
|
|
23
|
+
|
|
24
|
+
## Acceptance
|
|
25
|
+
|
|
26
|
+
- USE-only visibility: an interface's function is NOT visible through
|
|
27
|
+
USE FROM; IS visible through REFERENCE FROM.
|
|
28
|
+
- Transitive USE chains still resolve (06's shipped behavior).
|
|
29
|
+
- Cycle-guarded resolution terminates.
|
|
30
|
+
- The checker flags an unresolved USE FROM resource as an error.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# 02 — check-p11 catalog completion
|
|
2
|
+
|
|
3
|
+
Folds TODO.parity-ee 07 + 12. Shipped subset: interface redundant,
|
|
4
|
+
interface resource duplicate, subtype ref/cycle, duplicate
|
|
5
|
+
declaration, where/unique name pattern, unresolved ref, select/enumeration
|
|
6
|
+
extended type, self-schema reference, parse failure.
|
|
7
|
+
|
|
8
|
+
## Sources
|
|
9
|
+
|
|
10
|
+
- `~/src/external/exp-engine-engine/kernel/check.lisp` (835 lines,
|
|
11
|
+
per-node-type check-p11 methods) + `kernel/check-notes.lisp`.
|
|
12
|
+
- ISO 10303-11:2004 clause text:
|
|
13
|
+
`~/src/mn/iso-10303-11/sources/sections/`.
|
|
14
|
+
|
|
15
|
+
## Port list (diff of eeng methods vs shipped subset)
|
|
16
|
+
|
|
17
|
+
Per eeng check-p11: entity attribute redeclare compatibility,
|
|
18
|
+
inverse target/entity/attribute existence, derive aggregation rules,
|
|
19
|
+
rule-entity reference containment, function/procedure parameter and
|
|
20
|
+
return checks, subtype-constraint reflexive/rule references,
|
|
21
|
+
constant expression constness. Each ported check keeps the eeng note
|
|
22
|
+
id and cites its ISO 10303-11 clause.
|
|
23
|
+
|
|
24
|
+
## Acceptance
|
|
25
|
+
|
|
26
|
+
- eeng-differential over the SRL corpus: every eeng-emitted note of
|
|
27
|
+
the ported kinds is emitted here with matching schema/name; no
|
|
28
|
+
false positives on clean corpora (express suite green).
|
|
29
|
+
|
|
30
|
+
## Status: done
|
|
31
|
+
|
|
32
|
+
Shipped across three tranches:
|
|
33
|
+
|
|
34
|
+
1. Original subset — interface redundant, interface resource
|
|
35
|
+
duplicate, subtype ref/cycle, duplicate declaration, where/unique
|
|
36
|
+
name pattern, unresolved ref, select/enumeration extended type,
|
|
37
|
+
self-schema reference, parse failure; inverse target/entity/
|
|
38
|
+
attribute checks; group references; aggregate bounds;
|
|
39
|
+
check-attrib-name-fun.
|
|
40
|
+
2. Type-resolution tranche — constant/local/parameter/return types
|
|
41
|
+
(eeng check-constant-type, check-local-type, check-parameter-type,
|
|
42
|
+
check-fun-return-type) plus rule FOR entity refs.
|
|
43
|
+
3. Remainder — subtype-constraint supertype-expression refs (eeng
|
|
44
|
+
kernel/check.lisp:426, check_supertype_ref note id) and
|
|
45
|
+
SELF\ redeclaration resolution (ISO 10303-11:2004 9.2.2.3; eeng
|
|
46
|
+
kernel/check.lisp:255 comment-only). Expression bodies are covered
|
|
47
|
+
generically by check_unresolved_refs; eengine has no separate
|
|
48
|
+
constant-expression constness rule (kernel/check.lisp only checks
|
|
49
|
+
the constant's type), so that port-list item closes as covered.
|
|
50
|
+
|
|
51
|
+
Foreign-blindness rule: names that do not resolve in a single-file
|
|
52
|
+
parse (USE FROM targets of unloaded schemas) are skipped, not flagged —
|
|
53
|
+
both new checks verified note-free over 265 stepmod resource schemas.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# 03 — Entity computations
|
|
2
|
+
|
|
3
|
+
Matrix §3: eeng materializes inherited attributes and closures
|
|
4
|
+
(kernel/compute-inheritance.lisp, derive-attrs.lisp,
|
|
5
|
+
inverse-attrs.lisp, supertypes.lisp, explicit-attrs.lisp); expressir
|
|
6
|
+
walks supertype chains ad hoc. Needed by Annex G.2.6 select synthesis
|
|
7
|
+
(04/05) and the entity checks (02).
|
|
8
|
+
|
|
9
|
+
## Design
|
|
10
|
+
|
|
11
|
+
- `Entity#supertype_closure` — transitively closed supertype refs,
|
|
12
|
+
cycle-safe.
|
|
13
|
+
- `Entity#inherited_explicit_attributes` — explicit attributes from
|
|
14
|
+
the full closure, redeclaration-aware (SELF\\supertype.attr
|
|
15
|
+
overrides).
|
|
16
|
+
- `Entity#derived_attributes` / `Entity#inverse_attributes` —
|
|
17
|
+
accumulated from the closure.
|
|
18
|
+
|
|
19
|
+
## Acceptance
|
|
20
|
+
|
|
21
|
+
- chain + multiple inheritance + redeclaration fixtures; the
|
|
22
|
+
materialization matches a hand-computed table.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# 04 — SHTOLO rule audit + corpus differential
|
|
2
|
+
|
|
3
|
+
Folds TODO.parity-ee 14's remainder.
|
|
4
|
+
|
|
5
|
+
- Walk `spec/fixtures/shtolo/annex-g-rules.md` (G.NM.1-2, G.1.1-10,
|
|
6
|
+
G.2.1-7): mark every rule PASS/partial/✖ with a fixture per rule.
|
|
7
|
+
- G.1.6 dependently-instantiable output verified against the Annex G
|
|
8
|
+
text (eeng ✖ there; the standard wins).
|
|
9
|
+
- name-munging policy (`_dot_` and friends): eeng ✖; standard wins.
|
|
10
|
+
- prune-pass reachability (unreachable subtype branches).
|
|
11
|
+
- corpus differential: every modules.lst module arm/mim, flat output
|
|
12
|
+
diffed vs eeng :flat, divergences classified.
|
|
13
|
+
|
|
14
|
+
## Result: DONE (2026-10-15) — the audit is a live spec
|
|
15
|
+
|
|
16
|
+
`shtolo_annex_g_rule_audit_spec.rb` — 8 examples, one per previously
|
|
17
|
+
uncovered rule. Audited outcome:
|
|
18
|
+
|
|
19
|
+
- G.NM.2, G.1.2, G.1.5, G.1.8 (model-direct), G.2.3, G.2.4, G.2.6 —
|
|
20
|
+
PASS (G.2.4's folded extension keeps its G.NM.1-munged name —
|
|
21
|
+
correct per the name-clash rule).
|
|
22
|
+
- G.1.10 — was absent; **implemented** (`add_provenance_remark!`):
|
|
23
|
+
all-or-none provenance remark on the longform schema with
|
|
24
|
+
schema + schema_version_id lines.
|
|
25
|
+
- Still open (recorded in annex-g-rules.md): G.1.6
|
|
26
|
+
dependently-instantiable RULE/FUNCTION synthesis (eeng ✖; annex is
|
|
27
|
+
the contract) and the G.1.9 prune-depth notes.
|
|
28
|
+
|
|
29
|
+
Fixture note: `EXTENSIBLE_ENUMERATION` as a single composite keyword
|
|
30
|
+
is not in the grammar and not in the corpus — the corpus writes
|
|
31
|
+
`EXTENSIBLE ENUMERATION` (302×) / `EXTENSIBLE SELECT` (546×), both
|
|
32
|
+
supported.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# 05 — SHTOLO longform flatten (Annex G)
|
|
2
|
+
|
|
3
|
+
TODO.parity-ee 05. Convert the STEPmod multi-schema web into ONE
|
|
4
|
+
ISO 10303-11:1994 longform schema: no interfaces, visibility
|
|
5
|
+
preserved as rules, no name clashes, unreachable declarations pruned.
|
|
6
|
+
|
|
7
|
+
Sources: `ag-single-schema.adoc` (rule ids), eeng run-op (:flat) +
|
|
8
|
+
print-flatten + wo-flat.lisp (373 lines; eeng keeps structure and
|
|
9
|
+
lowercases — the standard wins on divergence), add/remove-declaration
|
|
10
|
+
and cleanup-interface lisps.
|
|
11
|
+
|
|
12
|
+
Builds on 01 (visibility), 03 (closures), 04 (rule audit).
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# 06 — Population / Part 21
|
|
2
|
+
|
|
3
|
+
TODO.parity-ee 13, scope ladder (each step ships):
|
|
4
|
+
|
|
5
|
+
1. P21 reader: parsanol grammar for ISO 10303-21 (HEADER entities,
|
|
6
|
+
DATA section: complex instances `(A(...)B(...))`, simple
|
|
7
|
+
`#1=TYPE(...)`, list/set/typed-ref values, enums `.T.`, binary
|
|
8
|
+
`"...`, redefines `/`); a `Model::Population` (header + instances).
|
|
9
|
+
2. Population validation against a loaded schema: instance entity
|
|
10
|
+
exists (direct or complex against the supertype graph), attribute
|
|
11
|
+
names/arity match, value types check.
|
|
12
|
+
3. eengine differential on the Part 21 fixtures
|
|
13
|
+
(`~/src/mn/iso-10303-detached-docs/sources/iso-10303-21*`).
|
|
14
|
+
|
|
15
|
+
## Status: done
|
|
16
|
+
|
|
17
|
+
1. Reader — `Expressir::P21` (parsanol grammar + PopulationBuilder):
|
|
18
|
+
HEADER FILE_* entities, DATA simple/complex instances, lists,
|
|
19
|
+
typed parameters, references, enumerations, binaries, strings
|
|
20
|
+
(doubled-quote escape), `$`/`*`, `/* */` comments.
|
|
21
|
+
2. Validator — `Expressir::P21::Validator`: FILE_SCHEMA name,
|
|
22
|
+
instance keywords, complex-record supertype cliques, mapped
|
|
23
|
+
attribute arity in Part 21 order (supertype attributes first;
|
|
24
|
+
DERIVE-redeclared slots keep their position valued `*` per clause
|
|
25
|
+
12.2.6), enumeration membership, instance references,
|
|
26
|
+
typed-parameter resolution; optional short_names map for clause
|
|
27
|
+
12.3 short names.
|
|
28
|
+
3. Corpus — ISO 10303-21 Annex H complete exchange structure parses
|
|
29
|
+
and validates clean (13 instances, comments, short names).
|
|
30
|
+
|
|
31
|
+
eengine differential (ladder step 3) is blocked by the oracle build:
|
|
32
|
+
eengine 5.1.0 --validate/--xref abort loading a bare p11 schema
|
|
33
|
+
(*PARSE-MODE* NIL) and every -MODE demands a stepmod context, while
|
|
34
|
+
--validate itself is flagged "not fully supported" upstream.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# 07 — Schema compare & patch
|
|
2
|
+
|
|
3
|
+
TODO.parity-ee 16. Structural diff of two schemata with a
|
|
4
|
+
machine-applicable patch: declarations matched by canonical path
|
|
5
|
+
(`schema.item`); deltas added/removed/changed (per-attribute
|
|
6
|
+
structural diff: types, optionality, aggregates); patch output
|
|
7
|
+
declarable against the flattened base (eeng `--compare`/`--patch`
|
|
8
|
+
semantics, plugin/p11 compare entry).
|
|
9
|
+
|
|
10
|
+
## Status: done
|
|
11
|
+
|
|
12
|
+
- `Expressir::Express::SchemaCompare` — deltas at `schema.item` and
|
|
13
|
+
entity-attribute `schema.item.attribute` paths; signatures are
|
|
14
|
+
lutaml-model `to_hash` trees stripped of resolution artifacts
|
|
15
|
+
(`base_path`, `ref`, `source`, remarks).
|
|
16
|
+
- `Expressir::Express::SchemaPatch.apply` — rebuilds the revised
|
|
17
|
+
schema through the framework round trip; the base is never mutated;
|
|
18
|
+
item-level `:changed` nodes subsume their attribute sub-deltas.
|
|
19
|
+
- Interfaces are out of scope by design: the patch target is a
|
|
20
|
+
flattened (longform) schema.
|
|
21
|
+
- Oracle: `spec/expressir/express/schema_compare_oracle_spec.rb`
|
|
22
|
+
agrees with `eengine --compare -MODE RESOURCE -STEPMOD <checkout>`
|
|
23
|
+
on added/removed entities, removed attributes and enum-value type
|
|
24
|
+
changes; gated on binary + stepmod checkout presence
|
|
25
|
+
(EENGINE_BIN / STEPMOD_DIR).
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# 08 — Official corpus CI gate
|
|
2
|
+
|
|
3
|
+
TODO.parity-ee 17. One rake task mapping every official corpus to
|
|
4
|
+
specs, with CI tiers: (a) every push — eeng bug corpus (bug39/40),
|
|
5
|
+
SHTOLO rule fixtures, Part 21 grammar fixtures; (b) nightly/manual —
|
|
6
|
+
SRL/SMRL full corpus differentials (pretty/flat/xml) when the eengine
|
|
7
|
+
oracle is on PATH.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# 09 — MIM mapping parser
|
|
2
|
+
|
|
3
|
+
TODO.parity-ee 18 (expressir#88). Parse + validate MIM reference
|
|
4
|
+
paths into a typed model: entity chains `A -> B -> C`, qualifiers
|
|
5
|
+
`[attr => val]`, `=>` derived references, `->>` subtype traversal,
|
|
6
|
+
`<>` select member. Sources: this checkout's
|
|
7
|
+
`schemas/modules/*/mapping.yaml` (`<<express:SCHEMA.ITEM,ITEM>>` link
|
|
8
|
+
markup), upstream module.xml `reference_path` bodies, the Part 1x
|
|
9
|
+
mapping-annex grammar; the module corpus is the oracle.
|
|
@@ -82,6 +82,13 @@ module Expressir
|
|
|
82
82
|
blength insert remove
|
|
83
83
|
].freeze
|
|
84
84
|
|
|
85
|
+
USE_ITEM_KINDS = [Model::Declarations::Entity, Model::Declarations::Type].freeze
|
|
86
|
+
REFERENCE_ITEM_KINDS = [
|
|
87
|
+
Model::Declarations::Constant, Model::Declarations::Entity,
|
|
88
|
+
Model::Declarations::Function, Model::Declarations::Procedure,
|
|
89
|
+
Model::Declarations::Type
|
|
90
|
+
].freeze
|
|
91
|
+
|
|
85
92
|
private
|
|
86
93
|
|
|
87
94
|
def note!(id, severity, schema, message, node = nil)
|
|
@@ -92,6 +99,7 @@ module Expressir
|
|
|
92
99
|
def check_schema(schema)
|
|
93
100
|
check_duplicates(schema)
|
|
94
101
|
check_interfaces(schema)
|
|
102
|
+
check_type_resolutions(schema)
|
|
95
103
|
check_self_schema_reference(schema)
|
|
96
104
|
schema.entities.each { |e| check_entity(schema, e) }
|
|
97
105
|
schema.types.each do |t|
|
|
@@ -100,9 +108,11 @@ module Expressir
|
|
|
100
108
|
check_where_rules(schema, t, t.where_rules)
|
|
101
109
|
end
|
|
102
110
|
schema.rules.each { |r| check_where_rules(schema, r, r.where_rules) }
|
|
111
|
+
check_subtype_constraints(schema)
|
|
103
112
|
schema.entities.each do |entity|
|
|
104
113
|
check_aggregate_bounds(schema, entity)
|
|
105
114
|
check_attrib_name_fun(schema, entity)
|
|
115
|
+
check_attribute_redeclarations(schema, entity)
|
|
106
116
|
end
|
|
107
117
|
check_string_references(schema)
|
|
108
118
|
check_unresolved_refs(schema)
|
|
@@ -184,14 +194,44 @@ module Expressir
|
|
|
184
194
|
end
|
|
185
195
|
|
|
186
196
|
resource_names(iface).each do |name|
|
|
187
|
-
|
|
197
|
+
decl = foreign_declaration(foreign, name)
|
|
198
|
+
unless decl
|
|
199
|
+
note!(:check_unresolved_ref, :error, schema,
|
|
200
|
+
"interface resource '#{name}' not in schema '#{target}'", iface)
|
|
201
|
+
next
|
|
202
|
+
end
|
|
188
203
|
|
|
189
|
-
|
|
190
|
-
|
|
204
|
+
# eeng resolve-interface: use-from resolves via
|
|
205
|
+
# find-type/entity, reference-from via the 5-kind or-chain;
|
|
206
|
+
# anything else is "Resource '~A' not found".
|
|
207
|
+
next if item_kind_interfacable?(iface.kind, decl)
|
|
208
|
+
|
|
209
|
+
note!(:check_interface_kind_restriction, :error, schema,
|
|
210
|
+
"interface resource '#{name}' is a #{decl.class.name.split('::').last}: " + "#{iface.kind} resolves #{allowed_kinds(iface.kind)} only", iface)
|
|
191
211
|
end
|
|
192
212
|
end
|
|
193
213
|
end
|
|
194
214
|
|
|
215
|
+
def item_kind_interfacable?(kind, decl)
|
|
216
|
+
(kind == Model::Declarations::Interface::REFERENCE ? REFERENCE_ITEM_KINDS : USE_ITEM_KINDS)
|
|
217
|
+
.any? { |k| decl.is_a?(k) }
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def allowed_kinds(kind)
|
|
221
|
+
(kind == Model::Declarations::Interface::REFERENCE ? REFERENCE_ITEM_KINDS : USE_ITEM_KINDS)
|
|
222
|
+
.map { |k| k.name.split("::").last }.join(", ")
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def foreign_declaration(schema, name)
|
|
226
|
+
key = name.safe_downcase
|
|
227
|
+
DECL_COLLECTIONS.each do |coll|
|
|
228
|
+
Array(schema.public_send(coll)).each do |d|
|
|
229
|
+
return d if d.id&.safe_downcase == key
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
nil
|
|
233
|
+
end
|
|
234
|
+
|
|
195
235
|
def iface_schema_name(iface)
|
|
196
236
|
iface.schema.is_a?(String) ? iface.schema : iface.schema&.id
|
|
197
237
|
end
|
|
@@ -210,6 +250,85 @@ module Expressir
|
|
|
210
250
|
end
|
|
211
251
|
end
|
|
212
252
|
|
|
253
|
+
# eeng check-p11 context checks (kernel/check.lisp:160-201,
|
|
254
|
+
# 299-336, 337-395): constant/local/parameter/return types must
|
|
255
|
+
# resolve to a TYPE or ENTITY visible in the schema (find-type/
|
|
256
|
+
# entity semantics - constants, functions, procedures do NOT
|
|
257
|
+
# satisfy them). Note ids are the eeng ones.
|
|
258
|
+
def check_type_resolutions(schema)
|
|
259
|
+
schema.constants.each do |constant|
|
|
260
|
+
check_type_ref(schema, Array(constant.type), :check_constant_type, constant.id, constant)
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
schema.functions.each do |function|
|
|
264
|
+
Array(function.parameters).each do |param|
|
|
265
|
+
check_type_ref(schema, Array(param.type), :check_parameter_type, param.id, param)
|
|
266
|
+
end
|
|
267
|
+
check_type_ref(schema, Array(function.return_type),
|
|
268
|
+
:check_function_return_type, function.id, function)
|
|
269
|
+
Array(function.variables).each do |variable|
|
|
270
|
+
check_type_ref(schema, Array(variable.type), :check_local_type, variable.id, variable)
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
schema.procedures.each do |procedure|
|
|
275
|
+
Array(procedure.parameters).each do |param|
|
|
276
|
+
check_type_ref(schema, Array(param.type), :check_parameter_type, param.id, param)
|
|
277
|
+
end
|
|
278
|
+
Array(procedure.variables).each do |variable|
|
|
279
|
+
check_type_ref(schema, Array(variable.type), :check_local_type, variable.id, variable)
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
schema.rules.each do |rule|
|
|
284
|
+
Array(rule.applies_to).each do |entity_ref|
|
|
285
|
+
# parameter-rule: the FOR entities resolve via
|
|
286
|
+
# find-type/entity too (kernel/check.lisp:311-322)
|
|
287
|
+
check_entity_ref(schema, Array(entity_ref), :check_parameter_type, rule.id, rule)
|
|
288
|
+
end
|
|
289
|
+
Array(rule.variables).each do |variable|
|
|
290
|
+
check_type_ref(schema, Array(variable.type), :check_local_type, variable.id, variable)
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def check_type_ref(schema, nodes, note_id, name, node)
|
|
296
|
+
nodes.each do |type|
|
|
297
|
+
next unless type.is_a?(Model::References::SimpleReference)
|
|
298
|
+
next if type.id.nil? || builtin?(type.id)
|
|
299
|
+
next if resolves_to_type_or_entity?(schema, type.id)
|
|
300
|
+
|
|
301
|
+
note!(note_id, :error, schema,
|
|
302
|
+
"type '#{type.id}' of '#{name}' does not resolve to a type or entity", node || type)
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def check_entity_ref(schema, nodes, note_id, name, node)
|
|
307
|
+
nodes.each do |ref|
|
|
308
|
+
next unless ref.is_a?(Model::References::SimpleReference)
|
|
309
|
+
next if ref.id.nil?
|
|
310
|
+
next if resolves_to_type_or_entity?(schema, ref.id)
|
|
311
|
+
|
|
312
|
+
note!(note_id, :error, schema,
|
|
313
|
+
"entity '#{ref.id}' of '#{name}' does not resolve to a type or entity", node || ref)
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
def resolves_to_type_or_entity?(schema, name)
|
|
318
|
+
key = name.safe_downcase
|
|
319
|
+
schema.children.any? do |child|
|
|
320
|
+
next false unless child.id&.safe_downcase == key
|
|
321
|
+
|
|
322
|
+
child.is_a?(Model::Declarations::Type) || child.is_a?(Model::Declarations::Entity) ||
|
|
323
|
+
(child.is_a?(Model::Declarations::InterfacedItem) && interface_item_type_or_entity?(child))
|
|
324
|
+
end
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
def interface_item_type_or_entity?(item)
|
|
328
|
+
base = item.base_item
|
|
329
|
+
base.is_a?(Model::Declarations::Type) || base.is_a?(Model::Declarations::Entity)
|
|
330
|
+
end
|
|
331
|
+
|
|
213
332
|
def check_entity(schema, entity)
|
|
214
333
|
Array(entity.subtype_of).each do |ref|
|
|
215
334
|
id = ref.is_a?(String) ? ref : ref.id
|
|
@@ -282,6 +401,75 @@ module Expressir
|
|
|
282
401
|
|
|
283
402
|
# eeng check-supertype-ref: every entity named in the SUPERTYPE
|
|
284
403
|
# expression must resolve to an entity of this schema.
|
|
404
|
+
# eeng check-p11 subtype_constraint (kernel/check.lisp:426) only
|
|
405
|
+
# checks the supertype expression; the note id matches the entity
|
|
406
|
+
# supertype path (kernel/check.lisp:523).
|
|
407
|
+
def explicit_attributes(entity)
|
|
408
|
+
Array(entity.attributes)
|
|
409
|
+
.select { |attr| attr.instance_of?(Model::Declarations::Attribute) }
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
def check_subtype_constraints(schema)
|
|
413
|
+
schema.subtype_constraints.each do |constraint|
|
|
414
|
+
expr = constraint.supertype_expression
|
|
415
|
+
next unless expr
|
|
416
|
+
|
|
417
|
+
each_reference(expr) do |ref|
|
|
418
|
+
id = ref.id
|
|
419
|
+
next if id.nil?
|
|
420
|
+
# Names outside this schema's scope (foreign entities of a
|
|
421
|
+
# single-file parse) cannot be verified here.
|
|
422
|
+
next unless resolves_to_type_or_entity?(schema, id)
|
|
423
|
+
next if find_entity(schema, id)
|
|
424
|
+
|
|
425
|
+
note!(:check_supertype_ref, :error, schema,
|
|
426
|
+
"SUBTYPE_CONSTRAINT #{constraint.id}: supertype " \
|
|
427
|
+
"'#{id}' is not an entity", constraint)
|
|
428
|
+
end
|
|
429
|
+
end
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
# A `SELF\<supertype>.<attr>` redeclaration must name a supertype
|
|
433
|
+
# in the inheritance closure carrying that attribute (ISO
|
|
434
|
+
# 10303-11:2004, 9.2.2.3). eeng kernel/check.lisp:255 leaves this
|
|
435
|
+
# as a TODO comment, so this check has no eeng note id.
|
|
436
|
+
def check_attribute_redeclarations(schema, entity)
|
|
437
|
+
explicit_attributes(entity).each do |attr|
|
|
438
|
+
tag = attr.supertype_attribute
|
|
439
|
+
next unless tag.is_a?(Model::References::AttributeReference)
|
|
440
|
+
|
|
441
|
+
sup_id = tag.ref&.entity&.id
|
|
442
|
+
attr_id = tag.attribute&.id
|
|
443
|
+
if sup_id.nil?
|
|
444
|
+
note!(:check_attribute_redeclaration, :error, schema,
|
|
445
|
+
"ENTITY #{entity.id}: redeclaration of '#{attr.id}' " \
|
|
446
|
+
"names no supertype", attr)
|
|
447
|
+
next
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
supertype = entity.supertype_closure
|
|
451
|
+
.find { |st| st.id&.safe_downcase == sup_id.safe_downcase }
|
|
452
|
+
if supertype.nil?
|
|
453
|
+
# The named supertype may be foreign (USE FROM) and thus
|
|
454
|
+
# outside the closure of a single-file parse; only flag it
|
|
455
|
+
# when it resolves in this scope yet is not a supertype.
|
|
456
|
+
if find_entity(schema, sup_id)
|
|
457
|
+
note!(:check_attribute_redeclaration, :error, schema,
|
|
458
|
+
"ENTITY #{entity.id}: redeclaration '#{attr.id}' names " \
|
|
459
|
+
"'#{sup_id}', which is not a supertype", attr)
|
|
460
|
+
end
|
|
461
|
+
next
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
next if explicit_attributes(supertype)
|
|
465
|
+
.any? { |candidate| candidate.id&.safe_downcase == attr_id&.safe_downcase }
|
|
466
|
+
|
|
467
|
+
note!(:check_attribute_redeclaration, :error, schema,
|
|
468
|
+
"ENTITY #{entity.id}: redeclaration '#{attr.id}': supertype " \
|
|
469
|
+
"'#{sup_id}' has no attribute '#{attr_id}'", attr)
|
|
470
|
+
end
|
|
471
|
+
end
|
|
472
|
+
|
|
285
473
|
def check_supertype_refs(schema, entity)
|
|
286
474
|
expr = entity.supertype_expression
|
|
287
475
|
return unless expr
|