Class: OrigenTesters::IGXLBasedTester::Parser::Descriptions

Inherits:
Object
  • Object
show all
Defined in:
lib/origen_testers/igxl_based_tester/parser/descriptions.rb

Overview

Extracts embedded test and flow descriptions (comments) from test program source files

Constant Summary collapse

SCRATCH_DIR =
"#{Origen.root}/.j750_scratch"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Descriptions

Returns a new instance of Descriptions.


25
26
27
28
29
30
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 25

def initialize(options = {})
  @parser = options[:parser]
  FileUtils.rm_rf(SCRATCH_DIR) if File.exist?(SCRATCH_DIR)
  parse_program
  true
end

Instance Attribute Details

#parserObject

Returns the value of attribute parser.


9
10
11
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 9

def parser
  @parser
end

#source_directoriesObject

Returns the value of attribute source_directories.


9
10
11
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 9

def source_directories
  @source_directories
end

#template_directoriesObject

Returns the value of attribute template_directories.


9
10
11
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 9

def template_directories
  @template_directories
end

Instance Method Details

#compile_programObject

Compile a scratch version of the program for parsing


165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 165

def compile_program
  if template_directories.size > 0
    unless @program_compiled
      Origen.log.info ''
      Origen.log.info 'Extracting embedded comments:'
      Origen.log.info ''
      copy_templates_to_scratch
      markup_template_comments
      # Compile the flow file, with Ruby comments now preserved and marked up
      Origen.app.runner.generate(compile: true, patterns: uncompiled_dir, output: compiled_dir,
                               check_for_changes: false, collect_stats: false, quiet: true)
      Origen.log.info ''
    end
    @program_compiled = true
  else
    false
  end
end

#compiled_dirObject


232
233
234
235
236
237
238
239
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 232

def compiled_dir
  @compiled_dir ||= "#{SCRATCH_DIR}/compiled"
  unless @compiled_dir_created
    FileUtils.mkdir_p(@compiled_dir) unless File.exist?(@compiled_dir)
    @compiled_dir_created = true
  end
  @compiled_dir
end

#copy_source_files_to_scratchObject

Copy all flow and instance source files to the scratch dir


199
200
201
202
203
204
205
206
207
208
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 199

def copy_source_files_to_scratch
  source_directories.each do |dir|
    Origen.file_handler.resolve_files(dir) do |file|
      subdir = file.relative_path_from(Pathname.new(dir)).dirname.to_s
      cpydir = "#{ungenerated_dir}/#{subdir}"
      FileUtils.mkdir_p(cpydir) unless File.exist?(cpydir)
      FileUtils.copy(file, cpydir)
    end
  end
end

#copy_templates_to_scratchObject

Copy all flow and instance template files to the scratch dir


185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 185

def copy_templates_to_scratch
  uncompiled_dir(true)
  template_directories.each do |dir|
    Origen.file_handler.resolve_files(dir) do |file|
      subdir = file.relative_path_from(Pathname.new(dir)).dirname.to_s
      cpydir = "#{uncompiled_dir}/#{subdir}"
      FileUtils.mkdir_p(cpydir) unless File.exist?(cpydir)
      FileUtils.copy(file, cpydir) if flow_or_instance_file?(file)
    end
  end
  `chmod -R 777 #{uncompiled_dir}/*` unless Dir["#{uncompiled_dir}/*"].empty?
end

#extract_flow_line_descriptionsObject


96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 96

def extract_flow_line_descriptions
  Origen.file_handler.resolve_files(compiled_dir) do |file|
    if flow_file?(file)
      f = file.basename('.txt').to_s
      comments = []
      header_line = true
      File.readlines(file).each do |line|
        if header_line
          header_line = false if line =~ /^\s*Label/
        else
          if line =~ /^<comment>(.*)/
            comments << Regexp.last_match[1].gsub("\r", '')
          else
            if t = FlowLine.extract_test(line)
              lookup.add_for_test_usage(t, file, comments)
            end
            comments = []
          end
        end
      end
    end
  end
