expressir 2.4.31-x86_64-linux → 2.4.36-x86_64-linux

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.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/conformance.yml +34 -0
  3. data/.gitignore +3 -0
  4. data/Gemfile +1 -1
  5. data/TODO.eengine/00-overview.md +39 -0
  6. data/TODO.eengine/01-resolution-diagnostics.md +30 -0
  7. data/TODO.eengine/02-check-catalog-completion.md +53 -0
  8. data/TODO.eengine/03-entity-computations.md +22 -0
  9. data/TODO.eengine/04-shtolo-rule-audit.md +32 -0
  10. data/TODO.eengine/05-shtolo-longform-flatten.md +12 -0
  11. data/TODO.eengine/06-population-p21.md +34 -0
  12. data/TODO.eengine/07-schema-compare-patch.md +25 -0
  13. data/TODO.eengine/08-official-corpus-gate.md +7 -0
  14. data/TODO.eengine/09-mim-mapping-parser.md +9 -0
  15. data/TODO.parity-ee/00-overview.md +1 -1
  16. data/TODO.sota/00-overview.md +57 -0
  17. data/TODO.sota/01-type-checking.md +115 -0
  18. data/TODO.sota/02-evaluator.md +86 -0
  19. data/TODO.sota/03-conformance.md +53 -0
  20. data/TODO.sota/04-lsp.md +70 -0
  21. data/TODO.sota/05-interop.md +55 -0
  22. data/TODO.sota/06-dialects.md +57 -0
  23. data/TODO.sota/07-reference-artifacts.md +55 -0
  24. data/TODO.suma-improvements/07-part28-xml.md +10 -13
  25. data/docs/_guides/interop/index.adoc +25 -0
  26. data/docs/_guides/interop/json-schema.adoc +88 -0
  27. data/docs/_guides/interop/owl-rdf.adoc +87 -0
  28. data/docs/_guides/reference/checker-notes.adoc +55 -0
  29. data/docs/_guides/reference/checker.adoc +36 -0
  30. data/docs/_guides/reference/evaluator.adoc +40 -0
  31. data/docs/_guides/reference/grammar-crosswalk.adoc +299 -0
  32. data/docs/_guides/reference/index.adoc +22 -0
  33. data/docs/_guides/reference/lsp.adoc +41 -0
  34. data/docs/_guides/reference/p21.adoc +30 -0
  35. data/docs/_guides/reference/shtolo.adoc +36 -0
  36. data/exe/expressir-lsp +6 -0
  37. data/expressir.gemspec +2 -2
  38. data/lib/expressir/3.2/expressir_core.so +0 -0
  39. data/lib/expressir/3.3/expressir_core.so +0 -0
  40. data/lib/expressir/3.4/expressir_core.so +0 -0
  41. data/lib/expressir/4.0/expressir_core.so +0 -0
  42. data/lib/expressir/cli.rb +25 -0
  43. data/lib/expressir/commands/check.rb +3 -1
  44. data/lib/expressir/commands/export_json_schema.rb +29 -0
  45. data/lib/expressir/commands/export_owl.rb +26 -0
  46. data/lib/expressir/commands/smrl_xml_index.rb +25 -0
  47. data/lib/expressir/commands/validate.rb +3 -0
  48. data/lib/expressir/commands.rb +3 -0
  49. data/lib/expressir/conformance/trend.rb +100 -0
  50. data/lib/expressir/conformance.rb +8 -0
  51. data/lib/expressir/eval/environment.rb +83 -0
  52. data/lib/expressir/eval/expression.rb +610 -0
  53. data/lib/expressir/eval/interpreter.rb +316 -0
  54. data/lib/expressir/eval/rules.rb +88 -0
  55. data/lib/expressir/eval/values.rb +74 -0
  56. data/lib/expressir/eval.rb +17 -0
  57. data/lib/expressir/express/builder.rb +17 -5
  58. data/lib/expressir/express/builders/entity_decl_builder.rb +17 -5
  59. data/lib/expressir/express/builders/expression_builder.rb +9 -1
  60. data/lib/expressir/express/checker.rb +970 -5
  61. data/lib/expressir/express/dialect.rb +44 -0
  62. data/lib/expressir/express/formatters/declarations_formatter.rb +21 -14
  63. data/lib/expressir/express/formatters/expressions_formatter.rb +4 -1
  64. data/lib/expressir/express/parser.rb +9 -4
  65. data/lib/expressir/express/pretty_formatter.rb +9 -14
  66. data/lib/expressir/express/schema_compare.rb +194 -0
  67. data/lib/expressir/express/shtolo.rb +194 -63
  68. data/lib/expressir/express.rb +3 -0
  69. data/lib/expressir/interop/json_schema.rb +195 -0
  70. data/lib/expressir/interop/owl.rb +216 -0
  71. data/lib/expressir/interop.rb +13 -0
  72. data/lib/expressir/lsp/document.rb +226 -0
  73. data/lib/expressir/lsp/server.rb +184 -0
  74. data/lib/expressir/lsp/workspace.rb +402 -0
  75. data/lib/expressir/lsp.rb +11 -0
  76. data/lib/expressir/model/declarations/entity.rb +132 -0
  77. data/lib/expressir/model/declarations/schema.rb +37 -6
  78. data/lib/expressir/p21/builder.rb +92 -0
  79. data/lib/expressir/p21/grammar.rb +107 -0
  80. data/lib/expressir/p21/parser.rb +16 -0
  81. data/lib/expressir/p21/population.rb +35 -0
  82. data/lib/expressir/p21/validator.rb +213 -0
  83. data/lib/expressir/p21.rb +17 -0
  84. data/lib/expressir/reference/grammar_crosswalk.rb +122 -0
  85. data/lib/expressir/reference/grammar_crosswalk.yml +800 -0
  86. data/lib/expressir/reference/note_catalog.rb +54 -0
  87. data/lib/expressir/reference.rb +10 -0
  88. data/lib/expressir/version.rb +1 -1
  89. data/lib/expressir.rb +5 -0
  90. data/lib/tasks/conformance.rake +27 -0
  91. data/lib/tasks/reference.rake +25 -0
  92. metadata +68 -4
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module Expressir
6
+ module Conformance
7
+ # Trended property metrics over a corpus slice: parse rate and
8
+ # format idempotence rate are fractions; the diagnostic rate is the
9
+ # number of Checker notes per parsed file. Per-note-id counts make
10
+ # the report actionable. Published by the nightly conformance
11
+ # workflow as a JSON artifact so the numbers can be trended.
12
+ class Trend
13
+ def self.measure(files)
14
+ report = {
15
+ "files" => files.size,
16
+ "parsed" => 0,
17
+ "parse_failed" => 0,
18
+ "measurement_failed" => 0,
19
+ "idempotent" => 0,
20
+ "not_idempotent" => 0,
21
+ "notes" => 0,
22
+ "errors" => 0,
23
+ "warnings" => 0,
24
+ "note_ids" => {},
25
+ }
26
+ files.each do |path|
27
+ measure_file(path, report)
28
+ end
29
+ report.merge!(
30
+ "parse_rate" => rate(report["parsed"], report["files"]),
31
+ "idempotence_rate" => rate(report["idempotent"], report["parsed"]),
32
+ "diagnostic_rate" => rate(report["notes"], report["parsed"]),
33
+ )
34
+ report
35
+ end
36
+
37
+ def self.run(files, output:)
38
+ report = measure(files)
39
+ File.write(output, "#{JSON.pretty_generate(report)}\n")
40
+ report
41
+ end
42
+
43
+ def self.measure_file(path, report)
44
+ repository = parse_file(path)
45
+ unless repository
46
+ report["parse_failed"] += 1
47
+ return
48
+ end
49
+ report["parsed"] += 1
50
+ measure_properties(repository, report)
51
+ end
52
+ private_class_method :measure_file
53
+
54
+ def self.parse_file(path)
55
+ Expressir::Express::Parser.from_exp(File.read(path))
56
+ rescue StandardError
57
+ nil
58
+ end
59
+ private_class_method :parse_file
60
+
61
+ def self.measure_properties(repository, report)
62
+ schema = Array(repository.schemas).first
63
+ if schema && idempotent?(schema)
64
+ report["idempotent"] += 1
65
+ else
66
+ report["not_idempotent"] += 1
67
+ end
68
+ notes = Expressir::Express::Checker.new(
69
+ Expressir::Model::Repository.new(files: [repository]),
70
+ ).check.notes
71
+ report["notes"] += notes.size
72
+ notes.each do |note|
73
+ report[note.severity == :error ? "errors" : "warnings"] += 1
74
+ report["note_ids"][note.id.to_s] =
75
+ report["note_ids"].fetch(note.id.to_s, 0) + 1
76
+ end
77
+ rescue StandardError
78
+ report["measurement_failed"] += 1
79
+ end
80
+ private_class_method :measure_properties
81
+
82
+ def self.idempotent?(schema)
83
+ once = Expressir::Express::Formatter.format(schema)
84
+ reparsed = Expressir::Express::Parser.from_exp(once)
85
+ twice = Expressir::Express::Formatter.format(reparsed.schemas.first)
86
+ once == twice
87
+ rescue StandardError
88
+ false
89
+ end
90
+ private_class_method :idempotent?
91
+
92
+ def self.rate(numerator, denominator)
93
+ return 0.0 if denominator.zero?
94
+
95
+ (numerator.to_f / denominator).round(4)
96
+ end
97
+ private_class_method :rate
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Expressir
4
+ # Measurement tiers over the standards corpus (TODO.sota/07 part 2).
5
+ module Conformance
6
+ autoload :Trend, "#{__dir__}/conformance/trend"
7
+ end
8
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Expressir
4
+ module Eval
5
+ # Lexical scope chain: a name resolves to a value through the
6
+ # innermost scope that declares it. The schema provides type
7
+ # context; the population (step 3) provides instances for the
8
+ # instance-aware builtins.
9
+ class Environment
10
+ attr_reader :schema, :population
11
+
12
+ def initialize(schema:, population: nil, frames: [{}])
13
+ @schema = schema
14
+ @population = population
15
+ @frames = frames
16
+ end
17
+
18
+ def push(frame)
19
+ Environment.new(schema: @schema, population: @population,
20
+ frames: @frames + [frame])
21
+ end
22
+
23
+ def define(name, value)
24
+ frame = @frames.last.dup
25
+ frame[name.safe_downcase] = value
26
+ Environment.new(schema: @schema, population: @population,
27
+ frames: @frames[0..-2] + [frame])
28
+ end
29
+
30
+ def lookup(name)
31
+ key = name.safe_downcase
32
+ @frames.reverse_each do |frame|
33
+ return frame[key] if frame.key?(key)
34
+ end
35
+ nil
36
+ end
37
+
38
+ def bound?(name)
39
+ !lookup(name).nil? || @frames.any? { |f| f.key?(name.safe_downcase) }
40
+ end
41
+
42
+ def interpreter
43
+ @interpreter ||= Interpreter.new(schema: @schema,
44
+ population: @population)
45
+ end
46
+
47
+ # Part 21 attribute slots for an entity: inherited explicit
48
+ # attributes (supertype closure order) then the entity's own —
49
+ # the same order the P21 validator maps values by.
50
+ def slots_for(entity)
51
+ @slots ||= {}
52
+ @slots[entity] ||= begin
53
+ inherited = entity.supertype_closure.flat_map do |supertype|
54
+ explicit_attributes(supertype)
55
+ end
56
+ (inherited + explicit_attributes(entity)).each_with_index
57
+ .to_h do |attribute, index|
58
+ [attribute.id&.safe_downcase, index]
59
+ end
60
+ end
61
+ end
62
+
63
+ def explicit_attributes(entity)
64
+ Array(entity.attributes)
65
+ .select { |a| a.instance_of?(Model::Declarations::Attribute) }
66
+ end
67
+
68
+ def entity_for_keyword(keyword)
69
+ Array(@schema&.entities).find do |entity|
70
+ entity.id&.safe_downcase == keyword&.safe_downcase
71
+ end
72
+ end
73
+
74
+ def instance_for(reference)
75
+ return nil unless @population && reference.is_a?(String)
76
+ return nil unless reference.start_with?("#")
77
+
78
+ record = @population.instances[reference]
79
+ record && Values::Instance.new(id: reference[1..], record: record)
80
+ end
81
+ end
82
+ end
83
+ end