Class: Udb::NonIsaSpecification

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Includes:
Kernel
Defined in:
lib/udb/obj/non_isa_specification.rb

Overview

Clean non-ISA specification object that handles YAML-based specifications

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, data)

Parameters:

  • name (String)
  • data (Hash{String => T.untyped})


40
41
42
43
44
45
46
# File 'lib/udb/obj/non_isa_specification.rb', line 40

def initialize(name, data)
  @name = name
  @data = data.dup
  @spec_data = nil
  @spec_path = nil
  load_spec_data
end

Instance Attribute Details

#dataHash{String => T.untyped} (readonly)

Returns:

  • (Hash{String => T.untyped})


31
32
33
# File 'lib/udb/obj/non_isa_specification.rb', line 31

def data
  @data
end

#nameString (readonly)

Returns:

  • (String)


28
29
30
# File 'lib/udb/obj/non_isa_specification.rb', line 28

def name
  @name
end

#spec_dataHash{String => T.untyped}? (readonly)

Returns:

  • (Hash{String => T.untyped}, nil)


37
38
39
# File 'lib/udb/obj/non_isa_specification.rb', line 37

def spec_data
  @spec_data
end

#spec_pathPathname? (readonly)

Returns:

  • (Pathname, nil)


34
35
36
# File 'lib/udb/obj/non_isa_specification.rb', line 34

def spec_path
  @spec_path
end

Instance Method Details

#defined_by_conditionT.untyped

Returns:

  • (T.untyped)


136
137
138
139
140
141
142
143
144
# File 'lib/udb/obj/non_isa_specification.rb', line 136

def defined_by_condition
  when_condition = @data['when()'] || @spec_data&.dig('when()')
  return OpenStruct.new(to_asciidoc: "Always included") if when_condition.nil?

  # Convert condition to human-readable description
  OpenStruct.new(
    to_asciidoc: "When #{when_condition}"
  )
end

#exists_in_cfg?(cfg_arch) ⇒ Boolean

Configuration methods

Parameters:

  • cfg_arch (T.untyped)

Returns:

  • (Boolean)


109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/udb/obj/non_isa_specification.rb', line 109

def exists_in_cfg?(cfg_arch)
  return false unless valid?

  # Check configuration conditions if present
  when_condition = @data['when()'] || @spec_data&.dig('when()')
  return true if when_condition.nil?

  # Evaluate condition against cfg_arch
  # For now, simple string matching - could be enhanced with expression evaluation
  case when_condition
  when String
    # Basic string matching for now
    cfg_arch.param_values.any? { |k, v| when_condition.include?(k.to_s) }
  else
    true
  end
end

#extract_prose_statements(include_sections: true) ⇒ Array<Hash{String, Symbol => T.untyped}>

Parameters:

  • include_sections (Boolean) (defaults to: true)

Returns:

  • (Array<Hash{String, Symbol => T.untyped}>)


177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/udb/obj/non_isa_specification.rb', line 177

def extract_prose_statements(include_sections: true)
  statements = []
  # Extract from description
  if spec_description.is_a?(Array)
    spec_description.each_with_index { |stmt, i| statements << stmt.merge(source: "description[#{i}]") if stmt.is_a?(Hash) }
  end
  # Extract from sections
  if include_sections
    sections.each_with_index do |section, section_idx|
      next unless section['content'].is_a?(Array)
      section['content'].each_with_index do |stmt, stmt_idx|
        statements << stmt.merge(source: "sections[#{section_idx}].content[#{stmt_idx}]") if stmt.is_a?(Hash)
      end
    end
  end
  statements
end

#load_spec_data

This method returns an undefined value.

Core spec data loading and validation



50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/udb/obj/non_isa_specification.rb', line 50

def load_spec_data
  base_path = Pathname.new(__dir__).parent.parent.parent.parent.parent.parent / "spec/custom/non_isa"
  @spec_path = base_path / "#{name}.yaml"
  return unless @spec_path.exist?

  begin
    @spec_data = YAML.safe_load_file(@spec_path, permitted_classes: [])
  rescue Psych::SyntaxError => e
    raise NonIsaSpecificationLoadError, "YAML syntax error in #{@spec_path}: #{e.message}"
  rescue => e
    raise NonIsaSpecificationLoadError, "Failed to load #{@spec_path}: #{e.message}"
  end
end

#long_nameString

Returns:

  • (String)


75
76
77
78
79
80
# File 'lib/udb/obj/non_isa_specification.rb', line 75

def long_name
  return @data['long_name'] if @data['long_name']
  return @spec_data['long_name'] if @spec_data&.dig('long_name')
  return @spec_data['name'] if @spec_data&.dig('name')
  name.split('_').map(&:capitalize).join(' ')