end

#extract_flow_summariesObject


68
69
70
71
72
73
74
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 68

def extract_flow_summaries
  Origen.file_handler.resolve_files(compiled_dir) do |file|
    if flow_file?(file)
      lookup.add_for_flow(file, parse_flow_summary(file))
    end
  end
end

#extract_test_instance_descriptionsObject

Parses a compiled template for marked up comments


77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 77

def extract_test_instance_descriptions
  Origen.file_handler.resolve_files(compiled_dir) do |file|
    if instance_file?(file)
      comments = []
      File.readlines(file).each do |line|
        if line =~ /^<comment>(.*)/
          comments << Regexp.last_match[1].gsub("\r", '')
        else
          fields = line.split("\t")
          unless ['Test Instances', '', 'Test Name'].include? fields[1]
            lookup.add_for_test_definition(fields[1], comments)
          end
          comments = []
        end
      end
    end
  end
end

#flow_file?(file) ⇒ Boolean

Returns:

  • (Boolean)

283
284
285
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 283

def flow_file?(file)
  flow_or_instance_file?(file, instance: false)
end

#flow_line(options = {}) ⇒ Object

Returns the description of the given test from the test flow


45
46
47
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 45

def flow_line(options = {})
  lookup.for_test_usage(options[:name], options[:flow])
end

#flow_or_instance_file?(file, options = {}) ⇒ Boolean

Returns true if the given file looks like a J750 flow file, works for templates to

Returns:

  • (Boolean)

252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 252

