expressir 2.4.14 → 2.4.16
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.parity-ee/18-mim-mapping.md +47 -0
- data/lib/expressir/commands/parity_inputs.rb +42 -8
- data/lib/expressir/express/checker.rb +6 -6
- data/lib/expressir/express/shtolo.rb +13 -7
- data/lib/expressir/version.rb +1 -1
- data/rakelib/oracle.rake +52 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ca7a970fe2d30edcb570639ddd4c178b2edf7bdee839844df7946fdb1e842d1b
|
|
4
|
+
data.tar.gz: a5a5b1c703de8027892d77792fbc957155101b8875fe1aa080feefec9d278ac7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '0950891e9ddb51792aaf69c1c82af9224ae6126b5ff77dd481e48105b2e39215dd23a1d1c3e30d060be4ef2988132b4aec47cf306903dc9081a05e73c5e6f42d'
|
|
7
|
+
data.tar.gz: 976131ab90fedb6e659129ca1f0aa6a3e8a8d5df40cb00950dc8b6b237789dcc4d896df03c35532e3afac6483e2f3674983bb0bc092adbf0534ed355d155a507
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# 18 — EXPRESS MIM mapping parser (expressir#88)
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
Parse and validate MIM "reference path" mappings — the application ↔
|
|
6
|
+
interpretation mapping every STEP module carries — into a typed model,
|
|
7
|
+
with the mapping paths validated against the ARM/MIM schemas.
|
|
8
|
+
|
|
9
|
+
## Sources
|
|
10
|
+
|
|
11
|
+
- This checkout's canonical form: `schemas/modules/*/mapping.yaml` —
|
|
12
|
+
structured ae/aimelt/aa records whose values use the
|
|
13
|
+
`<<express:SCHEMA.ITEM,ITEM>>` link markup (the same markup
|
|
14
|
+
`Suma::LinkValidation` validates today). Generated upstream from
|
|
15
|
+
module.xml.
|
|
16
|
+
- Upstream SMRL module.xml: `mapping`/`ae`/`aimelt` elements with
|
|
17
|
+
`reference_path` bodies — the ISO 10303-1x mapping methodology
|
|
18
|
+
grammar: entity chains `A -> B -> C`, qualifiers `[attr => val]`,
|
|
19
|
+
`=>` derived references, `->>` subtype traversal, `<>` select
|
|
20
|
+
member. Port the grammar from the Part 1x mapping annex text
|
|
21
|
+
(detached docs) + existing module corpus as the oracle.
|
|
22
|
+
- eeng has no counterpart — this is an expressir-first capability.
|
|
23
|
+
|
|
24
|
+
## Design
|
|
25
|
+
|
|
26
|
+
1. `Expressir::Model::Mapping` — MappingDocument →
|
|
27
|
+
ApplicationElements (entity, aimelt, attributes) and
|
|
28
|
+
ReferencePath nodes (path-expression AST: steps, qualifiers,
|
|
29
|
+
subtype traversals).
|
|
30
|
+
2. `mapping.yaml` reader (lutaml-model typed) — yaml → MappingDocument.
|
|
31
|
+
3. Reference-path expression parser — parsanol grammar over the path
|
|
32
|
+
syntax; AST reuses Model::References where shapes coincide.
|
|
33
|
+
4. Validation: every path resolves against the resolved ARM+MIM
|
|
34
|
+
repository (rides SchemaIndex / ItemGraph); unknown step = error
|
|
35
|
+
note (Checker id `check-mapping-path`).
|
|
36
|
+
5. CLI: `expressir mapping validate DIR|FILE` over module dirs.
|
|
37
|
+
|
|
38
|
+
## Acceptance
|
|
39
|
+
|
|
40
|
+
- All module mapping.yaml files in the SMRL parse; path validation
|
|
41
|
+
reports zero unknown steps (or a classified, explained residue).
|
|
42
|
+
- Round-trip: MappingDocument → yaml byte-stable.
|
|
43
|
+
|
|
44
|
+
## Test cases
|
|
45
|
+
|
|
46
|
+
- module corpus (603 modules); hand fixtures for each path grammar
|
|
47
|
+
production; invalid-path fixtures.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require "find"
|
|
2
|
+
require "thor"
|
|
2
3
|
|
|
3
4
|
module Expressir
|
|
4
5
|
module Commands
|
|
@@ -42,8 +43,9 @@ module Expressir
|
|
|
42
43
|
end
|
|
43
44
|
end
|
|
44
45
|
unless missing.empty?
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
raise Thor::Error,
|
|
47
|
+
"expressir: schema(s) not found: #{missing.uniq.join(', ')}" \
|
|
48
|
+
"#{resolver_hint(manifest, stepmod)}"
|
|
47
49
|
end
|
|
48
50
|
seen.values.compact.uniq
|
|
49
51
|
end
|
|
@@ -59,15 +61,18 @@ module Expressir
|
|
|
59
61
|
end
|
|
60
62
|
end
|
|
61
63
|
|
|
62
|
-
# Schema-name → path index from the ELF schema manifest.
|
|
64
|
+
# Schema-name → path index from the ELF schema manifest. An
|
|
65
|
+
# explicitly given manifest that cannot be loaded is fatal (#455):
|
|
66
|
+
# when the root has no interface dependencies the lookup would
|
|
67
|
+
# never consult the index, so a typo'd --manifest would exit 0.
|
|
63
68
|
def manifest_index(manifest_path)
|
|
64
69
|
manifest = Expressir::SchemaManifest.from_file(manifest_path)
|
|
65
70
|
manifest.schemas.to_h do |entry|
|
|
66
71
|
[entry.id.downcase, entry.path]
|
|
67
72
|
end
|
|
68
73
|
rescue StandardError => e
|
|
69
|
-
|
|
70
|
-
|
|
74
|
+
raise Thor::Error,
|
|
75
|
+
"expressir: could not load schema manifest #{manifest_path}: #{e.message}"
|
|
71
76
|
end
|
|
72
77
|
|
|
73
78
|
# Schema-name → path index over a STEPmod checkout root (the
|
|
@@ -90,14 +95,43 @@ module Expressir
|
|
|
90
95
|
return manifest_index(manifest) if manifest
|
|
91
96
|
return stepmod_index(stepmod) if stepmod
|
|
92
97
|
|
|
93
|
-
|
|
98
|
+
# Default: the file's own directory plus, when the root sits
|
|
99
|
+
# inside a STEPmod checkout, its enclosing `schemas/` tree —
|
|
100
|
+
# the layout wg12-step modules live in. Same-directory
|
|
101
|
+
# declarations win over tree hits for the same schema name:
|
|
102
|
+
# the file next to the root is the intentional one (#455).
|
|
103
|
+
index = same_dir_index(root_path)
|
|
104
|
+
ancestor = ancestor_schemas_dir(root_path)
|
|
105
|
+
if ancestor
|
|
106
|
+
tree = stepmod_index(File.dirname(ancestor))
|
|
107
|
+
tree.update(index)
|
|
108
|
+
index = tree
|
|
109
|
+
end
|
|
110
|
+
index
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Nearest ancestor directory NAMED `schemas`, or nil.
|
|
114
|
+
def ancestor_schemas_dir(root_path)
|
|
115
|
+
dir = File.dirname(File.expand_path(root_path))
|
|
116
|
+
until dir == "/"
|
|
117
|
+
return dir if File.basename(dir) == "schemas"
|
|
118
|
+
|
|
119
|
+
dir = File.dirname(dir)
|
|
120
|
+
end
|
|
121
|
+
nil
|
|
94
122
|
end
|
|
95
123
|
|
|
96
124
|
def same_dir_index(root_path)
|
|
97
125
|
dir = File.dirname(File.expand_path(root_path))
|
|
98
|
-
|
|
99
|
-
|
|
126
|
+
h = {}
|
|
127
|
+
Dir.glob(File.join(dir, "*.exp")).each do |path|
|
|
128
|
+
# index by DECLARED schema name first (a file named arm.exp
|
|
129
|
+
# may declare schema m_arm), basename as fallback
|
|
130
|
+
declared = File.read(path)[/\bSCHEMA\s+(\w+)/i, 1]
|
|
131
|
+
h[declared.downcase] = path if declared
|
|
132
|
+
h[File.basename(path, ".exp").downcase] ||= path
|
|
100
133
|
end
|
|
134
|
+
h
|
|
101
135
|
end
|
|
102
136
|
|
|
103
137
|
# Interface names declared by +source+. Remark text is stripped
|
|
@@ -290,7 +290,7 @@ module Expressir
|
|
|
290
290
|
end
|
|
291
291
|
end
|
|
292
292
|
|
|
293
|
-
def each_reference(node, &)
|
|
293
|
+
def each_reference(node, &block)
|
|
294
294
|
case node
|
|
295
295
|
when Model::References::SimpleReference then yield node
|
|
296
296
|
when Model::ModelElement
|
|
@@ -299,8 +299,8 @@ module Expressir
|
|
|
299
299
|
|
|
300
300
|
value = node.public_send(attr)
|
|
301
301
|
case value
|
|
302
|
-
when Array then value.each { |item| each_reference(item, &) }
|
|
303
|
-
when Model::ModelElement then each_reference(value, &)
|
|
302
|
+
when Array then value.each { |item| each_reference(item, &block) }
|
|
303
|
+
when Model::ModelElement then each_reference(value, &block)
|
|
304
304
|
end
|
|
305
305
|
end
|
|
306
306
|
end
|
|
@@ -407,7 +407,7 @@ module Expressir
|
|
|
407
407
|
end
|
|
408
408
|
end
|
|
409
409
|
|
|
410
|
-
def each_string(node, &)
|
|
410
|
+
def each_string(node, &block)
|
|
411
411
|
case node
|
|
412
412
|
when Model::Literals::String then yield node, node.value
|
|
413
413
|
when Model::ModelElement
|
|
@@ -416,8 +416,8 @@ module Expressir
|
|
|
416
416
|
|
|
417
417
|
value = node.public_send(attr)
|
|
418
418
|
case value
|
|
419
|
-
when Array then value.each { |item| each_string(item, &) }
|
|
420
|
-
when Model::ModelElement then each_string(value, &)
|
|
419
|
+
when Array then value.each { |item| each_string(item, &block) }
|
|
420
|
+
when Model::ModelElement then each_string(value, &block)
|
|
421
421
|
end
|
|
422
422
|
end
|
|
423
423
|
end
|
|
@@ -351,13 +351,17 @@ module Expressir
|
|
|
351
351
|
end
|
|
352
352
|
end
|
|
353
353
|
|
|
354
|
-
# Every identifier a call site names, across the
|
|
355
|
-
# surviving declarations: FunctionCall for functions
|
|
356
|
-
# ProcedureCall statements for procedures
|
|
357
|
-
#
|
|
358
|
-
#
|
|
359
|
-
#
|
|
354
|
+
# Every identifier a call site or reference names, across the
|
|
355
|
+
# artifact's surviving declarations: FunctionCall for functions,
|
|
356
|
+
# ProcedureCall statements for procedures, and ANY SimpleReference
|
|
357
|
+
# naming a schema function/procedure — a zero-argument function
|
|
358
|
+
# used bare (`v < limit_value`) parses as a plain reference, not
|
|
359
|
+
# a FunctionCall, and dropping it would leave the longform with a
|
|
360
|
+
# dangling call. Over-retaining is safe: prune only decides what
|
|
361
|
+
# may be dropped.
|
|
360
362
|
def called_ids(schema)
|
|
363
|
+
invocable = (schema.functions.to_a + schema.procedures.to_a)
|
|
364
|
+
.map { |d| d.id.safe_downcase }
|
|
361
365
|
called = {}
|
|
362
366
|
each_node(schema) do |node|
|
|
363
367
|
id = nil
|
|
@@ -366,8 +370,10 @@ module Expressir
|
|
|
366
370
|
id = node.function.is_a?(String) ? node.function : node.function&.id
|
|
367
371
|
when Expressir::Model::Statements::ProcedureCall
|
|
368
372
|
id = node.procedure.is_a?(String) ? node.procedure : node.procedure&.id
|
|
373
|
+
when Model::References::SimpleReference
|
|
374
|
+
id = node.id
|
|
369
375
|
end
|
|
370
|
-
called[id.safe_downcase] = true if id
|
|
376
|
+
called[id.safe_downcase] = true if id && invocable.include?(id.safe_downcase)
|
|
371
377
|
end
|
|
372
378
|
called
|
|
373
379
|
end
|
data/lib/expressir/version.rb
CHANGED
data/rakelib/oracle.rake
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "digest"
|
|
4
|
+
require "fileutils"
|
|
5
|
+
|
|
6
|
+
ORACLE_TAG = "eeng-5.2.8"
|
|
7
|
+
ORACLE_BASE =
|
|
8
|
+
"https://github.com/expresslang/eengine-releases/releases/download/#{ORACLE_TAG}".freeze
|
|
9
|
+
# Release-asset naming convention for the pinned tag: platform prefix
|
|
10
|
+
# and CPU tag used by expresslang/eengine-releases.
|
|
11
|
+
ORACLE_ASSET_NAMES = {
|
|
12
|
+
%w[darwin arm64] => "mac-arm64",
|
|
13
|
+
%w[darwin x86_64] => "mac-x86-64",
|
|
14
|
+
%w[linux x86_64] => "lnx-x86-64",
|
|
15
|
+
%w[linux arm64] => "lnx-arm64",
|
|
16
|
+
%w[mingw x86_64] => "win-x86-64",
|
|
17
|
+
}.freeze
|
|
18
|
+
|
|
19
|
+
namespace :oracle do
|
|
20
|
+
desc "Fetch the eengine oracle (#{ORACLE_TAG}) into tmp/oracle/eengine " \
|
|
21
|
+
"for the SHTOLO corpus differential"
|
|
22
|
+
task :fetch do
|
|
23
|
+
platform = [Gem::Platform.local.os, Gem::Platform.local.cpu]
|
|
24
|
+
tag = ORACLE_ASSET_NAMES[platform]
|
|
25
|
+
abort "no #{ORACLE_TAG} asset for #{platform.join('-')}" unless tag
|
|
26
|
+
|
|
27
|
+
version = ORACLE_TAG.delete_prefix("eeng-")
|
|
28
|
+
asset = "eengine-#{version}-#{tag}-sbcl#{'.exe' if platform.first == 'mingw'}"
|
|
29
|
+
target = File.expand_path("../tmp/oracle/eengine", __dir__)
|
|
30
|
+
digest = "#{target}.sha256"
|
|
31
|
+
|
|
32
|
+
if File.executable?(target)
|
|
33
|
+
expected = File.read(digest).strip.split(/\s+/).first if File.exist?(digest)
|
|
34
|
+
if expected && Digest::SHA256.file(target).hexdigest == expected
|
|
35
|
+
warn "oracle already present: #{target}"
|
|
36
|
+
exit 0
|
|
37
|
+
end
|
|
38
|
+
warn "cached oracle is missing or corrupt; refetching"
|
|
39
|
+
rm_f target
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
dir = File.dirname(target)
|
|
43
|
+
mkdir_p dir
|
|
44
|
+
download = File.join(dir, "#{asset}.part")
|
|
45
|
+
sh "curl", "-fSL", "-o", download, "#{ORACLE_BASE}/#{asset}"
|
|
46
|
+
sha = Digest::SHA256.file(download).hexdigest
|
|
47
|
+
mv download, target
|
|
48
|
+
chmod 0o755, target
|
|
49
|
+
File.write(digest, "#{sha} eengine\n")
|
|
50
|
+
puts "oracle ready: #{target} (#{sha})"
|
|
51
|
+
end
|
|
52
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: expressir
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.4.
|
|
4
|
+
version: 2.4.16
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-09-
|
|
11
|
+
date: 2026-09-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: base64
|
|
@@ -318,6 +318,7 @@ files:
|
|
|
318
318
|
- TODO.parity-ee/15-part28-xml.md
|
|
319
319
|
- TODO.parity-ee/16-compare-patch.md
|
|
320
320
|
- TODO.parity-ee/17-official-tests.md
|
|
321
|
+
- TODO.parity-ee/18-mim-mapping.md
|
|
321
322
|
- TODO.parity-ee/19-architecture.md
|
|
322
323
|
- TODO.parity-ee/parity-matrix.md
|
|
323
324
|
- benchmark/srl_benchmark.rb
|
|
@@ -639,6 +640,7 @@ files:
|
|
|
639
640
|
- lib/expressir/schema_manifest_entry.rb
|
|
640
641
|
- lib/expressir/version.rb
|
|
641
642
|
- lib/tasks/verify_remarks.rake
|
|
643
|
+
- rakelib/oracle.rake
|
|
642
644
|
- rakelib/verify_remarks.rake
|
|
643
645
|
homepage: https://github.com/lutaml/expressir
|
|
644
646
|
licenses:
|