Class: Origen::Tester::J750::Parser::Descriptions

Inherits:
Object
  • Object
show all
Defined in:
lib/origen/tester/j750/parser/descriptions.rb

Overview

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

Constant Summary

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

Instance Attribute Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (Descriptions) initialize(options = {})

Returns a new instance of Descriptions



24
25
26
27
28
29
# File 'lib/origen/tester/j750/parser/descriptions.rb', line 24

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

Instance Attribute Details

- (Object) parser

Returns the value of attribute parser



8
9
10
# File 'lib/origen/tester/j750/parser/descriptions.rb', line 8

def parser
  @parser
end

- (Object) source_directories

Returns the value of attribute source_directories



8
9
10
# File 'lib/origen/tester/j750/parser/descriptions.rb', line 8

def source_directories
  @source_directories
end

- (Object) template_directories

Returns the value of attribute template_directories



8
9
10
# File 'lib/origen/tester/j750/parser/descriptions.rb', line 8

def template_directories
  @template_directories
end

Instance Method Details

- (Object) compile_program

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/tester/j750/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

- (Object) compiled_dir



232
233
234
235
236
237
238
239
# File 'lib/origen/tester/j750/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

- (Object) copy_source_files_to_scratch

Copy all flow and instance source files to the scratch dir



199
200
201
202
203
204
205
206
207
208
# File 'lib/origen/tester/j750/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

- (Object) copy_templates_to_scratch

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/tester/j750/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

- (Object) extract_flow_line_descriptions



95
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/tester/j750/parser/descriptions.rb', line 95

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
            t = FlowLine.extract_test(line)
            if t
              lookup.add_for_test_usage(t, file, comments)
            end
            comments = []
          end
        end
      end
    end
  end
end

- (Object) extract_flow_summaries



67
68
69
70
71
72
73
# File 'lib/origen/tester/j750/parser/descriptions.rb', line 67

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

- (Object) extract_test_instance_descriptions

Parses a compiled template for marked up comments



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

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

- (Boolean) flow_file?(file)

Returns:

  • (Boolean)


283
284
285
# File 'lib/origen/tester/j750/parser/descriptions.rb', line 283

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

- (Object) flow_line(options = {})

Returns the description of the given test from the test flow



44
45
46
# File 'lib/origen/tester/j750/parser/descriptions.rb', line 44

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

- (Boolean) flow_or_instance_file?(file, options = {})

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/tester/j750/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

- (Object) flow_summary(options = {})

Returns the description for the given flow



32
33
34
# File 'lib/origen/tester/j750/parser/descriptions.rb', line 32

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

- (Object) generate_program

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/tester/j750/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

- (Object) generate_program_files



120
121
122
123
124
125
126
# File 'lib/origen/tester/j750/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

- (Object) generated_dir



241
242
243
244
245
246
247
248
# File 'lib/origen/tester/j750/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

- (Boolean) instance_file?(file)

Returns:

  • (Boolean)


287
288
289
# File 'lib/origen/tester/j750/parser/descriptions.rb', line 287

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

- (Object) lookup

All descriptions are stored in this lookup table



13
14
15
16
17
18
19
20
21
22
# File 'lib/origen/tester/j750/parser/descriptions.rb', line 13

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 = Origen::Tester::Parser::DescriptionLookup.new
  end
end

- (Object) markup_source_file_comments

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/tester/j750/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

- (Object) markup_template_comments

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/tester/j750/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

- (Object) parse_flow_summary(file)

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/tester/j750/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

- (Object) parse_program



48
49
50
51
52
53
54
55
56
57
# File 'lib/origen/tester/j750/parser/descriptions.rb', line 48

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

- (Object) test_instance(options = {})

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



38
39
40
# File 'lib/origen/tester/j750/parser/descriptions.rb', line 38

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

- (Object) uncompiled_dir(force_make = false)



210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/origen/tester/j750/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

- (Object) ungenerated_dir



223
224
225
226
227
228
229
230
# File 'lib/origen/tester/j750/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