require_relative '../artefact.rb' module Compfile class ParserArtefact < Comfpile::Artefact def initialize(*args, **opts) super(*args) @search_regexes = opts[:search_regexes] @parsed_parameters = {} parent_artefact :sourcefile, @target add_step do sourcefile_parse_step sourcefile_dependency_step end end # Attempts to find the set of values for a given # parameter key. # # @param [String, Array] keys Key, or array of keys, to look for # # @return [Array] Array of values found for this key # def find_parsed_parameters(keys) if keys.is_a? Array output = [] keys.each do |key| output += @parsed_parameters[key] || [] end output else @parsed_parameters[key] || [] end end # # Try to find a relative or absolute source file # artefact. # Used to resolve the include, require and reference # statements and find relative and/or absolute source # files with matching name. Similar to how C++'s # include statement it will check relative, then # globally. # # @param [String, Array] name Path of the sourcefile to look for # @param [Boolean] optional If true, will also check for absolute # source file, and will discard the file if it can't be found. # Useful for e.g. C/C++ header files that may not be in the search # path of comfpile. # # @return [String] Resolved path of the sourcefile. Relative # if a relative file is found, else absolute. # def resolve_sourcefile(name, optional: false) if(name.is_a? Array) name.map do |n| resolve_sourcefile(n, optional: optional) end name.compact else own_dir = File.dirname(@target) relative_file = File.join(own_dir, name) if not craft_artefact(:sourcefile, relative_file).nil? relative_file elsif not craft_artefact(:sourcefile, name).nil? name elsif optional relative_file else nil end end end def sourcefile_parse_step log "Parsing file #{@target}..." File.readlines(@parent_artefact[:file]).each do |line| @search_regexes.each do |r| match = r.match line next if match.nil? key = match[:key] value = match[:value] next if key.nil? log "Found k/v pair: '#{key}' '#{value}'", :debug @parsed_parameters[key] ||= [] @parsed_parameters[key] << value end end log "Parsing completed, found #{@parsed_parameters.keys.size} parameters!" end def sourcefile_dependency_step included_artefacts = resolve_sourcefile find_parsed_parameters 'include' required_artefacts = resolve_sourcefile find_parsed_parameters 'require' referenced_artefacts = resolve_sourcefile find_parsed_parameters 'reference' included_artefacts.each { |a| include_artefact :parsed, a } required_artefacts.each { |a| require_artefact :parsed, a } referenced_artefacts.each { |a| reference_artefact :parsed, a } log "Generated dependencies. Included #{included_artefacts.size}, required #{required_artefact.size} and referenced #{referenced_artefacts.size}." end end class ParserEngine < ArtefactEngine def initialize(core, **options) super(core, **options) @input_file_regex = options[:allowed_files] @require_regex = options[:require_reg] @include_regex = options[:include_reg] end def generate_parser_artefact(stage, target) match = @input_file_regex.match target return nil if match.nil? a = Artefact.new(@core, self, stage, target) a.parent_artefact(:sourcefile, target) a.add_step do @parameters[:included_files] = [] @parameters[:required_files] = [] File.readlines(@parent_artefact[:file]) do |l| case l when @require_regex filename = $~[:file] own_dir = File.dirname(@target) relative_file = File.join(own_dir, filename) unless craft_artefact(:sourcefile, relative_file).nil? @parameters[:required_files] << require_artefact(:parsed, relative_file) else @parameters[:required_files] << require_artefact(:parsed, filename) end when @include_regex filename = $~[:file] own_dir = File.dirname(@target) relative_file = File.join(own_dir, filename) unless craft_artefact(:sourcefile, relative_file).nil? @parameters[:included_files] << craft_artefact(:parsed, relative_file) else @parameters[:included_files] << craft_artefact(:parsed, filename) end end end end end def generate_dependency_artefact(stage, target) end def craft(stage, target) case stage when :parsed generate_parser_artefact(stage, target) when :dependency_list else nil end end end