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,85 @@
|
|
|
1
|
+
require "find"
|
|
2
|
+
|
|
3
|
+
module Expressir
|
|
4
|
+
module Commands
|
|
5
|
+
# Common parser/discovery helpers shared by parity CLI commands
|
|
6
|
+
# (expand, flatten, check) — they all need: list of files in the
|
|
7
|
+
# interface closure of a root file, and the root schema parsed.
|
|
8
|
+
module ParityInputs
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
# Resolve the transitive interface closure of +root_path+. Deps are
|
|
12
|
+
# looked up by schema name: first in the file's own directory, then
|
|
13
|
+
# across the enclosing STEPmod checkout (the nearest ancestor holding
|
|
14
|
+
# a `schemas/` directory, e.g. resources/ and modules/ trees).
|
|
15
|
+
def closure_paths(root_path, manifest: nil, stepmod: nil)
|
|
16
|
+
index = schema_index(root_path)
|
|
17
|
+
seen = { File.basename(root_path, ".exp").downcase => root_path }
|
|
18
|
+
queue = [File.basename(root_path, ".exp").downcase]
|
|
19
|
+
until queue.empty?
|
|
20
|
+
name = queue.shift
|
|
21
|
+
path = seen[name] || index[name]
|
|
22
|
+
next unless path
|
|
23
|
+
next if seen.key?(name) && seen[name] != root_path
|
|
24
|
+
|
|
25
|
+
seen[name] = path
|
|
26
|
+
closure_names(File.read(path)).each { |d| queue << d.downcase }
|
|
27
|
+
end
|
|
28
|
+
seen.values.uniq
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Schema-name → path map for the STEPmod checkout around +root_path+,
|
|
32
|
+
# built once per invocation. The index root is the nearest ancestor
|
|
33
|
+
# directory NAMED `schemas` (wg12-step layout:
|
|
34
|
+
# `schemas/modules/<module>/mim.exp`), and entries key on the schema
|
|
35
|
+
# name declared inside each file — module files are `arm.exp` /
|
|
36
|
+
# `mim.exp`, so basenames cannot be the key. Falls back to the file's
|
|
37
|
+
# own directory when there is no schemas/ ancestor.
|
|
38
|
+
def schema_index(root_path)
|
|
39
|
+
dir = File.dirname(File.expand_path(root_path))
|
|
40
|
+
until dir == "/" || File.basename(dir) == "schemas"
|
|
41
|
+
parent = File.dirname(dir)
|
|
42
|
+
break if parent == dir
|
|
43
|
+
|
|
44
|
+
dir = parent
|
|
45
|
+
end
|
|
46
|
+
return same_dir_index(root_path) unless File.basename(dir) == "schemas"
|
|
47
|
+
|
|
48
|
+
@@indexes ||= {}
|
|
49
|
+
@@indexes[dir] ||= begin
|
|
50
|
+
h = {}
|
|
51
|
+
Find.find(dir) do |path|
|
|
52
|
+
next unless path.end_with?(".exp")
|
|
53
|
+
|
|
54
|
+
declared = File.read(path)[/\bSCHEMA\s+(\w+)/i, 1]
|
|
55
|
+
h[declared.downcase] = path if declared
|
|
56
|
+
h[File.basename(path, ".exp").downcase] ||= path
|
|
57
|
+
end
|
|
58
|
+
h
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def same_dir_index(root_path)
|
|
63
|
+
dir = File.dirname(File.expand_path(root_path))
|
|
64
|
+
Dir.glob(File.join(dir, "*.exp")).to_h do |p|
|
|
65
|
+
[File.basename(p, ".exp").downcase, p]
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def closure_names(source)
|
|
70
|
+
source.scan(/\bUSE\s+FROM\s+(\w+)/i).flatten.uniq +
|
|
71
|
+
source.scan(/\bREFERENCE\s+FROM\s+(\w+)/i).flatten.uniq
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# manifest:/stepmod: are accepted for the ELF-manifest resolver
|
|
75
|
+
# contract; the directory-index fallback ignores them until that
|
|
76
|
+
# resolver lands.
|
|
77
|
+
def root_schema(root_path, manifest: nil, stepmod: nil)
|
|
78
|
+
name = File.read(root_path)[/\bSCHEMA\s+(\w+)/, 1]
|
|
79
|
+
cp = closure_paths(root_path)
|
|
80
|
+
repo = Expressir::Express::Parser.from_files(cp, max_processes: 1)
|
|
81
|
+
[repo.schemas.find { |s| s.id == name }, repo]
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -79,6 +79,28 @@ module Expressir
|
|
|
79
79
|
def ascii(path)
|
|
80
80
|
ValidateAscii.new(options).run(path)
|
|
81
81
|
end
|
|
82
|
+
|
|
83
|
+
desc "check *PATHS", "Run eeng check-p11 semantic checks"
|
|
84
|
+
long_desc <<~DESC
|
|
85
|
+
Walks one or more EXPRESS files (or directories of .exp) and
|
|
86
|
+
reports the eeng check-p11 note subset covered by Checker:
|
|
87
|
+
redundant interfaces, duplicate resources, unresolved interface
|
|
88
|
+
schema/ref, SUBTYPE OF targets, SELECT/ENUM BASED_ON, and
|
|
89
|
+
WHERE/UNIQUE label patterns.
|
|
90
|
+
|
|
91
|
+
Exits 1 when any error-severity note fires.
|
|
92
|
+
DESC
|
|
93
|
+
method_option :json, type: :boolean, default: false,
|
|
94
|
+
desc: "Emit the report as JSON (errors + warnings)"
|
|
95
|
+
method_option :manifest, type: :string,
|
|
96
|
+
desc: "ELF schema manifest YAML defining where schemas live " \
|
|
97
|
+
"(primary resolution mode)"
|
|
98
|
+
method_option :stepmod, type: :string,
|
|
99
|
+
desc: "STEPmod checkout root — explicit opt-in to directory-" \
|
|
100
|
+
"convention resolution as the fallback"
|
|
101
|
+
def check(*paths)
|
|
102
|
+
Check.new(options).run(*paths)
|
|
103
|
+
end
|
|
82
104
|
end
|
|
83
105
|
end
|
|
84
106
|
end
|
data/lib/expressir/commands.rb
CHANGED
|
@@ -4,9 +4,14 @@ module Expressir
|
|
|
4
4
|
autoload :Base, "#{__dir__}/commands/base"
|
|
5
5
|
autoload :Benchmark, "#{__dir__}/commands/benchmark"
|
|
6
6
|
autoload :BenchmarkCache, "#{__dir__}/commands/benchmark_cache"
|
|
7
|
+
autoload :Check, "#{__dir__}/commands/check"
|
|
7
8
|
autoload :Clean, "#{__dir__}/commands/clean"
|
|
8
9
|
autoload :Coverage, "#{__dir__}/commands/coverage"
|
|
10
|
+
autoload :Expand, "#{__dir__}/commands/expand"
|
|
11
|
+
autoload :Fix, "#{__dir__}/commands/fix"
|
|
12
|
+
autoload :Flatten, "#{__dir__}/commands/flatten"
|
|
9
13
|
autoload :Format, "#{__dir__}/commands/format"
|
|
14
|
+
autoload :ParityInputs, "#{__dir__}/commands/parity_inputs"
|
|
10
15
|
autoload :Validate, "#{__dir__}/commands/validate"
|
|
11
16
|
autoload :ValidateLoad, "#{__dir__}/commands/validate_load"
|
|
12
17
|
autoload :ValidateAscii, "#{__dir__}/commands/validate_ascii"
|
|
@@ -325,13 +325,22 @@ module Expressir
|
|
|
325
325
|
|
|
326
326
|
# Simple types
|
|
327
327
|
Builder.register(:boolean_type) { |d| type_builder.build_boolean_type(d) }
|
|
328
|
+
# GENERIC[: label] / GENERIC_ENTITY[: label] — ISO 10303-11
|
|
329
|
+
# 9.5.3.2 type label (GH-339).
|
|
330
|
+
def self.type_label_id(ast_data)
|
|
331
|
+
label = ast_data.is_a?(Hash) ? ast_data[:type_label] : nil
|
|
332
|
+
return nil unless label.is_a?(Hash)
|
|
333
|
+
|
|
334
|
+
Builder.build_optional({ simple_id: label[:type_label_id][:simple_id] })
|
|
335
|
+
end
|
|
336
|
+
|
|
328
337
|
Builder.register(:integer_type) { |d| type_builder.build_integer_type(d) }
|
|
329
338
|
Builder.register(:logical_type) { |d| type_builder.build_logical_type(d) }
|
|
330
339
|
Builder.register(:number_type) { |d| type_builder.build_number_type(d) }
|
|
331
340
|
|
|
332
341
|
# Type constructors
|
|
333
|
-
Builder.register(:generic_type) { |
|
|
334
|
-
Builder.register(:generic_entity_type) { |
|
|
342
|
+
Builder.register(:generic_type) { |d| Expressir::Model::DataTypes::Generic.new(id: BuilderRegistry.type_label_id(d)) }
|
|
343
|
+
Builder.register(:generic_entity_type) { |d| Expressir::Model::DataTypes::GenericEntity.new(id: BuilderRegistry.type_label_id(d)) }
|
|
335
344
|
Builder.register(:aggregate_type) do |d|
|
|
336
345
|
type_builder.build_aggregate_type(d)
|
|
337
346
|
end
|
|
@@ -46,13 +46,22 @@ module Expressir
|
|
|
46
46
|
|
|
47
47
|
if subtype_declaration.is_a?(Hash)
|
|
48
48
|
list_ref = subtype_declaration[:list_of_entity_ref]
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
# SUBTYPE OF (a) flattens to a Hash; SUBTYPE OF (a, b) to an
|
|
50
|
+
# Array of single-key fragments (entity_ref possibly merged
|
|
51
|
+
# with its op_comma). Collect entity_ref from either shape
|
|
52
|
+
# (lutaml/expressir#341).
|
|
53
|
+
raw_entity_refs =
|
|
54
|
+
if list_ref.is_a?(Hash)
|
|
55
|
+
ref = list_ref[:entity_ref]
|
|
56
|
+
ref.is_a?(Array) ? ref : [ref]
|
|
57
|
+
elsif list_ref.is_a?(Array)
|
|
58
|
+
list_ref.filter_map { |el| el[:entity_ref] if el.is_a?(Hash) }
|
|
59
|
+
.flat_map { |d| d.is_a?(Array) ? d : [d] }
|
|
55
60
|
end
|
|
61
|
+
if raw_entity_refs && !raw_entity_refs.empty?
|
|
62
|
+
subtype_of = Builder.build_children(raw_entity_refs.map do |d|
|
|
63
|
+
{ entity_ref: d }
|
|
64
|
+
end)
|
|
56
65
|
end
|
|
57
66
|
end
|
|
58
67
|
end
|
|
@@ -78,7 +87,8 @@ module Expressir
|
|
|
78
87
|
end
|
|
79
88
|
|
|
80
89
|
if entity_body[:unique_clause]
|
|
81
|
-
|
|
90
|
+
built = Builder.build({ unique_clause: entity_body[:unique_clause] })
|
|
91
|
+
unique_rules = Array(built).compact
|
|
82
92
|
end
|
|
83
93
|
unique_rules ||= []
|
|
84
94
|
|
|
@@ -21,7 +21,9 @@ module Expressir
|
|
|
21
21
|
if body.is_a?(Hash)
|
|
22
22
|
abstract = !body[:abstract_supertype].nil?
|
|
23
23
|
if body[:total_over].is_a?(Hash)
|
|
24
|
-
|
|
24
|
+
refs = body[:total_over][:list_of_entity_ref] ||
|
|
25
|
+
body[:total_over][:entity_ref]
|
|
26
|
+
total_over = Builder.build_children(Builder.ensure_array(refs))
|
|
25
27
|
end
|
|
26
28
|
# Wrap supertype_expression in its node type so Builder.build dispatches correctly
|
|
27
29
|
supertype_expression = if body[:supertype_expression]
|
|
@@ -114,10 +114,18 @@ module Expressir
|
|
|
114
114
|
bound1 = Builder.build_optional(bound_spec[:bound1])
|
|
115
115
|
bound2 = Builder.build_optional(bound_spec[:bound2])
|
|
116
116
|
base_type = Builder.build_optional(ast_data[:parameter_type])
|
|
117
|
+
# Element modifiers are legal on general aggregations too
|
|
118
|
+
# (attributes and parameters); dropping them silently changed
|
|
119
|
+
# element constraints (GH-338). ARRAY carries both flags,
|
|
120
|
+
# LIST only UNIQUE, per the model.
|
|
121
|
+
optional = !ast_data[:t_optional].nil? if type_class.method_defined?(:optional)
|
|
122
|
+
unique = !ast_data[:t_unique].nil? if type_class.method_defined?(:unique)
|
|
117
123
|
|
|
118
124
|
type_class.new(
|
|
119
125
|
bound1: bound1,
|
|
120
126
|
bound2: bound2,
|
|
127
|
+
optional: optional,
|
|
128
|
+
unique: unique,
|
|
121
129
|
base_type: base_type,
|
|
122
130
|
)
|
|
123
131
|
end
|
|
@@ -25,8 +25,15 @@ module Expressir
|
|
|
25
25
|
attributes = Builder.build_children(inner_data[:referenced_attribute])
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
attributes = attributes.compact
|
|
29
|
+
|
|
30
|
+
# The grammar's separator repetition can yield a phantom rule
|
|
31
|
+
# fragment (no label, no referenced attributes) between real
|
|
32
|
+
# rules; drop it so clean never emits a bare ";" (GH-340).
|
|
33
|
+
return nil if id.nil? && attributes.empty?
|
|
34
|
+
|
|
28
35
|
Expressir::Model::Declarations::UniqueRule.new(id: id,
|
|
29
|
-
attributes: attributes
|
|
36
|
+
attributes: attributes)
|
|
30
37
|
end
|
|
31
38
|
end
|
|
32
39
|
end
|