expressir 2.1.31 → 2.2.0
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/.github/workflows/docs.yml +3 -2
- data/.github/workflows/release.yml +6 -0
- data/.rubocop_todo.yml +98 -89
- data/Gemfile +1 -1
- data/README.adoc +372 -1
- data/docs/_guides/formatter/formatter-architecture.adoc +401 -0
- data/docs/_guides/ruby-api/parsing-files.adoc +1 -1
- data/docs/_pages/parsers.adoc +31 -5
- data/docs/lychee.toml +3 -0
- data/expressir.gemspec +2 -2
- data/lib/expressir/benchmark.rb +6 -6
- data/lib/expressir/cli.rb +9 -0
- data/lib/expressir/commands/format.rb +28 -0
- data/lib/expressir/coverage.rb +15 -11
- data/lib/expressir/express/builder.rb +350 -0
- data/lib/expressir/express/builders/attribute_decl_builder.rb +38 -0
- data/lib/expressir/express/builders/built_in_builder.rb +88 -0
- data/lib/expressir/express/builders/constant_builder.rb +115 -0
- data/lib/expressir/express/builders/declaration_builder.rb +24 -0
- data/lib/expressir/express/builders/derive_clause_builder.rb +16 -0
- data/lib/expressir/express/builders/derived_attr_builder.rb +28 -0
- data/lib/expressir/express/builders/domain_rule_builder.rb +21 -0
- data/lib/expressir/express/builders/entity_decl_builder.rb +108 -0
- data/lib/expressir/express/builders/explicit_attr_builder.rb +52 -0
- data/lib/expressir/express/builders/expression_builder.rb +453 -0
- data/lib/expressir/express/builders/function_decl_builder.rb +84 -0
- data/lib/expressir/express/builders/helpers.rb +148 -0
- data/lib/expressir/express/builders/interface_builder.rb +171 -0
- data/lib/expressir/express/builders/inverse_attr_builder.rb +45 -0
- data/lib/expressir/express/builders/inverse_attr_type_builder.rb +36 -0
- data/lib/expressir/express/builders/inverse_clause_builder.rb +16 -0
- data/lib/expressir/express/builders/literal_builder.rb +107 -0
- data/lib/expressir/express/builders/procedure_decl_builder.rb +80 -0
- data/lib/expressir/express/builders/qualifier_builder.rb +128 -0
- data/lib/expressir/express/builders/reference_builder.rb +27 -0
- data/lib/expressir/express/builders/rule_decl_builder.rb +95 -0
- data/lib/expressir/express/builders/schema_body_decl_builder.rb +22 -0
- data/lib/expressir/express/builders/schema_decl_builder.rb +62 -0
- data/lib/expressir/express/builders/schema_version_builder.rb +40 -0
- data/lib/expressir/express/builders/simple_id_builder.rb +26 -0
- data/lib/expressir/express/builders/statement_builder.rb +250 -0
- data/lib/expressir/express/builders/subtype_constraint_builder.rb +188 -0
- data/lib/expressir/express/builders/syntax_builder.rb +19 -0
- data/lib/expressir/express/builders/token_builder.rb +15 -0
- data/lib/expressir/express/builders/type_builder.rb +264 -0
- data/lib/expressir/express/builders/type_decl_builder.rb +32 -0
- data/lib/expressir/express/builders/unique_clause_builder.rb +22 -0
- data/lib/expressir/express/builders/unique_rule_builder.rb +36 -0
- data/lib/expressir/express/builders/where_clause_builder.rb +22 -0
- data/lib/expressir/express/builders.rb +43 -0
- data/lib/expressir/express/error.rb +18 -2
- data/lib/expressir/express/formatter.rb +18 -1508
- data/lib/expressir/express/formatters/data_types_formatter.rb +317 -0
- data/lib/expressir/express/formatters/declarations_formatter.rb +689 -0
- data/lib/expressir/express/formatters/expressions_formatter.rb +160 -0
- data/lib/expressir/express/formatters/literals_formatter.rb +46 -0
- data/lib/expressir/express/formatters/references_formatter.rb +42 -0
- data/lib/expressir/express/formatters/remark_formatter.rb +296 -0
- data/lib/expressir/express/formatters/statements_formatter.rb +224 -0
- data/lib/expressir/express/formatters/supertype_expressions_formatter.rb +48 -0
- data/lib/expressir/express/parser.rb +129 -14
- data/lib/expressir/express/pretty_formatter.rb +624 -0
- data/lib/expressir/express/remark_attacher.rb +1155 -0
- data/lib/expressir/express/resolve_references_model_visitor.rb +1 -0
- data/lib/expressir/express/streaming_builder.rb +467 -0
- data/lib/expressir/express/transformer/remark_handling.rb +196 -0
- data/lib/expressir/model/identifier.rb +1 -1
- data/lib/expressir/model/model_element.rb +30 -2
- data/lib/expressir/model/remark_info.rb +51 -0
- data/lib/expressir/model/search_engine.rb +58 -9
- data/lib/expressir/version.rb +1 -1
- data/lib/expressir.rb +5 -1
- metadata +56 -7
- data/lib/expressir/express/visitor.rb +0 -2815
data/README.adoc
CHANGED
|
@@ -30,6 +30,132 @@ Expressir consists of 3 parts:
|
|
|
30
30
|
// ** OMG UML 2 for Eclipse (XMI 2.1)
|
|
31
31
|
|
|
32
32
|
|
|
33
|
+
== Features
|
|
34
|
+
|
|
35
|
+
=== Remark preservation
|
|
36
|
+
|
|
37
|
+
Expressir fully preserves EXPRESS remarks (comments) during parsing and formatting, maintaining them in their original positions:
|
|
38
|
+
|
|
39
|
+
==== Preamble remarks
|
|
40
|
+
|
|
41
|
+
Remarks between a scope declaration and its first child are preserved as preamble remarks:
|
|
42
|
+
|
|
43
|
+
[source,express]
|
|
44
|
+
----
|
|
45
|
+
SCHEMA example;
|
|
46
|
+
-- This is a preamble remark
|
|
47
|
+
-- It appears after SCHEMA but before declarations
|
|
48
|
+
|
|
49
|
+
ENTITY person;
|
|
50
|
+
-- Entity preamble remark
|
|
51
|
+
name : STRING;
|
|
52
|
+
END_ENTITY;
|
|
53
|
+
|
|
54
|
+
END_SCHEMA;
|
|
55
|
+
----
|
|
56
|
+
|
|
57
|
+
==== Inline tail remarks
|
|
58
|
+
|
|
59
|
+
Remarks on the same line as attribute or enumeration item declarations:
|
|
60
|
+
|
|
61
|
+
[source,express]
|
|
62
|
+
----
|
|
63
|
+
ENTITY person;
|
|
64
|
+
name : STRING; -- Inline remark for name attribute
|
|
65
|
+
age : INTEGER; -- Inline remark for age attribute
|
|
66
|
+
END_ENTITY;
|
|
67
|
+
|
|
68
|
+
TYPE status = ENUMERATION OF
|
|
69
|
+
(active, -- Active status
|
|
70
|
+
inactive, -- Inactive status
|
|
71
|
+
pending); -- Pending status
|
|
72
|
+
END_TYPE;
|
|
73
|
+
----
|
|
74
|
+
|
|
75
|
+
==== END_* scope remarks
|
|
76
|
+
|
|
77
|
+
Remarks on END_TYPE, END_ENTITY, END_SCHEMA, etc. lines:
|
|
78
|
+
|
|
79
|
+
[source,express]
|
|
80
|
+
----
|
|
81
|
+
TYPE status = ENUMERATION OF
|
|
82
|
+
(active,
|
|
83
|
+
inactive);
|
|
84
|
+
END_TYPE; -- Status enumeration type
|
|
85
|
+
|
|
86
|
+
ENTITY person;
|
|
87
|
+
name : STRING;
|
|
88
|
+
END_ENTITY; -- Person entity
|
|
89
|
+
|
|
90
|
+
END_SCHEMA; -- schema_name
|
|
91
|
+
----
|
|
92
|
+
|
|
93
|
+
==== Unicode support
|
|
94
|
+
|
|
95
|
+
All remark types support full Unicode content:
|
|
96
|
+
|
|
97
|
+
[source,express]
|
|
98
|
+
----
|
|
99
|
+
SCHEMA test;
|
|
100
|
+
-- 日本語、中文、한글 in remarks
|
|
101
|
+
|
|
102
|
+
ENTITY person;
|
|
103
|
+
name : STRING; -- Name in Japanese: 名前
|
|
104
|
+
END_ENTITY;
|
|
105
|
+
|
|
106
|
+
END_SCHEMA; -- test
|
|
107
|
+
----
|
|
108
|
+
|
|
109
|
+
For implementation details, see link:docs/ARCHITECTURE.md#remark-attachment-system[Remark Attachment System].
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
== Performance: Parsanol Integration
|
|
113
|
+
|
|
114
|
+
Expressir uses the link:https://github.com/parsanol/parsanol-ruby[Parsanol] gem for high-performance parsing when available.
|
|
115
|
+
|
|
116
|
+
=== Performance Comparison
|
|
117
|
+
|
|
118
|
+
[cols="3,2,2,3"]
|
|
119
|
+
|===
|
|
120
|
+
| Mode | Time | Speedup | Notes
|
|
121
|
+
|
|
122
|
+
| Ruby (Parsanol) | 3036 ms | 1x (baseline) | Pure Ruby parsing
|
|
123
|
+
| Native Batch (Parsanol) | 153 ms | 19.9x faster | AST via u64 array transfer
|
|
124
|
+
| Native ZeroCopy (Parsanol) | 106 ms | 28.7x faster | Zero-copy with source positions
|
|
125
|
+
|===
|
|
126
|
+
|
|
127
|
+
=== Features
|
|
128
|
+
|
|
129
|
+
When Parsanol is installed:
|
|
130
|
+
|
|
131
|
+
* **18-44x faster parsing** - Rust native backend
|
|
132
|
+
* **99.5% fewer allocations** - Arena-based AST construction
|
|
133
|
+
* **Source position tracking** - Slice objects for error reporting
|
|
134
|
+
* **Streaming Builder API** - Zero-allocation custom parsing
|
|
135
|
+
|
|
136
|
+
=== Usage
|
|
137
|
+
|
|
138
|
+
Expressir automatically uses Parsanol when available:
|
|
139
|
+
|
|
140
|
+
[source,ruby]
|
|
141
|
+
----
|
|
142
|
+
# Automatically uses Parsanol native parser when available
|
|
143
|
+
repo = Expressir::Express::Parser.from_file("geometry.exp")
|
|
144
|
+
|
|
145
|
+
# Check if native parser is being used
|
|
146
|
+
if Parsanol::Native.available?
|
|
147
|
+
puts "Using Parsanol (Rust parser)"
|
|
148
|
+
end
|
|
149
|
+
----
|
|
150
|
+
|
|
151
|
+
For maximum performance, ensure the Parsanol gem is installed:
|
|
152
|
+
|
|
153
|
+
[source,sh]
|
|
154
|
+
----
|
|
155
|
+
gem install parsanol
|
|
156
|
+
----
|
|
157
|
+
|
|
158
|
+
|
|
33
159
|
== Installation
|
|
34
160
|
|
|
35
161
|
Add this line to your application's `Gemfile`:
|
|
@@ -80,7 +206,7 @@ Commands:
|
|
|
80
206
|
expressir clean PATH # Strip remarks and prettify EXPRESS schema at PATH
|
|
81
207
|
expressir format PATH # pretty print EXPRESS schema located at PATH
|
|
82
208
|
expressir help [COMMAND] # Describe available commands or one specific command
|
|
83
|
-
expressir validate *PATH
|
|
209
|
+
expressir validate load *PATH # validate EXPRESS schema located at PATH
|
|
84
210
|
expressir validate ascii PATH # Validate EXPRESS files for ASCII-only content (excluding remarks)
|
|
85
211
|
expressir coverage *PATH # List EXPRESS entities and check documentation coverage
|
|
86
212
|
expressir version # Expressir Version
|
|
@@ -103,6 +229,251 @@ This command:
|
|
|
103
229
|
. Formats it with consistent indentation and spacing
|
|
104
230
|
. Outputs the formatted schema to stdout
|
|
105
231
|
|
|
232
|
+
=== Pretty print with ELF compliance
|
|
233
|
+
|
|
234
|
+
The `PrettyFormatter` class provides ELF (EXPRESS Language Foundation) compliant
|
|
235
|
+
pretty printing with configurable formatting options. This formatter follows the
|
|
236
|
+
https://www.express-language-foundation.org/pretty-print-spec/[ELF Pretty Print specification].
|
|
237
|
+
|
|
238
|
+
==== Using PrettyFormatter in Ruby
|
|
239
|
+
|
|
240
|
+
[source,ruby]
|
|
241
|
+
----
|
|
242
|
+
# Basic usage - formats with default settings
|
|
243
|
+
repository = Expressir::Express::Parser.from_file("schema.exp")
|
|
244
|
+
formatter = Expressir::Express::PrettyFormatter.new
|
|
245
|
+
formatted = formatter.format(repository)
|
|
246
|
+
puts formatted
|
|
247
|
+
----
|
|
248
|
+
|
|
249
|
+
==== Configuration options
|
|
250
|
+
|
|
251
|
+
The PrettyFormatter supports several configuration options to customize the output.
|
|
252
|
+
|
|
253
|
+
[source,ruby]
|
|
254
|
+
----
|
|
255
|
+
formatter = Expressir::Express::PrettyFormatter.new(
|
|
256
|
+
indent: 4, # Spaces per indentation level (default: 4)
|
|
257
|
+
line_length: 80, # Maximum line length (default: nil)
|
|
258
|
+
provenance: true, # Include provenance info (default: true)
|
|
259
|
+
provenance_name: "MyTool", # Tool name (default: "Expressir")
|
|
260
|
+
provenance_version: "1.0.0", # Tool version (default: Expressir::VERSION)
|
|
261
|
+
no_remarks: false # Suppress remarks (default: false)
|
|
262
|
+
)
|
|
263
|
+
----
|
|
264
|
+
|
|
265
|
+
[options="header"]
|
|
266
|
+
|===
|
|
267
|
+
| Option | Type | Default | Description
|
|
268
|
+
|
|
269
|
+
| `indent`
|
|
270
|
+
| Integer
|
|
271
|
+
| `4`
|
|
272
|
+
| Number of spaces per indentation level
|
|
273
|
+
|
|
274
|
+
| `line_length`
|
|
275
|
+
| Integer or nil
|
|
276
|
+
| `nil`
|
|
277
|
+
| Maximum line length (not yet enforced)
|
|
278
|
+
|
|
279
|
+
| `provenance`
|
|
280
|
+
| Boolean
|
|
281
|
+
| `true`
|
|
282
|
+
| Include provenance information in output
|
|
283
|
+
|
|
284
|
+
| `provenance_name`
|
|
285
|
+
| String
|
|
286
|
+
| `"Expressir"`
|
|
287
|
+
| Tool name for provenance
|
|
288
|
+
|
|
289
|
+
| `provenance_version`
|
|
290
|
+
| String
|
|
291
|
+
| `Expressir::VERSION`
|
|
292
|
+
| Tool version for provenance
|
|
293
|
+
|
|
294
|
+
| `no_remarks`
|
|
295
|
+
| Boolean
|
|
296
|
+
| `false`
|
|
297
|
+
| Suppress remarks from source schema
|
|
298
|
+
|===
|
|
299
|
+
|
|
300
|
+
==== Environment variable configuration
|
|
301
|
+
|
|
302
|
+
Configuration can be overridden using environment variables. Environment variables
|
|
303
|
+
take precedence over defaults but are overridden by explicit options:
|
|
304
|
+
|
|
305
|
+
[source,sh]
|
|
306
|
+
----
|
|
307
|
+
# Set environment variables
|
|
308
|
+
export EXPRESSIR_INDENT=2
|
|
309
|
+
export EXPRESSIR_LINE_LENGTH=100
|
|
310
|
+
export EXPRESSIR_PROVENANCE=false
|
|
311
|
+
export EXPRESSIR_PROVENANCE_NAME="CustomTool"
|
|
312
|
+
export EXPRESSIR_PROVENANCE_VERSION="2.0.0"
|
|
313
|
+
|
|
314
|
+
# These will be used unless overridden by options
|
|
315
|
+
ruby my_formatter.rb
|
|
316
|
+
----
|
|
317
|
+
|
|
318
|
+
[options="header"]
|
|
319
|
+
|===
|
|
320
|
+
| Environment Variable | Description
|
|
321
|
+
|
|
322
|
+
| `EXPRESSIR_INDENT`
|
|
323
|
+
| Indentation width (spaces)
|
|
324
|
+
|
|
325
|
+
| `EXPRESSIR_LINE_LENGTH`
|
|
326
|
+
| Maximum line length
|
|
327
|
+
|
|
328
|
+
| `EXPRESSIR_PROVENANCE`
|
|
329
|
+
| Enable/disable provenance (`true`/`false`)
|
|
330
|
+
|
|
331
|
+
| `EXPRESSIR_PROVENANCE_NAME`
|
|
332
|
+
| Tool name for provenance
|
|
333
|
+
|
|
334
|
+
| `EXPRESSIR_PROVENANCE_VERSION`
|
|
335
|
+
| Tool version for provenance
|
|
336
|
+
|===
|
|
337
|
+
|
|
338
|
+
The configuration follows a MECE (Mutually Exclusive, Collectively Exhaustive)
|
|
339
|
+
hierarchy: **Options > ENV > Defaults**
|
|
340
|
+
|
|
341
|
+
==== Key features
|
|
342
|
+
|
|
343
|
+
The PrettyFormatter provides several enhancements over the standard formatter:
|
|
344
|
+
|
|
345
|
+
CONSTANT alignment:: Constants in CONSTANT blocks are aligned at both the colon
|
|
346
|
+
and assignment operator positions for improved readability.
|
|
347
|
+
+
|
|
348
|
+
[example]
|
|
349
|
+
====
|
|
350
|
+
[source]
|
|
351
|
+
----
|
|
352
|
+
CONSTANT
|
|
353
|
+
short_name : INTEGER := 1;
|
|
354
|
+
longer_name : STRING := 'test';
|
|
355
|
+
x : REAL := 3.14;
|
|
356
|
+
END_CONSTANT;
|
|
357
|
+
----
|
|
358
|
+
====
|
|
359
|
+
|
|
360
|
+
Provenance information:: Automatically includes metadata about the formatting
|
|
361
|
+
tool and parameters used, aiding in reproducibility.
|
|
362
|
+
+
|
|
363
|
+
[example]
|
|
364
|
+
====
|
|
365
|
+
[source]
|
|
366
|
+
----
|
|
367
|
+
(*
|
|
368
|
+
Generated by: Expressir version 2.1.31
|
|
369
|
+
Format parameters: indent: 4
|
|
370
|
+
*)
|
|
371
|
+
----
|
|
372
|
+
====
|
|
373
|
+
|
|
374
|
+
Configurable indentation:: Supports custom indentation width (2, 4, 8 spaces, etc.)
|
|
375
|
+
to match project coding standards.
|
|
376
|
+
|
|
377
|
+
Preamble support:: Preserves and formats source-level remarks that appear before
|
|
378
|
+
the first SCHEMA declaration.
|
|
379
|
+
|
|
380
|
+
==== Comparison with standard Formatter
|
|
381
|
+
|
|
382
|
+
[options="header"]
|
|
383
|
+
|===
|
|
384
|
+
| Feature | Formatter | PrettyFormatter
|
|
385
|
+
|
|
386
|
+
| Indentation
|
|
387
|
+
| 2 spaces (fixed)
|
|
388
|
+
| Configurable (default: 4)
|
|
389
|
+
|
|
390
|
+
| CONSTANT alignment
|
|
391
|
+
| No
|
|
392
|
+
| Yes (colons and assignments)
|
|
393
|
+
|
|
394
|
+
| Provenance
|
|
395
|
+
| No
|
|
396
|
+
| Yes (configurable)
|
|
397
|
+
|
|
398
|
+
| Preamble formatting
|
|
399
|
+
| No
|
|
400
|
+
| Yes
|
|
401
|
+
|
|
402
|
+
| Line length enforcement
|
|
403
|
+
| No
|
|
404
|
+
| Planned (not yet implemented)
|
|
405
|
+
|
|
406
|
+
| ELF compliant
|
|
407
|
+
| No
|
|
408
|
+
| Yes
|
|
409
|
+
|
|
410
|
+
| Configuration via ENV
|
|
411
|
+
| No
|
|
412
|
+
| Yes
|
|
413
|
+
|===
|
|
414
|
+
|
|
415
|
+
==== Example usage
|
|
416
|
+
|
|
417
|
+
.Formatting with custom settings
|
|
418
|
+
[example]
|
|
419
|
+
====
|
|
420
|
+
[source,ruby]
|
|
421
|
+
----
|
|
422
|
+
# Parse schema
|
|
423
|
+
repository = Expressir::Express::Parser.from_file("examples/ler/simple_schema.exp")
|
|
424
|
+
|
|
425
|
+
# Format with custom indentation and provenance
|
|
426
|
+
formatter = Expressir::Express::PrettyFormatter.new(
|
|
427
|
+
indent: 2,
|
|
428
|
+
provenance_name: "MyFormatter",
|
|
429
|
+
provenance_version: "1.0.0"
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
formatted = formatter.format(repository)
|
|
433
|
+
|
|
434
|
+
# Save to file
|
|
435
|
+
File.write("formatted_schema.exp", formatted)
|
|
436
|
+
----
|
|
437
|
+
====
|
|
438
|
+
|
|
439
|
+
.Formatting without provenance
|
|
440
|
+
[example]
|
|
441
|
+
====
|
|
442
|
+
[source,ruby]
|
|
443
|
+
----
|
|
444
|
+
# Format without provenance information
|
|
445
|
+
formatter = Expressir::Express::PrettyFormatter.new(provenance: false)
|
|
446
|
+
repository = Expressir::Express::Parser.from_file("schema.exp")
|
|
447
|
+
formatted = formatter.format(repository)
|
|
448
|
+
|
|
449
|
+
# Output is clean without metadata comments
|
|
450
|
+
puts formatted
|
|
451
|
+
----
|
|
452
|
+
====
|
|
453
|
+
|
|
454
|
+
.Round-trip formatting verification
|
|
455
|
+
[example]
|
|
456
|
+
====
|
|
457
|
+
[source,ruby]
|
|
458
|
+
----
|
|
459
|
+
# Format a schema
|
|
460
|
+
original = Expressir::Express::Parser.from_file("schema.exp")
|
|
461
|
+
formatter = Expressir::Express::PrettyFormatter.new
|
|
462
|
+
|
|
463
|
+
# Format once
|
|
464
|
+
formatted1 = formatter.format(original)
|
|
465
|
+
|
|
466
|
+
# Parse the formatted output
|
|
467
|
+
File.write("temp.exp", formatted1)
|
|
468
|
+
reparsed = Expressir::Express::Parser.from_file("temp.exp")
|
|
469
|
+
|
|
470
|
+
# Format again - should be identical (stable formatting)
|
|
471
|
+
formatted2 = formatter.format(reparsed)
|
|
472
|
+
|
|
473
|
+
puts "Formatting is stable" if formatted1 == formatted2
|
|
474
|
+
----
|
|
475
|
+
====
|
|
476
|
+
|
|
106
477
|
=== Clean schema
|
|
107
478
|
|
|
108
479
|
The `clean` command strips remarks and prettifies EXPRESS schemas. This is
|