def flow_or_instance_file?(file, options = {})
  options = { flow:     true,
              instance: true
  }.merge(options)
  if options[:flow] && options[:instance]
    match = 'Flow|Instances'
  elsif options[:flow]
    match = 'Flow'
  else
    match = 'Instances'
  end
  # Not sure the best way to determine the file type of a partial, just
  # return true for now to play it safe
  return true if file.basename.to_s =~ /^_/
  File.readlines(file).each do |line|
    begin
      unless line =~ /^%/ || line =~ /^\s*<comment>/
        return !!(line =~ /#{match}/)
      end
    rescue Exception => e
      if e.is_a?(ArgumentError) && e.message =~ /invalid byte sequence/
        return false
      else
        puts e.message
        puts e.backtrace
        exit 1
      end
    end
  end
end

#flow_summary(options = {}) ⇒ Object

Returns the description for the given flow


33
34
35
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 33

def flow_summary(options = {})
  lookup.for_flow(options[:file])
end

#generate_programObject

Generate a scratch version of the program for parsing


144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 144

def generate_program
  if source_directories.size > 0
    unless @program_generated
      Origen.log.info ''
      Origen.log.info 'Extracting embedded comments:'
      Origen.log.info ''
      copy_source_files_to_scratch
      markup_source_file_comments
      # Compile the flow file, with Ruby comments now preserved and marked up
      desc = Origen.app.runner.generate(program: true, patterns: ungenerated_dir, output: generated_dir,
                                      check_for_changes: false, collect_stats: false, quiet: true,
                                      collect_descriptions: true)
      Origen.log.info ''
    end
    @program_generated = true
  else
    false
  end
end

#generate_program_filesObject


120
121
122
123
124
125
126
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 120

def generate_program_files
  a = generate_program
  b = compile_program
  unless a || b
    fail 'No source or template files declared from which to parse descriptions!'
  end
end

#generated_dirObject


241
242
243
244
245
246
247
248
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 241

def generated_dir
  @generated_dir ||= "#{SCRATCH_DIR}/generated"
  unless @generated_dir_created
    FileUtils.mkdir_p(@generated_dir) unless File.exist?(@generated_dir)
    @generated_dir_created = true
  end
  @generated_dir
end

#instance_file?(file) ⇒ Boolean

Returns:

  • (Boolean)

287
288
289
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 287

def instance_file?(file)
  flow_or_instance_file?(file, flow: false)
end

#lookupObject

All descriptions are stored in this lookup table


14
15
16
17
18
19
20
21
22
23
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 14

def lookup
  return @lookup if @lookup
  # Use the one from the interface if present, program generation will
  # automatically push descriptions in here
  if Origen.interface_present?
    @lookup = Origen.interface.descriptions
  else
    @lookup = ::OrigenTesters::Parser::DescriptionLookup.new
  end
end

#markup_source_file_commentsObject

Substitute Ruby line comments so they are preserved by generation


315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 315

def markup_source_file_comments
  Origen.file_handler.resolve_files(ungenerated_dir) do |file|
    lines = File.readlines(file)
    File.open(file, 'w') do |f|
      lines.each do |line|
        if line =~ /^\s*#\s?(.*)/ # Remove single leading whitespace from comment if it exists
          comment = Regexp.last_match[1]
          # If comment starts with a '#-' it should be removed by generation
          if line =~ /^\s*#-.*/
            f.write line
          # Otherwise preserve it
          else
            f.write "Origen.interface.comment '#{comment}'\n"
          end
        else
          f.write line
        end
      end
    end
  end
end

#markup_template_commentsObject

Substitute Ruby line comments so they are preserved by compilation


292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 292

def markup_template_comments
  Origen.file_handler.resolve_files(uncompiled_dir) do |file|
    lines = File.readlines(file)
    File.open(file, 'w') do |f|
      lines.each do |line|
        if line =~ /^%\s*#\s?(.*)/ # Remove single leading whitespace from comment if it exists
          comment = Regexp.last_match[1]
          # If comment starts with a '#-' it should be removed by compilation
          if line =~ /^%\s*#-.*/
            f.write line
          # Otherwise preserve it
          else
            f.write "<comment>#{comment}\n"
          end
        else
          f.write line
        end
      end
    end
  end
end

#parse_flow_summary(file) ⇒ Object

Parses the given flow file for summary text and returns it, summary text must be the very first thing in the file. Returns an array of strings each representing a line of text.


131
132
133
134
135
136
137
138
139
140
141
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 131

def parse_flow_summary(file)
  desc = []
  File.readlines(file).each do |line|
    if line =~ /%?\s*<comment>(.*)/
      desc << Regexp.last_match[1].gsub("\r", '')
    else
      break
    end
  end
  desc
end

#parse_programObject


49
50
51
52
53
54
55
56
57
58
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 49

def parse_program
  Origen.file_handler.preserve_state do
    generate_program_files
    # Comments must be extracted manually for any compiled files, for
    # generated files the comments will already be in the lookup
    extract_flow_summaries
    extract_test_instance_descriptions
    extract_flow_line_descriptions
  end
end

#test_instance(options = {}) ⇒ Object

Returns the description of the given test from the test instance sheet declaration


39
40
41
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 39

def test_instance(options = {})
  lookup.for_test_definition(options[:name])
end

#uncompiled_dir(force_make = false) ⇒ Object


210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 210

def uncompiled_dir(force_make = false)
  @uncompiled_dir ||= "#{SCRATCH_DIR}/uncompiled"
  if force_make
    FileUtils.rm_rf(@uncompiled_dir) if File.exist?(@uncompiled_dir)
    @uncompiled_dir_created = false
  end
  unless @uncompiled_dir_created
    FileUtils.mkdir_p(@uncompiled_dir) unless File.exist?(@uncompiled_dir)
    @uncompiled_dir_created = true
  end
  @uncompiled_dir
end

#ungenerated_dirObject


223
224
225
226
227
228
229
230
# File 'lib/origen_testers/igxl_based_tester/parser/descriptions.rb', line 223

def ungenerated_dir
  @ungenerated_dir ||= "#{SCRATCH_DIR}/ungenerated"
  unless @ungenerated_dir_created
    FileUtils.mkdir_p(@ungenerated_dir) unless File.exist?(@ungenerated_dir)
    @ungenerated_dir_created = true
  end
  @ungenerated_dir
end