end

#optional_in_cfg?(cfg_arch) ⇒ Boolean

Parameters:

  • cfg_arch (T.untyped)

Returns:

  • (Boolean)


129
130
131
132
# File 'lib/udb/obj/non_isa_specification.rb', line 129

def optional_in_cfg?(cfg_arch)
  # Non-ISA specs are generally optional unless marked as mandatory
  !(@data['mandatory'] == true || @spec_data&.dig('mandatory') == true)
end

#referencesArray<Hash{String, Symbol => T.untyped}>

Returns:

  • (Array<Hash{String, Symbol => T.untyped}>)


102
103
104
# File 'lib/udb/obj/non_isa_specification.rb', line 102

def references
  @spec_data&.dig('references') || []
end

#render_for_cfg(cfg_arch, base_level: 3, normative: true, non_normative: true) ⇒ String

Rendering methods

Parameters:

  • cfg_arch (T.untyped)
  • base_level (Integer) (defaults to: 3)
  • normative (Boolean) (defaults to: true)
  • non_normative (Boolean) (defaults to: true)

Returns:

  • (String)


205
206
207
208
209
210
211
212
213
214
# File 'lib/udb/obj/non_isa_specification.rb', line 205

def render_for_cfg(cfg_arch, base_level: 3, normative: true, non_normative: true)
  return "" unless exists_in_cfg?(cfg_arch)

  to_asciidoc(
    base_level: base_level,
    normative: normative,
    non_normative: non_normative,
    when_callback: create_when_callback(cfg_arch)
  )
end

#sectionsArray<Hash{String, Symbol => T.untyped}>

Returns:

  • (Array<Hash{String, Symbol => T.untyped}>)


96
97
98
# File 'lib/udb/obj/non_isa_specification.rb', line 96

def sections
  @spec_data&.dig('sections') || []
end

#spec_descriptionT.untyped

Returns:

  • (T.untyped)


90
91
92
# File 'lib/udb/obj/non_isa_specification.rb', line 90

def spec_description
  @spec_data&.dig('description')
end

#to_asciidoc(base_level: 3, normative: true, non_normative: true, when_callback: nil) ⇒ String

Parameters:

  • base_level (Integer) (defaults to: 3)
  • normative (Boolean) (defaults to: true)
  • non_normative (Boolean) (defaults to: true)
  • when_callback (T.proc.params(arg0: T.untyped, arg1: T.untyped).returns(T::Boolean), nil) (defaults to: nil)

Returns:

  • (String)


225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/udb/obj/non_isa_specification.rb', line 225

def to_asciidoc(base_level: 3, normative: true, non_normative: true, when_callback: nil)
  return create_fallback_content(base_level) unless valid?

  content = []

  # Add main description prose
  desc_content = render_structured_prose(spec_description, normative: normative, non_normative: non_normative, when_callback: when_callback)
  content << desc_content if desc_content && !desc_content.empty?
  content << ""

  # Process all sections
  content.concat(render_sections(base_level, normative, non_normative, when_callback))

  # Add references section if present
  content.concat(render_references(base_level)) unless references.empty?

  content.join("\n")
end

#valid?Boolean

Returns:

  • (Boolean)


66
67
68
69
70
71
# File 'lib/udb/obj/non_isa_specification.rb', line 66

def valid?
  !@spec_data.nil? &&
    @spec_data['kind'] == 'non-isa specification' &&
    !@spec_data['name'].nil? &&
    !@spec_data['description'].nil?
end

#validate_prose_idsArray<String>

Validation methods

Returns:

  • (Array<String>)


149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/udb/obj/non_isa_specification.rb', line 149

def validate_prose_ids
  return [] unless valid?

  issues = []
  statements = extract_prose_statements
  statements.each do |stmt|
    next unless stmt['id']
    id = stmt['id']
    source = stmt[:source] || 'unknown'

    # Check ID format according to prose-schema conventions
    unless valid_id_format?(id)
      issues << "Invalid ID format '#{id}' in #{source}: must be lowercase with underscores/hyphens only"
    end

    # Check for non-ISA specification naming convention
    unless valid_id_naming?(id)
      issues << "ID '#{id}' in #{source} should start with '#{name.downcase}-' for non-ISA specifications"
    end
  end

  # Check for duplicate IDs
  issues.concat(find_duplicate_ids(statements))
  issues
end

#versionString?

Returns:

  • (String, nil)


84
85
86
# File 'lib/udb/obj/non_isa_specification.rb', line 84

def version
  @spec_data&.dig('version')
end