From 3c7f48016d7773e3fa3e2be43fc43b8511e38cc5 Mon Sep 17 00:00:00 2001 From: David Bailey Date: Sat, 12 Aug 2023 20:36:26 +0200 Subject: [PATCH] feat: :fire: oh god --- .gitignore | 1 + Gemfile.lock | 37 ++-- bin/console | 140 ++------------ bin/cpp-engine_old.rb | 48 +++++ bin/cpp_engine.rb | 70 +++++++ bin/ghdl_engine.rb | 94 ++++++++++ comfpile.code-workspace | 6 +- lib/comfpile.rb | 4 +- lib/comfpile/artefact.rb | 11 +- lib/comfpile/artefact_engine.rb | 8 +- lib/comfpile/context.rb | 138 +++++++------- lib/comfpile/core.rb | 63 +++---- lib/comfpile/engines/config_engine.rb | 4 +- lib/comfpile/engines/filesource_engine.rb | 15 +- lib/comfpile/engines/parser_engine.rb | 2 +- lib/comfpile/old_context.rb | 171 ++++++++++++++++++ .../spi_master_tb.vhd => spi_master_tb.vhd | 0 .../{ => cpp}/lib_test/comf.yml | 0 .../{ => cpp}/lib_test/test.cpp | 0 test/faux_build_dir/{ => cpp}/lib_test/test.h | 0 .../{ => cpp}/lib_test/test_settings.h | 0 test/faux_build_dir/cpp/main.cpp | 23 +++ test/faux_build_dir/cpp/main.h | 9 + test/faux_build_dir/cpp/main2.cpp | 22 +++ test/faux_build_dir/main.cpp | 8 - test/faux_build_dir/main.h | 5 - .../{ => vhdl}/UQDS_specifics_pkg.vhd | 0 test/faux_build_dir/vhdl/comf.yml | 1 + test/faux_build_dir/{ => vhdl}/spi_master.vhd | 0 test/faux_build_dir/vhdl/spi_master_tb.vhd | 108 +++++++++++ 30 files changed, 708 insertions(+), 280 deletions(-) create mode 100644 bin/cpp-engine_old.rb create mode 100644 bin/cpp_engine.rb create mode 100644 bin/ghdl_engine.rb create mode 100644 lib/comfpile/old_context.rb rename test/faux_build_dir/spi_master_tb.vhd => spi_master_tb.vhd (100%) rename test/faux_build_dir/{ => cpp}/lib_test/comf.yml (100%) rename test/faux_build_dir/{ => cpp}/lib_test/test.cpp (100%) rename test/faux_build_dir/{ => cpp}/lib_test/test.h (100%) rename test/faux_build_dir/{ => cpp}/lib_test/test_settings.h (100%) create mode 100644 test/faux_build_dir/cpp/main.cpp create mode 100644 test/faux_build_dir/cpp/main.h create mode 100644 test/faux_build_dir/cpp/main2.cpp delete mode 100644 test/faux_build_dir/main.cpp delete mode 100644 test/faux_build_dir/main.h rename test/faux_build_dir/{ => vhdl}/UQDS_specifics_pkg.vhd (100%) create mode 100644 test/faux_build_dir/vhdl/comf.yml rename test/faux_build_dir/{ => vhdl}/spi_master.vhd (100%) create mode 100644 test/faux_build_dir/vhdl/spi_master_tb.vhd diff --git a/.gitignore b/.gitignore index 9106b2a..5b202f0 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ /pkg/ /spec/reports/ /tmp/ +/build/ \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index 6791cc1..79db816 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -10,51 +10,54 @@ GEM backport (1.2.0) benchmark (0.2.1) coderay (1.1.3) - debug (1.7.2) + debug (1.8.0) irb (>= 1.5.0) reline (>= 0.3.1) diff-lcs (1.5.0) e2mmap (0.1.0) io-console (0.6.0) - irb (1.6.4) - reline (>= 0.3.0) - jaro_winkler (1.5.4) + irb (1.7.4) + reline (>= 0.3.6) + jaro_winkler (1.5.6) json (2.6.3) kramdown (2.4.0) rexml kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) + language_server-protocol (3.17.0.3) method_source (1.0.0) - minitest (5.18.0) - nokogiri (1.14.3-x86_64-linux) + minitest (5.18.1) + nokogiri (1.15.3-x86_64-linux) racc (~> 1.4) - parallel (1.22.1) - parser (3.2.2.0) + parallel (1.23.0) + parser (3.2.2.3) ast (~> 2.4.1) + racc pry (0.14.2) coderay (~> 1.1) method_source (~> 1.0) - racc (1.6.2) + racc (1.7.1) rainbow (3.1.1) rake (13.0.6) rbs (2.8.4) - regexp_parser (2.7.0) - reline (0.3.3) + regexp_parser (2.8.1) + reline (0.3.6) io-console (~> 0.5) reverse_markdown (2.1.1) nokogiri rexml (3.2.5) - rubocop (1.50.1) + rubocop (1.54.2) json (~> 2.3) + language_server-protocol (>= 3.17.0) parallel (~> 1.10) - parser (>= 3.2.0.0) + parser (>= 3.2.2.3) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.8, < 3.0) rexml (>= 3.2.5, < 4.0) rubocop-ast (>= 1.28.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.28.0) + rubocop-ast (1.29.0) parser (>= 3.2.1.0) ruby-progressbar (1.13.0) solargraph (0.49.0) @@ -73,10 +76,10 @@ GEM thor (~> 1.0) tilt (~> 2.0) yard (~> 0.9, >= 0.9.24) - thor (1.2.1) - tilt (2.1.0) + thor (1.2.2) + tilt (2.2.0) unicode-display_width (2.4.2) - yard (0.9.33) + yard (0.9.34) PLATFORMS x86_64-linux diff --git a/bin/console b/bin/console index f444b3d..6926412 100755 --- a/bin/console +++ b/bin/console @@ -12,138 +12,20 @@ $core = Comfpile::Core.new() $core.add_artefact_engine Comfpile::FilesourceEngine, root_path: File.join(File.dirname(__FILE__), '../test/faux_build_dir') $core.add_artefact_engine Comfpile::ConfigLoaderEngine -$core.add_artefact_engine Comfpile::ParserEngine, - file_regex: /^(.+)\.(h|c|cpp)$/, - search_regexes: [ - { - regex: /^#include\s*[<"](?.+)[>"]/, - key: 'include' - }, - { - regex: /\/\/\s*comf\.(?\w+)[=:]\s*(?.+)/ - } -] -$core.add_artefact_engine Comfpile::ParserEngine, - file_regex: /^(.+)\.vhd$/, - search_regexes: [ - { - regex: /--+\s*comf\.(?[^:]+)[=:]\s*(?.+)/ - } -] +require_relative 'ghdl_engine.rb' +require_relative 'cpp_engine.rb' -$core.add_artefact_engine do |engine| - engine.add_recipe(:ghdl_analysed, /^(.+)\.vhd/) do |match, a| - a.parent_artefact :dependency_analysis_include, a.target +t_start = Time.now() +dep_art = $core.craft_and_complete(:execute, "cpp/main.cpp") +dep_art = $core.craft_and_complete(:execute, "cpp/main2.cpp") +t_end = Time.now() - a.add_step do - @parent_artefact.dependencies.each do |dependency| - next if dependency.target == a.target +# t_start = Time.now() +# dep_art = $core.craft_and_complete(:gtkwave_output, "vhdl/spi_master_tb.vhd") +# t_end = Time.now() - log "Adding dependency for ghdl analysis of #{dependency.target}..." - - require_artefact :ghdl_analysed, dependency.target - end - end - - a.add_step do - work_library = find_parsed_parameter('vhdl.work') - if work_library.nil? - work_library = '' - else - work_library = '--work=' + work_library - end - - cmd = "ghdl -a -fsynopsys --std=08 #{work_library} #{self.file}" - log "Executing: #{cmd}" - - `#{cmd}` - end - end - - engine.add_recipe(:ghdl_elaborated, /^(.+)\.vhd/) do |match, a| - a.parent_artefact :dependency_analysis, a.target - - a.add_step do - dependencies.each do |dep| - require_artefact :ghdl_analysed, dep.target - end - end - - a.add_step do - work_library = find_parsed_parameter('vhdl.work') - if work_library.nil? - work_library = '' - else - work_library = '--work=' + work_library - end - - elaborate_arch = find_parsed_parameter('vhdl.elaborate') || File.basename(@target).chomp(File.extname(@target)) - - cmd = "ghdl -e -fsynopsys --std=08 #{work_library} #{elaborate_arch}" - log "Executing: #{cmd}" - - `#{cmd}` - end - end - - engine.add_recipe :ghdl_run, /^(.+)\.vhd/ do |match, a| - a.parent_artefact :ghdl_elaborated, a.target - - a.add_step do - work_library = find_parsed_parameter('vhdl.work') - if work_library.nil? - work_library = '' - else - work_library = '--work=' + work_library - end - - elaborate_arch = find_parsed_parameter('vhdl.elaborate') || File.basename(@target).chomp(File.extname(@target)) - - @parameters[:ghdl_arch] = elaborate_arch - - cmd = "ghdl -r -fsynopsys --std=08 #{work_library} #{elaborate_arch} --wave=#{elaborate_arch}.ghw" - log "Executing: #{cmd}" - - `#{cmd}` - end - end - - engine.add_recipe(:gtkwave_output, /^(.+)\.vhd/) do |match, a| - a.parent_artefact :ghdl_run, a.target - a.add_step do - `gtkwave #{@parent_artefact[:ghdl_arch]}.ghw` - end - end -end - -$core.add_artefact_engine do |engine| - - engine.add_recipe(:dependency_list, /^(.+)\.(h|c|cpp)$/) do |match, a| - - a.require_artefact :dependency_analysis, a.target - a.require_artefact :dependency_analysis_include, a.target - - a.add_step do - deps_artefact = find_artefact(:dependency_analysis, @target) - @parameters[:dependency_list] = deps_artefact.dependencies - end - end - - engine.add_recipe(:x86_debug, /^run (.+)/) do |match, a| - - a.require_artefact :parsed, "#{match[1]}.cpp" - end - - engine.add_recipe(:x86_debug, /(.+)\.o$/) do |match, a| - a.require_artefact :sourcefile, "#{match[1]}.cpp" - - a.add_step do - - end - - true - end -end +# puts "Full dependency list is: #{dep_art.dependencies.map(&:target)} (took #{t_end - t_start})" +# puts "Includes of all source files:" # (If you use this, don't forget to add pry to your Gemfile!) require "pry" diff --git a/bin/cpp-engine_old.rb b/bin/cpp-engine_old.rb new file mode 100644 index 0000000..278b2b9 --- /dev/null +++ b/bin/cpp-engine_old.rb @@ -0,0 +1,48 @@ + + +$core.add_artefact_engine Comfpile::ParserEngine, + file_regex: /^(.+)\.(h|c|cpp)$/, + search_regexes: [ + { + regex: /^#include\s*[<"](?.+)[>"]/, + key: 'include' + }, + { + regex: /\/\/\s*comf\.(?\w+)[=:]\s*(?.+)/ + } +] + +$core.add_artefact_engine do |engine| + + engine.add_recipe(:dependency_list, /^(.+)\.(h|c|cpp)$/) do |match, a| + + a.require_artefact :dependency_analysis, a.target + a.require_artefact :dependency_analysis_include, a.target + + a.add_step do + deps_artefact = find_artefact(:dependency_analysis, @target) + @parameters[:dependency_list] = deps_artefact.dependencies + end + end + + engine.add_recipe(:x86_debug, /^run (.+)/) do |match, a| + + a.require_artefact :parsed, "#{match[1]}.cpp" + end + + engine.add_recipe(:x86_debug, /(.+)\.o$/) do |match, a| + a.require_artefact :sourcefile, "#{match[1]}.cpp" + + a.add_step do + + end + end + + engine.add_recipe(:execute, /(.*)/) do |match, a| + a.parent_artefact :executable, match[0] + + a.add_step do + @parent_artefact + end + end +end \ No newline at end of file diff --git a/bin/cpp_engine.rb b/bin/cpp_engine.rb new file mode 100644 index 0000000..4a7ba00 --- /dev/null +++ b/bin/cpp_engine.rb @@ -0,0 +1,70 @@ + + +$core.add_artefact_engine Comfpile::ParserEngine, + file_regex: /^(.+)\.(h|c|cpp)$/, + search_regexes: [ + { + regex: /^#include\s*[<"](?.+)[>"]/, + key: 'include' + }, + { + regex: /\/\/\s*comf\.(?\w+)[=:]?\s*(?.+)/ + } +] + +$core.add_artefact_engine do |engine| + engine.add_recipe(:object, /^(.*)\.(h|c|cpp)$/) do |match, a| + a.parent_artefact :sourcefile, match[0] + + a.add_step do + `g++ -I #{@build_dir} -c #{@target} -o #{@target}.o` + end + end + + engine.add_recipe(:main_object, /^(.*)\.(h|c|cpp)$/) do |match, a| + a.parent_artefact :sourcefile, match[0] + + a.add_step do + `g++ -DCOMF_MAIN -I #{@build_dir} -c #{@target} -o #{@target}.main.o` + end + end + + engine.add_recipe(:executable) do |match, a| + a.parent_artefact :dependency_analysis, match + + a.add_step do + @object_files = [] + + @parent_artefact.dependencies.each do |dep| + next unless ['.c', '.cpp'].include? File.extname(dep.target) + next if dep.target == @target + + @object_files << require_artefact(:object, dep.target) + end + + @main_object_file = require_artefact(:main_object, @target) + end + + a.add_step do + link_objects = [] + @object_files.each do |obj| + link_objects << obj.target + '.o' + end + link_objects << @main_object_file.target + '.main.o' + + cmd = "g++ #{link_objects.join(' ')} -o #{@target.sub(/\.[^.\/]*\Z/, '')}" + log cmd + + `#{cmd}` + end + end + + engine.add_recipe(:execute) do |match, a| + + a.parent_artefact :executable, match + + a.add_step do + print `./#{@target.sub(/\.[^.\/]*\Z/, '')}` + end + end +end \ No newline at end of file diff --git a/bin/ghdl_engine.rb b/bin/ghdl_engine.rb new file mode 100644 index 0000000..637c0a2 --- /dev/null +++ b/bin/ghdl_engine.rb @@ -0,0 +1,94 @@ + + +$core.add_artefact_engine Comfpile::ParserEngine, + file_regex: /^(.+)\.vhd$/, + search_regexes: [ + { + regex: /--+\s*comf\.(?[^:]+)[=:]\s*(?.+)/ + } +] + +$core.add_artefact_engine do |engine| + engine.add_recipe(:ghdl_analysed, /^(.+)\.vhd/) do |match, a| + a.parent_artefact :dependency_analysis_include, a.target + + a.add_step do + @parent_artefact.dependencies.each do |dependency| + next if dependency.target == a.target + + log "Adding dependency for ghdl analysis of #{dependency.target}..." + + require_artefact :ghdl_analysed, dependency.target + end + end + + a.add_step do + work_library = find_parsed_parameter('vhdl.work') + if work_library.nil? + work_library = '' + else + work_library = '--work=' + work_library + end + + cmd = "ghdl -a -fsynopsys --std=08 #{work_library} #{self.file}" + log "Executing: #{cmd}" + + `#{cmd}` + end + end + + engine.add_recipe(:ghdl_elaborated, /^(.+)\.vhd/) do |match, a| + a.parent_artefact :dependency_analysis, a.target + + a.add_step do + dependencies.each do |dep| + require_artefact :ghdl_analysed, dep.target + end + end + + a.add_step do + work_library = find_parsed_parameter('vhdl.work') + if work_library.nil? + work_library = '' + else + work_library = '--work=' + work_library + end + + elaborate_arch = find_parsed_parameter('vhdl.elaborate') || File.basename(@target).chomp(File.extname(@target)) + + cmd = "ghdl -e -fsynopsys --std=08 #{work_library} #{elaborate_arch}" + log "Executing: #{cmd}" + + `#{cmd}` + end + end + + engine.add_recipe :ghdl_run, /^(.+)\.vhd/ do |match, a| + a.parent_artefact :ghdl_elaborated, a.target + + a.add_step do + work_library = find_parsed_parameter('vhdl.work') + if work_library.nil? + work_library = '' + else + work_library = '--work=' + work_library + end + + elaborate_arch = find_parsed_parameter('vhdl.elaborate') || File.basename(@target).chomp(File.extname(@target)) + + @parameters[:ghdl_arch] = elaborate_arch + + cmd = "ghdl -r -fsynopsys --std=08 #{work_library} #{elaborate_arch} --wave=#{elaborate_arch}.ghw" + log "Executing: #{cmd}" + + `#{cmd}` + end + end + + engine.add_recipe(:gtkwave_output, /^(.+)\.vhd/) do |match, a| + a.parent_artefact :ghdl_run, a.target + a.add_step do + `gtkwave #{@parent_artefact[:ghdl_arch]}.ghw` + end + end +end \ No newline at end of file diff --git a/comfpile.code-workspace b/comfpile.code-workspace index 876a149..acc38e0 100644 --- a/comfpile.code-workspace +++ b/comfpile.code-workspace @@ -4,5 +4,9 @@ "path": "." } ], - "settings": {} + "settings": { + "conventionalCommits.scopes": [ + "context" + ] + } } \ No newline at end of file diff --git a/lib/comfpile.rb b/lib/comfpile.rb index 2ea0c64..08bb219 100644 --- a/lib/comfpile.rb +++ b/lib/comfpile.rb @@ -6,4 +6,6 @@ require_relative 'comfpile/core.rb' require_relative 'comfpile/engines/filesource_engine.rb' require_relative 'comfpile/engines/parser_engine.rb' -require_relative 'comfpile/engines/config_engine.rb' \ No newline at end of file +require_relative 'comfpile/engines/config_engine.rb' + +require_relative 'comfpile/context.rb' \ No newline at end of file diff --git a/lib/comfpile/artefact.rb b/lib/comfpile/artefact.rb index f76d193..1b0d3a3 100644 --- a/lib/comfpile/artefact.rb +++ b/lib/comfpile/artefact.rb @@ -8,6 +8,9 @@ module Comfpile class Artefact attr_reader :core, :engine + # @return [Comfpile::ContextKey] The context key of this artefact + attr_reader :context + attr_reader :exit_state attr_reader :stage, :target @@ -32,6 +35,8 @@ module Comfpile # linking steps, but the objects can be built separately. attr_reader :referenced_artefacts + attr_reader :build_dir + # ARTEFACT STATES # # The following states are known to the system: @@ -55,7 +60,7 @@ module Comfpile @stage = stage @target = target - @context = @core.sanitize_context context + @context = @core.get_context_key context @parent_artefact = nil @@ -76,6 +81,8 @@ module Comfpile @exit_state = nil @running = false + + @build_dir = opts[:build_dir] || @core.get_context_build_dir_path(self) end def [](key) @@ -109,7 +116,7 @@ module Comfpile @log_current_line = text @log_current_level = level - puts "> %-30s %s:\n %s" % [@stage, @target, text] + print "\033[2K> %-30s %s: %s\r" % [@stage, @target, text] nil end diff --git a/lib/comfpile/artefact_engine.rb b/lib/comfpile/artefact_engine.rb index aedf3c5..199d9de 100644 --- a/lib/comfpile/artefact_engine.rb +++ b/lib/comfpile/artefact_engine.rb @@ -16,7 +16,7 @@ module Comfpile end def craft(stage, target, context) - context = @core.sanitize_context context + context = @core.get_context_key context @recipes.each do |recipe| match = target @@ -25,10 +25,10 @@ module Comfpile next unless stage == recipe[:stage] end - if r = recipe[:regex] + if not (r = recipe[:regex]).nil? if r.is_a? String next unless target == r - else + elsif r.is_a? Regexp match = r.match target next if match.nil? end @@ -51,7 +51,7 @@ module Comfpile other.subpriority <=> self.subpriority end - def add_recipe(stage = nil, target_regex, &block) + def add_recipe(stage, target_regex = nil, &block) @recipes << { regex: target_regex, stage: stage, diff --git a/lib/comfpile/context.rb b/lib/comfpile/context.rb index 4562ece..41af118 100644 --- a/lib/comfpile/context.rb +++ b/lib/comfpile/context.rb @@ -53,17 +53,7 @@ module Comfpile tags.empty? end - def hash - @tag.hash - end - def eql?(other) - if(other.is_a? Symbol) - @tag.eql? other - elsif(other.is_a? ContextTag) - @tag.eql? other.tag - end - end end # @@ -119,78 +109,88 @@ module Comfpile raise ArgumentError, "Attempted to set child-parameter of another parameter!" end - current_hash[key[-1]] = value - - value - end - alias set []= - - def set_flag(key, value) - set resolve_key(key).append(value), true - end - def get_flags(key) - (@config_options&.dig(*resolve_key(key)) || {}).keys + return @provider.provide_context(new_keys) end - def dig(arg0, *args) - @config_options&.dig(arg0, *args) - end - - def append(key, value) - key = resolve_key key - array = @config_options&.dig(*key) - - if array.nil? - array = set key, [] - end - - raise ArgumentError, "Attempted to append to a non-list parameter!" unless array.is_a? Array - - array << value - end - alias append_to append - - def assert(orig_key, value) - key = resolve_key orig_key - current_value = @config_options&.dig(*key) - - if current_value.nil? - set key, value - elsif current_value != value - raise ArgumentError, "Config key assertion failed! #{orig_key} should be #{value}, is #{current_value}!" - end - end - - def build_config - @config_options = nil - - @seeder_blocks.sort { |block| block[:priority] }.each do |block| - self.instance_exec(block, &block[:block]) - end - - self.freeze + def to_s + "CTX[" + @context_symbol.to_s + "]" end + alias inspect to_s end - - class ContextConfigContainer + + class ContextKeyProvider def initialize - @context_configs_seeds = [] + @known_context_keys = Hash.new end - def find_seeds_for(context_tag) - out = [] + def symbol_to_keys(symbol) + raise ArgumentError, 'Input symbol needs to be a Symbol!' unless symbol.is_a? Symbol - @context_configs_seeds.each do |seed| - seed_tags = seed[:context_tags] - - seed_tags.each do |tag| + out_keys = Hash.new + symbol.to_s.split(';').each do |key| + if key =~ /(?[^=]+)=(?[^=]+)/ + out_keys[$~['key'].to_sym] = $~['value'].to_s + else + out_keys[key.to_sym] = true end end + + out_keys end - def add_to_config(context_config) - raise ArgumentError, "No context supplied!" unless context_config.is_a? ContextConfig + def sanitize_keys(keys) + out_keys = Hash.new + + keys.each do |key, value| + if value.is_a? TrueClass + out_keys[key.to_sym] = true + elsif (not value.nil?) and (not value.is_a? FalseClass) + out_keys[key.to_sym] = value.to_s + end + end + + out_keys + end + + def keys_to_symbol(keys) + raise ArgumentError, 'Keys needs to be a Hash!' unless keys.is_a? Hash + + keys.keys.sort.map do |key| + value = keys[key] + + if value.is_a? TrueClass + key.to_s + elsif value.is_a? FalseClass + nil + else + "#{key}=#{value}" + end + end.compact.join(';').to_sym + end + + def provide_context(ctx) + return ctx if ctx.is_a? ContextKey + + orig_ctx = ctx + + return @known_context_keys[ctx] if @known_context_keys.include? ctx + + ctx = symbol_to_keys(ctx) if ctx.is_a? Symbol + ctx = sanitize_keys(ctx) + + ctx_symbol = keys_to_symbol(ctx) + + if @known_context_keys.include? ctx + existing_ctx = @known_context_keys[ctx] + @known_context_keys[orig_ctx] = existing_ctx + return existing_ctx + end + + new_ctx = ContextKey.new(self, ctx, ctx_symbol) + + @known_context_keys[ctx] = new_ctx + @known_context_keys[ctx_symbol] = new_ctx end end end \ No newline at end of file diff --git a/lib/comfpile/core.rb b/lib/comfpile/core.rb index 3a9bb05..92cacae 100644 --- a/lib/comfpile/core.rb +++ b/lib/comfpile/core.rb @@ -1,4 +1,6 @@ +require 'digest' + require_relative 'artefact_engine.rb' require_relative 'context.rb' @@ -7,7 +9,9 @@ module Comfpile class Core attr_reader :processing_stack - def initialize() + def initialize(build_dir_path: File.join('/tmp/comfpile/', Digest::MD5.hexdigest(Dir.pwd))) + @build_dir_path = File.expand_path(build_dir_path) + @artefact_engines = [] @artefact_prio_counter = 0 @@ -15,44 +19,18 @@ module Comfpile # First query is stage, second filename. @artefacts = {} - @valid_contexts = {} - # Stack-style processing queue for item processing @processing_stack = [] + + @context_key_provider = ContextKeyProvider.new() end - # Sanitize and unify context tags. - # This function will take either an array of tags, or a symbol, - # and sanitize and unify it to match a predictable context tag - # format. - # - # Context tags are symbols containing a list of unique configs - # types to use, separated by underscore ('_') - # - # @param [Array, Symbol] context The context to - # sanitize - # - # @return [Symbol] Sanitized context. Unique, sorted list - # of tags, joined into a Symbol. - # - def sanitize_context(context) - if context.nil? - return :default - elsif context.is_a? Array - new_context = context.uniq.sort.join('_').to_sym - @valid_contexts[new_context] = true - - return new_context - elsif context.is_a? Symbol - return context if @valid_contexts[context] - return sanitize_context(context.to_s.split('_')) - else - raise ArgumentError, "Unknown context key type supplied!" - end + def get_context_key(key) + return @context_key_provider.provide_context(key) end def find_artefact(stage, file = :none, context = :default) - context = sanitize_context(context) + context = get_context_key(context) @artefacts.dig(context, stage, file) end @@ -73,7 +51,7 @@ module Comfpile # @return [Comfpile::Artefact, nil] Found or created artefact, or nil if nothing could be done # def craft_artefact(stage, file = :none, context = :default) - context = sanitize_context(context) + context = get_context_key(context) artefact = find_artefact(stage, file, context) @@ -97,7 +75,7 @@ module Comfpile end def add_artefact(stage, file = :none, context = :default, engine: nil, artefact_class: Comfpile::Artefact) - context = sanitize_context context + context = get_context_key context return unless find_artefact(stage, file, context).nil? @@ -165,6 +143,12 @@ module Comfpile nil end + def get_context_build_dir_path(context) + context = context.context if context.is_a? Artefact + + File.expand_path(File.join(@build_dir_path, context.to_s)) + end + def execute_step return if @processing_stack.empty? # puts "Got #{@processing_stack.length} items..." @@ -177,9 +161,14 @@ module Comfpile # puts "Processing artefact #{artefact.stage} #{artefact.target}" - begin - artefact.execute_step - rescue ArtefactExecSkipError + build_path = get_context_build_dir_path(artefact) + FileUtils.mkpath build_path + + Dir.chdir build_path do + begin + artefact.execute_step + rescue ArtefactExecSkipError + end end nil diff --git a/lib/comfpile/engines/config_engine.rb b/lib/comfpile/engines/config_engine.rb index ef7b911..ec98a56 100644 --- a/lib/comfpile/engines/config_engine.rb +++ b/lib/comfpile/engines/config_engine.rb @@ -25,7 +25,9 @@ module Comfpile end @config_file_artefact = craft_artefact(:sourcefile, File.join(@target, "comf.yml")) - wait_on @config_file_artefact + return if @config_file_artefact.nil? + + wait_on @config_file_artefact add_step do unless @config_file_artefact.nil? diff --git a/lib/comfpile/engines/filesource_engine.rb b/lib/comfpile/engines/filesource_engine.rb index b126072..eef059f 100644 --- a/lib/comfpile/engines/filesource_engine.rb +++ b/lib/comfpile/engines/filesource_engine.rb @@ -6,18 +6,23 @@ module Comfpile alias path filename alias file filename - def initialize(*args, file: filename, **opts) + def initialize(*args, file: nil, **opts) super(*args, **opts) - @filename = file + @original_filename = file - unless File.exist? @filename + unless File.exist? @original_filename fail! "File could not be loaded!" return end - # TODO add actual file reading/copying to build dir + @filename = @target + + add_step do + FileUtils.mkpath File.dirname(@filename) + FileUtils.cp @original_filename, @filename + end end def mtime @@ -35,7 +40,7 @@ module Comfpile def craft(stage, target, context) return nil unless stage == :sourcefile - full_path = File.join(@root_path, target) + full_path = File.expand_path(File.join(@root_path, target)) return nil unless File.exists? full_path diff --git a/lib/comfpile/engines/parser_engine.rb b/lib/comfpile/engines/parser_engine.rb index 26f4836..7197829 100644 --- a/lib/comfpile/engines/parser_engine.rb +++ b/lib/comfpile/engines/parser_engine.rb @@ -117,7 +117,7 @@ module Comfpile end def sourcefile_dependency_step - ['include', 'require', 'reference'].map do |key| + ['include', 'require', 'reference'].each do |key| key_artefacts = resolve_sourcefile(find_parsed_parameters(key), optional: key == 'include') @parsed_dependencies[key] = key_artefacts.map { |key| craft_artefact(:parsed, key) } diff --git a/lib/comfpile/old_context.rb b/lib/comfpile/old_context.rb new file mode 100644 index 0000000..cbc70a0 --- /dev/null +++ b/lib/comfpile/old_context.rb @@ -0,0 +1,171 @@ + + +module Comfpile + class ContextTag + def initialize(tag) + @@known_tags ||= {} + + case tag + when Symbol, String + precompiled = @@known_tags[tag.to_sym] + + if not precompiled.nil? + @tag = precompiled[:tag] + @tag_array = precompiled[:array] + else + @tag_array = tag.to_s.split('_').uniq.sort + + end + when Array + @tag_array = tag.map(&:to_s).uniq.sort + @tag = @tag_array + end + + @tag ||= @tag_array.join('_').to_sym + + tag_data = { + tag: @tag, + array: @ŧag_array + } + + @@known_tags[@tag] ||= tag_data + @@known_tags[tag] ||= tag_data + end + + + def self.tagify(tag) + @known_tags ||= {} + + + end + + end + + # + # This class represents the configuration of a specific context. + # It has two main jobs: + # To provide functions to set up and merge configuration options + # from the various tags given to it, and + # to give reader options for the various config options. + # + # Most importantly, it contains mechanisms for safely setting up + # configurations and flagging issues. + # + class ContextConfig + attr_reader :context_tag + + attr_reader :config_options + + def initialize(context_tag, parent) + @context_tag = context_tag + + @seeder_blocks = [] + + @config_options = nil + end + + def add_seeder_block(priority, &block) + @seeder_blocks << { + priority: priority, + block: block + } + end + + def resolve_key(key) + if key.is_a? Array + return key.map {|k| k.to_sym } + elsif key.is_a? String + return key.split('.').map {|k| k.to_sym } + elsif key.is_a? Symbol + return resolve_key(key.to_s) + end + end + + def [](key) + @config_options&.dig(*resolve_key(key)) + end + def []=(key, value) + key = resolve_key(key) + + current_hash = (@config_options ||= {}) + key[0..-2].each do |key| + current_hash = (current_hash[key] ||= {}) + next if current_hash.is_a? Hash + raise ArgumentError, "Attempted to set child-parameter of another parameter!" + end + + current_hash[key[-1]] = value + + value + end + alias set []= + + def set_flag(key, value) + set resolve_key(key).append(value), true + end + def get_flags(key) + (@config_options&.dig(*resolve_key(key)) || {}).keys + end + + def dig(arg0, *args) + @config_options&.dig(arg0, *args) + end + + def append(key, value) + key = resolve_key key + array = @config_options&.dig(*key) + + if array.nil? + array = set key, [] + end + + raise ArgumentError, "Attempted to append to a non-list parameter!" unless array.is_a? Array + + array << value + end + alias append_to append + + def assert(orig_key, value) + key = resolve_key orig_key + current_value = @config_options&.dig(*key) + + if current_value.nil? + set key, value + elsif current_value != value + raise ArgumentError, "Config key assertion failed! #{orig_key} should be #{value}, is #{current_value}!" + end + end + + def build_config + @config_options = nil + + @seeder_blocks.sort { |block| block[:priority] }.each do |block| + self.instance_exec(block, &block[:block]) + end + + self.freeze + end + end + + class ContextConfigContainer + def initialize + @context_configs_seeds = [] + end + + def find_seeds_for(context_tag) + out = [] + + @context_configs_seeds.each do |seed| + seed_tags = seed[:context_tags] + + seed_tags.each do |tag| + + end + end + end + + def add_to_config(context_config) + raise ArgumentError, "No context supplied!" unless context_config.is_a? ContextConfig + end + end +end \ No newline at end of file diff --git a/test/faux_build_dir/spi_master_tb.vhd b/spi_master_tb.vhd similarity index 100% rename from test/faux_build_dir/spi_master_tb.vhd rename to spi_master_tb.vhd diff --git a/test/faux_build_dir/lib_test/comf.yml b/test/faux_build_dir/cpp/lib_test/comf.yml similarity index 100% rename from test/faux_build_dir/lib_test/comf.yml rename to test/faux_build_dir/cpp/lib_test/comf.yml diff --git a/test/faux_build_dir/lib_test/test.cpp b/test/faux_build_dir/cpp/lib_test/test.cpp similarity index 100% rename from test/faux_build_dir/lib_test/test.cpp rename to test/faux_build_dir/cpp/lib_test/test.cpp diff --git a/test/faux_build_dir/lib_test/test.h b/test/faux_build_dir/cpp/lib_test/test.h similarity index 100% rename from test/faux_build_dir/lib_test/test.h rename to test/faux_build_dir/cpp/lib_test/test.h diff --git a/test/faux_build_dir/lib_test/test_settings.h b/test/faux_build_dir/cpp/lib_test/test_settings.h similarity index 100% rename from test/faux_build_dir/lib_test/test_settings.h rename to test/faux_build_dir/cpp/lib_test/test_settings.h diff --git a/test/faux_build_dir/cpp/main.cpp b/test/faux_build_dir/cpp/main.cpp new file mode 100644 index 0000000..b9976e1 --- /dev/null +++ b/test/faux_build_dir/cpp/main.cpp @@ -0,0 +1,23 @@ + +// Your First C++ Program + +#include + +#include "main.h" + +void print_bar() { + std::cout << "Bar"; +} + +#ifdef COMF_MAIN + +int main() { + + print_bar(); + print_foo(); + + std::cout << "Hello World!"; + return 0; +} + +#endif \ No newline at end of file diff --git a/test/faux_build_dir/cpp/main.h b/test/faux_build_dir/cpp/main.h new file mode 100644 index 0000000..773e68f --- /dev/null +++ b/test/faux_build_dir/cpp/main.h @@ -0,0 +1,9 @@ + + +#pragma once + +// comf.reference main.cpp +// comf.reference main2.cpp + +void print_foo(); +void print_bar(); \ No newline at end of file diff --git a/test/faux_build_dir/cpp/main2.cpp b/test/faux_build_dir/cpp/main2.cpp new file mode 100644 index 0000000..20bc337 --- /dev/null +++ b/test/faux_build_dir/cpp/main2.cpp @@ -0,0 +1,22 @@ + +// Your First C++ Program + +#include + +#include "main.h" + +void print_foo() { + std::cout << "Foo"; +} + +#ifdef COMF_MAIN + +int main() { + print_foo(); + print_bar(); + + std::cout << "Hello World!"; + return 0; +} + +#endif \ No newline at end of file diff --git a/test/faux_build_dir/main.cpp b/test/faux_build_dir/main.cpp deleted file mode 100644 index 90e1541..0000000 --- a/test/faux_build_dir/main.cpp +++ /dev/null @@ -1,8 +0,0 @@ - - -#include "main.h" -#include - -int main() { - return 0; -} \ No newline at end of file diff --git a/test/faux_build_dir/main.h b/test/faux_build_dir/main.h deleted file mode 100644 index 5c55a78..0000000 --- a/test/faux_build_dir/main.h +++ /dev/null @@ -1,5 +0,0 @@ - - -#pragma once - -#include "lib_test/test.h" \ No newline at end of file diff --git a/test/faux_build_dir/UQDS_specifics_pkg.vhd b/test/faux_build_dir/vhdl/UQDS_specifics_pkg.vhd similarity index 100% rename from test/faux_build_dir/UQDS_specifics_pkg.vhd rename to test/faux_build_dir/vhdl/UQDS_specifics_pkg.vhd diff --git a/test/faux_build_dir/vhdl/comf.yml b/test/faux_build_dir/vhdl/comf.yml new file mode 100644 index 0000000..2646a61 --- /dev/null +++ b/test/faux_build_dir/vhdl/comf.yml @@ -0,0 +1 @@ +test: Hellooooo diff --git a/test/faux_build_dir/spi_master.vhd b/test/faux_build_dir/vhdl/spi_master.vhd similarity index 100% rename from test/faux_build_dir/spi_master.vhd rename to test/faux_build_dir/vhdl/spi_master.vhd diff --git a/test/faux_build_dir/vhdl/spi_master_tb.vhd b/test/faux_build_dir/vhdl/spi_master_tb.vhd new file mode 100644 index 0000000..e299bcb --- /dev/null +++ b/test/faux_build_dir/vhdl/spi_master_tb.vhd @@ -0,0 +1,108 @@ + +-- comf.include: UQDS_specifics_pkg.vhd + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library uqdslib; +use uqdslib.UQDS_Specifics_pkg.all; + +entity spi_master_tb is +end; + +architecture bench of spi_master_tb is + -- Clock period + constant clk_period : time := 5 ns; + -- Generics + constant clkdiv : integer := 40; + constant clk_idle : std_logic := '1'; + + -- Ports + signal rst : std_logic := '0'; + signal clk : std_logic; + signal data_tx : std_logic_vector(7 downto 0); + signal data_rx : std_logic_vector(7 downto 0); + signal send_request : std_logic; + signal byte_tx_complete : std_logic; + signal byte_rx_complete : std_logic; + signal pin_mosi : std_logic; + signal pin_miso : std_logic; + signal pin_clk : std_logic; + + signal test_done : std_logic := '0'; + +begin + + spi_master_inst : uqdslib.UQDS_Specifics_pkg.spi_master + generic map ( + clkdiv => clkdiv, + clk_idle => clk_idle + ) + port map ( + rst => rst, + clk => clk, + spi_control_to.data_tx => data_tx, + spi_control_to.send_request => send_request, + spi_control_from.data_rx => data_rx, + spi_control_from.byte_tx_complete => byte_tx_complete, + spi_control_from.byte_rx_complete => byte_rx_complete, + pin_mosi => pin_mosi, + pin_miso => pin_miso, + pin_clk => pin_clk + ); + + pin_miso <= pin_mosi; + + clk_process : process + begin + clk <= '1'; + wait for clk_period/2; + clk <= '0'; + wait for clk_period/2; + + if(test_done) then wait; end if; + end process clk_process; + + data_process : process + begin + + rst <= '1'; + wait for 100 ns; + rst <= '0'; + + for i in 0 to 4 loop + data_tx <= std_logic_vector(to_unsigned(i, data_tx'length)); + send_request <= '1'; + wait until falling_edge(byte_tx_complete) for 1 ms; + send_request <= '0'; + end loop; + + for i in 0 to 4 loop + data_tx <= std_logic_vector(to_unsigned(i, data_tx'length)); + send_request <= '1'; + wait until falling_edge(byte_tx_complete) for 1 ms; + send_request <= '0'; + + wait for 1.5 us; + end loop; + + data_tx <= std_logic_vector(to_unsigned(69, data_tx'length)); + send_request <= '1'; + wait until falling_edge(byte_tx_complete) for 1 ms; + send_request <= '0'; + + wait for 400 ns; + rst <= '1'; + wait for 100 ns; + rst <= '0'; + wait for 3 us; + + test_done <= '1'; + + wait until falling_edge(byte_rx_complete) for 1 us; + + wait; + + end process data_process; +end;