expressir 2.4.18 → 2.4.19

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 71c43838ba6c2853f84bfa1faca26760abe4919d35b98895ef224866bd49da62
4
- data.tar.gz: 715a55be95f4ead656b98e0df59ccf06c2036eb532d6990a8ea036ee5f0f78c4
3
+ metadata.gz: a5174add01b6b7053e2317d479e746ba330901c6bdc547d5ba7429ea46889ae3
4
+ data.tar.gz: 66bd27f4a626a956e840f90013bbe5ce7dc6817f127c554bccf5cb413cbd2981
5
5
  SHA512:
6
- metadata.gz: dac93ad5688fc8e2d3814fd6933b352ea35d78b89f157e99f30114ddafb07b53aaeb80aaa45fd63540a9ee400ac1aacc3724800446f868472499d9d4cf501629
7
- data.tar.gz: 12cd7ef87afa0510215d0c1315e68ba5bbaed5a910255ebfa40e18b328b25f87ef3a24f93ce1073a798ce0e748e6344861f05900f863377ed801d9f1f66e7bab
6
+ metadata.gz: 6aa415b0bd88d3cf5bd95d3786b01dff6f66e00e13ca95a3a19755f1e60cc17163800841fd9f7ea21d98acee505c0b67ae1ef6a3e3e032394cfb848395b1295d
7
+ data.tar.gz: ce39ba436ff04bf239e16744625c2e989b75db1674ffed24314d9fb75ae393e0f3b9ca8f0ab9263a47cd79572807e958f29ebfcedc88c42f00e886c9dd75a14f
@@ -64,7 +64,7 @@ module Expressir
64
64
 
65
65
  TOKEN = /->|<-|<=|=>|[{}\[\]()=:|!,*\/]|'(?:''|[^'])*'|\w+(?:\.\w+)?/
66
66
  MARKERS = ["{", "}", "[", "]", "(", ")", ":", "|", "!", ",", "/",
67
- "*"].freeze
67
+ "*", "MAPPING_OF"].freeze
68
68
  LINKS = ["->", "<-", "<=", "=>"].freeze
69
69
  DECLARATION_COLLECTIONS = %i[types entities].freeze
70
70
  private_constant :TOKEN, :MARKERS, :LINKS, :DECLARATION_COLLECTIONS
@@ -111,17 +111,11 @@ module Expressir
111
111
  steps << Step.new(operator: token)
112
112
  else
113
113
  name, _, attribute = token.partition(".")
114
- if name.casecmp("MAPPING_OF").zero? && tokens[i + 1] == "("
115
- # notation wrapper: /MAPPING_OF(X)/ refers to X; the
116
- # wrapper itself carries no node semantics
117
- steps << Step.new(operator: token)
118
- else
119
- operator = pending_link || ("=" if pending_type_assign)
120
- steps << Step.new(operator: operator, name: name,
121
- attribute: attribute.empty? ? nil : attribute)
122
- pending_link = nil
123
- pending_type_assign = false
124
- end
114
+ operator = pending_link || ("=" if pending_type_assign)
115
+ steps << Step.new(operator: operator, name: name,
116
+ attribute: attribute.empty? ? nil : attribute)
117
+ pending_link = nil
118
+ pending_type_assign = false
125
119
  end
126
120
  i += 1
127
121
  end
@@ -153,34 +147,40 @@ module Expressir
153
147
  by_name = name_index(repository)
154
148
  issues = []
155
149
  prev = nil
150
+ last_qualified = nil
156
151
  path.steps.each_with_index do |step, pos|
157
- if MARKERS.include?(step.operator)
158
- prev = nil
159
- next
160
- end
152
+ # markers never break the running link, mirroring parse
153
+ next if MARKERS.include?(step.operator)
161
154
 
162
- issues.concat(check_step(step, pos, prev, by_name))
155
+ issues.concat(check_step(step, pos, prev, last_qualified, by_name))
163
156
  prev = step if step.name
157
+ last_qualified = step if step.name && step.attribute
164
158
  end
165
159
  issues
166
160
  end
167
161
 
