Class: Ibex::TableArtifact::MetadataValidator
- Inherits:
-
Object
- Object
- Ibex::TableArtifact::MetadataValidator
show all
- Includes:
- ValidationSupport
- Defined in:
- lib/ibex/table_artifact/validator/metadata.rb,
sig/ibex/table_artifact/validator/metadata.rbs
Constant Summary
ValidationSupport::DIGEST
Instance Method Summary
collapse
-
#ids_for_kind(symbols, kind) ⇒ Set[Integer]
-
#initialize(payload, symbols:, productions:) ⇒ MetadataValidator
constructor
A new instance of MetadataValidator.
-
#integer_ids(data, path, sorted: true) ⇒ Array[Integer]
-
#validate! ⇒ void
-
#validate_cst(data) ⇒ void
-
#validate_cst_kinds(data, path) ⇒ Integer
-
#validate_cst_slots(data, path, kind_count) ⇒ void
-
#validate_fields(data, path, production) ⇒ void
-
#validate_named_kinds(data, path, names) ⇒ void
-
#validate_named_nonterminals(data, path, kind_count) ⇒ void
-
#validate_range(data, path, limit) ⇒ void
-
#validate_recovery(data) ⇒ void
-
#validate_semantic_actions(data) ⇒ void
#array, #boolean, #digest, #enum, #integer, #invalid, #nullable_integer, #nullable_string, #record, #sorted_unique!, #string
Constructor Details
#initialize(payload, symbols:, productions:) ⇒ MetadataValidator
Returns a new instance of MetadataValidator.
10
11
12
13
14
15
16
|
# File 'lib/ibex/table_artifact/validator/metadata.rb', line 10
def initialize(payload, symbols:, productions:)
@payload = payload
@symbols = symbols
@productions = productions
@terminal_ids = ids_for_kind(symbols, "terminal")
@nonterminal_ids = ids_for_kind(symbols, "nonterminal")
end
|
Instance Method Details
#ids_for_kind(symbols, kind) ⇒ Set[Integer]
28
29
30
31
32
33
34
|
# File 'lib/ibex/table_artifact/validator/metadata.rb', line 28
def ids_for_kind(symbols, kind)
symbols.filter_map do |symbol|
next unless symbol.fetch("kind") == kind
symbol.fetch("id") end.to_set
end
|
#integer_ids(data, path, sorted: true) ⇒ Array[Integer]
168
169
170
171
172
173
174
175
176
|
# File 'lib/ibex/table_artifact/validator/metadata.rb', line 168
def integer_ids(data, path, sorted: true)
ids = array(data, path).map.with_index { |id, index| integer(id, "#{path}[#{index}]", minimum: 0) }
if sorted
sorted_unique!(ids, path)
else
invalid(path, "must contain unique ids") unless ids.uniq.length == ids.length
end
ids
end
|
#validate! ⇒ void
This method returns an undefined value.
19
20
21
22
23
|
# File 'lib/ibex/table_artifact/validator/metadata.rb', line 19
def validate!
validate_semantic_actions(@payload.fetch("semantic_actions"))
validate_recovery(@payload.fetch("recovery"))
validate_cst(@payload.fetch("cst"))
end
|
#validate_cst(data) ⇒ void
This method returns an undefined value.
67
68
69
70
71
72
73
74
75
76
|
# File 'lib/ibex/table_artifact/validator/metadata.rb', line 67
def validate_cst(data)
return if data.nil?
path = "$.payload.cst"
data = record(data, path, %w[version trivia_policy kinds slots])
invalid("#{path}.version", "must be 1") unless integer(data.fetch("version"), "#{path}.version") == 1
enum(data.fetch("trivia_policy"), "#{path}.trivia_policy", %w[leading balanced drop])
kind_count = validate_cst_kinds(data.fetch("kinds"), "#{path}.kinds")
validate_cst_slots(data.fetch("slots"), "#{path}.slots", kind_count)
end
|
#validate_cst_kinds(data, path) ⇒ Integer
79
80
81
82
83
84
85
86
87
88
89
|
# File 'lib/ibex/table_artifact/validator/metadata.rb', line 79
def validate_cst_kinds(data, path)
keys = %w[names terminal_range nonterminal_range named named_nonterminals trivia synthetic]
data = record(data, path, keys)
names = array(data.fetch("names"), "#{path}.names") names.each_with_index { |name, index| string(name, "#{path}.names[#{index}]") }
validate_range(data.fetch("terminal_range"), "#{path}.terminal_range", names.length)
validate_range(data.fetch("nonterminal_range"), "#{path}.nonterminal_range", names.length)
%w[named trivia synthetic].each { |key| validate_named_kinds(data.fetch(key), "#{path}.#{key}", names) }
validate_named_nonterminals(data.fetch("named_nonterminals"), "#{path}.named_nonterminals", names.length)
names.length
end
|
#validate_cst_slots(data, path, kind_count) ⇒ void
This method returns an undefined value.
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
# File 'lib/ibex/table_artifact/validator/metadata.rb', line 132
def validate_cst_slots(data, path, kind_count)
production_ids = array(data, path).map.with_index do |slot, index|
slot_path = "#{path}[#{index}]"
slot = record(slot, slot_path, %w[production_id node_kind_id node_name fields])
production_id = integer(slot.fetch("production_id"), "#{slot_path}.production_id", minimum: 0)
unless production_id < @productions.length
invalid("#{slot_path}.production_id",
"references a missing production")
end
node_kind = integer(slot.fetch("node_kind_id"), "#{slot_path}.node_kind_id", minimum: 0)
invalid("#{slot_path}.node_kind_id", "references a missing kind") unless node_kind < kind_count
string(slot.fetch("node_name"), "#{slot_path}.node_name")
validate_fields(slot.fetch("fields"), "#{slot_path}.fields", @productions.fetch(production_id))
production_id
end
sorted_unique!(production_ids, path)
end
|
#validate_fields(data, path, production) ⇒ void
This method returns an undefined value.
152
153
154
155
156
157
158
159
160
161
162
163
164
165
|
# File 'lib/ibex/table_artifact/validator/metadata.rb', line 152
def validate_fields(data, path, production)
names = array(data, path).map.with_index do |field, index|
field_path = "#{path}[#{index}]"
field = record(field, field_path, %w[name index extraction])
name = string(field.fetch("name"), "#{field_path}.name")
field_index = integer(field.fetch("index"), "#{field_path}.index", minimum: 0)
rhs_length = production.fetch("rhs_length") invalid("#{field_path}.index", "exceeds production rhs") unless field_index < rhs_length
= field.fetch("extraction")
enum(, "#{field_path}.extraction", %w[repetition separated_list]) unless .nil?
name
end
invalid(path, "must have unique field names") unless names.uniq.length == names.length
end
|
#validate_named_kinds(data, path, names) ⇒ void
This method returns an undefined value.
101
102
103
104
105
106
107
108
109
110
111
112
|
# File 'lib/ibex/table_artifact/validator/metadata.rb', line 101
def validate_named_kinds(data, path, names)
entries = array(data, path)
ids = entries.map.with_index do |entry, index|
entry_path = "#{path}[#{index}]"
entry = record(entry, entry_path, %w[name id])
name = string(entry.fetch("name"), "#{entry_path}.name")
id = integer(entry.fetch("id"), "#{entry_path}.id", minimum: 0)
invalid(entry_path, "does not match the kind name table") unless names[id] == name
id
end
sorted_unique!(ids, path)
end
|
#validate_named_nonterminals(data, path, kind_count) ⇒ void
This method returns an undefined value.
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
# File 'lib/ibex/table_artifact/validator/metadata.rb', line 115
def validate_named_nonterminals(data, path, kind_count)
pairs = array(data, path).map.with_index do |entry, index|
entry_path = "#{path}[#{index}]"
entry = record(entry, entry_path, %w[kind_id symbol_id])
kind_id = integer(entry.fetch("kind_id"), "#{entry_path}.kind_id", minimum: 0)
invalid("#{entry_path}.kind_id", "references a missing kind") unless kind_id < kind_count
symbol_id = integer(entry.fetch("symbol_id"), "#{entry_path}.symbol_id", minimum: 0)
invalid("#{entry_path}.symbol_id", "must reference a nonterminal") unless @nonterminal_ids.include?(symbol_id)
[kind_id, symbol_id]
end
return if pairs == pairs.sort && pairs.map(&:first).uniq.length == pairs.length
invalid(path,
"must be sorted with unique kind ids")
end
|
#validate_range(data, path, limit) ⇒ void
This method returns an undefined value.
92
93
94
95
96
97
98
|
# File 'lib/ibex/table_artifact/validator/metadata.rb', line 92
def validate_range(data, path, limit)
values = array(data, path)
invalid(path, "must contain two bounds") unless values.length == 2
start = integer(values.fetch(0), "#{path}[0]", minimum: 0)
finish = integer(values.fetch(1), "#{path}[1]", minimum: 0)
invalid(path, "must be an ordered half-open range") unless finish.between?(start, limit)
end
|
#validate_recovery(data) ⇒ void
This method returns an undefined value.
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
# File 'lib/ibex/table_artifact/validator/metadata.rb', line 48
def validate_recovery(data)
path = "$.payload.recovery"
data = record(data, path, %w[sync_token_ids on_error_reduce_symbol_ids])
sync_ids = integer_ids(data.fetch("sync_token_ids"), "#{path}.sync_token_ids", sorted: false)
sync_ids.each do |id|
invalid("#{path}.sync_token_ids", "must reference terminals") unless @terminal_ids.include?(id)
end
groups = array(data.fetch("on_error_reduce_symbol_ids"), "#{path}.on_error_reduce_symbol_ids")
groups.each_with_index do |group, index|
ids = integer_ids(group, "#{path}.on_error_reduce_symbol_ids[#{index}]", sorted: false)
invalid("#{path}.on_error_reduce_symbol_ids[#{index}]", "must not be empty") if ids.empty?
ids.each do |id|
invalid("#{path}.on_error_reduce_symbol_ids[#{index}]", "must reference nonterminals") unless
@nonterminal_ids.include?(id)
end
end
end
|
#validate_semantic_actions(data) ⇒ void
This method returns an undefined value.
37
38
39
40
41
42
43
44
45
|
# File 'lib/ibex/table_artifact/validator/metadata.rb', line 37
def validate_semantic_actions(data)
path = "$.payload.semantic_actions"
data = record(data, path, %w[binding verified slots])
enum(data.fetch("binding"), "#{path}.binding", ["opaque-wrapper-production-id-v1"])
invalid("#{path}.verified", "must be false") unless boolean(data.fetch("verified"), "#{path}.verified") == false
slots = integer_ids(data.fetch("slots"), "#{path}.slots")
expected = @productions.filter_map { |production| production.fetch("action_slot") }
invalid("#{path}.slots", "must match production action slots") unless slots == expected
end
|