162
+ EXPRESS_BUILTINS = %w[NUMBER INTEGER REAL STRING BOOLEAN LOGICAL
163
+ BINARY].freeze
164
+ private_constant :EXPRESS_BUILTINS
165
+
168
166
  def name_index(repository)
167
+ index = EXPRESS_BUILTINS.to_h { |b| [b.downcase, [nil, nil]] }
169
168
  repository.schemas.flat_map do |schema|
170
169
  DECLARATION_COLLECTIONS.flat_map do |coll|
171
170
  Array(schema.public_send(coll))
172
171
  .select { |d| d.respond_to?(:id) && d.id }
173
172
  .map { |d| [d.id.safe_downcase, [schema, d]] }
174
173
  end
175
- end.to_h
174
+ end.each { |pair| index[pair[0]] = pair[1] }
175
+ index
176
176
  end
177
177
 
178
- def check_step(step, pos, prev, by_name)
178
+ def check_step(step, pos, prev, last_qualified, by_name)
179
179
  found = by_name[step.name&.safe_downcase]
180
180
  return [Issue.new(step: pos, message: "unknown type '#{step.name}'")] unless found
181
181
 
182
182
  issues = attribute_issues(step, pos, found[1], by_name)
183
- issues.concat(link_issues(step, pos, prev, by_name))
183
+ issues.concat(link_issues(step, pos, prev, last_qualified, by_name))
184
184
  issues
185
185
  end
186
186
 
@@ -239,7 +239,7 @@ module Expressir
239
239
  "aggregate but carries [#{step.index}]")]
240
240
  end
241
241
 
242
- def link_issues(step, pos, prev, by_name)
242
+ def link_issues(step, pos, prev, last_qualified, by_name)
243
243
  return [] unless LINKS.include?(step.operator)
244
244
  unless prev && step.name
245
245
  return [Issue.new(step: pos,
@@ -247,20 +247,39 @@ module Expressir
247
247
  end
248
248
 
249
249
  case step.operator
250
- when "->", "<-" then attribute_link_issues(step, pos, prev)
250
+ when "->", "<-"
251
+ attribute_link_issues(step, pos, prev, last_qualified)
251
252
  when "<=" then subtype_link_issues(step, pos, prev, by_name)
252
253
  when "=>" then supertype_link_issues(step, pos, prev, by_name)
253
254
  end
254
255
  end
255
256
 
256
- def attribute_link_issues(_step, pos, prev)
257
- unless prev.attribute
258
- return [Issue.new(step: pos,
259
- message: "'->' requires an attribute-qualified " \
260
- "node before it, got '#{prev.name}'")]
257
+ # `->`: the attribute-qualified node precedes the operator;
258
+ # `<-`: it follows (the entity before <- is referenced BY the
259
+ # attribute after it). An aggregate dereference `[i]` keeps the
260
+ # running attribute owner qualified for the next link
261
+ # (`attr -> list_type[i] -> element_type`).
262
+ def attribute_link_issues(step, pos, prev, last_qualified)
263
+ if step.operator == "->"
264
+ qualified = if prev&.attribute
265
+ prev
266
+ else
267
+ (prev&.index ? last_qualified : nil)
268
+ end
269
+ unless qualified&.attribute
270
+ return [Issue.new(step: pos,
271
+ message: "'->' requires an attribute-qualified " \
272
+ "node before it, got '#{prev&.name}'")]
273
+ end
274
+
275
+ return []
261
276
  end
262
277
 
263
- []
278
+ return [] if step.attribute
279
+
280
+ [Issue.new(step: pos,
281
+ message: "'<-' requires an attribute-qualified node " \
282
+ "after it, got '#{step.name}'")]
264
283
  end
265
284
 
266
285
  # `a <= b`: a is a subtype of b.
@@ -3,6 +3,6 @@ module Expressir
3
3
  # autoload it (Ruby autoload only works for module/class constants, not
4
4
  # for string constants like `Expressir::VERSION`).
5
5
  module Version
6
- VERSION = "2.4.18".freeze
6
+ VERSION = "2.4.19".freeze
7
7
  end
8
8
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: expressir
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.18
4
+ version: 2.4.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.