rggen-core 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. checksums.yaml +7 -0
  2. data/CODE_OF_CONDUCT.md +46 -0
  3. data/LICENSE +21 -0
  4. data/README.md +46 -0
  5. data/exe/rggen +13 -0
  6. data/lib/rggen/core.rb +101 -0
  7. data/lib/rggen/core/base/component.rb +54 -0
  8. data/lib/rggen/core/base/component_factory.rb +84 -0
  9. data/lib/rggen/core/base/feature.rb +46 -0
  10. data/lib/rggen/core/base/feature_factory.rb +37 -0
  11. data/lib/rggen/core/base/hierarchical_accessors.rb +91 -0
  12. data/lib/rggen/core/base/hierarchical_feature_accessors.rb +83 -0
  13. data/lib/rggen/core/base/internal_struct.rb +21 -0
  14. data/lib/rggen/core/base/shared_context.rb +18 -0
  15. data/lib/rggen/core/builder.rb +13 -0
  16. data/lib/rggen/core/builder/builder.rb +150 -0
  17. data/lib/rggen/core/builder/category.rb +116 -0
  18. data/lib/rggen/core/builder/component_entry.rb +29 -0
  19. data/lib/rggen/core/builder/component_registry.rb +47 -0
  20. data/lib/rggen/core/builder/feature_registry.rb +126 -0
  21. data/lib/rggen/core/builder/input_component_registry.rb +35 -0
  22. data/lib/rggen/core/builder/list_feature_entry.rb +98 -0
  23. data/lib/rggen/core/builder/output_component_registry.rb +10 -0
  24. data/lib/rggen/core/builder/simple_feature_entry.rb +39 -0
  25. data/lib/rggen/core/cli.rb +29 -0
  26. data/lib/rggen/core/configuration.rb +19 -0
  27. data/lib/rggen/core/configuration/component.rb +10 -0
  28. data/lib/rggen/core/configuration/component_factory.rb +19 -0
  29. data/lib/rggen/core/configuration/error.rb +16 -0
  30. data/lib/rggen/core/configuration/feature.rb +13 -0
  31. data/lib/rggen/core/configuration/feature_factory.rb +11 -0
  32. data/lib/rggen/core/configuration/hash_loader.rb +15 -0
  33. data/lib/rggen/core/configuration/json_loader.rb +18 -0
  34. data/lib/rggen/core/configuration/loader.rb +11 -0
  35. data/lib/rggen/core/configuration/ruby_loader.rb +15 -0
  36. data/lib/rggen/core/configuration/yaml_loader.rb +18 -0
  37. data/lib/rggen/core/core_extensions/casecmp.rb +12 -0
  38. data/lib/rggen/core/core_extensions/forwardable.rb +12 -0
  39. data/lib/rggen/core/core_extensions/forwardable_workaround.rb +22 -0
  40. data/lib/rggen/core/core_extensions/object.rb +14 -0
  41. data/lib/rggen/core/dsl.rb +30 -0
  42. data/lib/rggen/core/exceptions.rb +29 -0
  43. data/lib/rggen/core/facets.rb +7 -0
  44. data/lib/rggen/core/generator.rb +51 -0
  45. data/lib/rggen/core/input_base/component.rb +30 -0
  46. data/lib/rggen/core/input_base/component_factory.rb +88 -0
  47. data/lib/rggen/core/input_base/feature.rb +130 -0
  48. data/lib/rggen/core/input_base/feature_factory.rb +80 -0
  49. data/lib/rggen/core/input_base/input_data.rb +98 -0
  50. data/lib/rggen/core/input_base/input_matcher.rb +79 -0
  51. data/lib/rggen/core/input_base/input_value.rb +34 -0
  52. data/lib/rggen/core/input_base/json_loader.rb +16 -0
  53. data/lib/rggen/core/input_base/loader.rb +44 -0
  54. data/lib/rggen/core/input_base/property.rb +76 -0
  55. data/lib/rggen/core/input_base/verifier.rb +41 -0
  56. data/lib/rggen/core/input_base/yaml_loader.rb +34 -0
  57. data/lib/rggen/core/options.rb +181 -0
  58. data/lib/rggen/core/output_base/code_generator.rb +59 -0
  59. data/lib/rggen/core/output_base/component.rb +100 -0
  60. data/lib/rggen/core/output_base/component_factory.rb +35 -0
  61. data/lib/rggen/core/output_base/erb_engine.rb +21 -0
  62. data/lib/rggen/core/output_base/feature.rb +147 -0
  63. data/lib/rggen/core/output_base/feature_factory.rb +13 -0
  64. data/lib/rggen/core/output_base/file_writer.rb +40 -0
  65. data/lib/rggen/core/output_base/template_engine.rb +27 -0
  66. data/lib/rggen/core/printers.rb +53 -0
  67. data/lib/rggen/core/register_map.rb +21 -0
  68. data/lib/rggen/core/register_map/component.rb +20 -0
  69. data/lib/rggen/core/register_map/component_factory.rb +19 -0
  70. data/lib/rggen/core/register_map/error.rb +16 -0
  71. data/lib/rggen/core/register_map/feature.rb +22 -0
  72. data/lib/rggen/core/register_map/feature_factory.rb +11 -0
  73. data/lib/rggen/core/register_map/hash_loader.rb +47 -0
  74. data/lib/rggen/core/register_map/input_data.rb +34 -0
  75. data/lib/rggen/core/register_map/json_loader.rb +18 -0
  76. data/lib/rggen/core/register_map/loader.rb +15 -0
  77. data/lib/rggen/core/register_map/ruby_loader.rb +15 -0
  78. data/lib/rggen/core/register_map/yaml_loader.rb +18 -0
  79. data/lib/rggen/core/utility/attribute_setter.rb +53 -0
  80. data/lib/rggen/core/utility/code_utility.rb +64 -0
  81. data/lib/rggen/core/utility/code_utility/code_block.rb +88 -0
  82. data/lib/rggen/core/utility/code_utility/line.rb +51 -0
  83. data/lib/rggen/core/utility/code_utility/source_file.rb +104 -0
  84. data/lib/rggen/core/utility/code_utility/structure_definition.rb +54 -0
  85. data/lib/rggen/core/utility/regexp_patterns.rb +38 -0
  86. data/lib/rggen/core/version.rb +10 -0
  87. metadata +188 -0
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module InputBase
6
+ class Property
7
+ def self.define(feature, name, **options, &body)
8
+ new(name, options, body).define(feature)
9
+ end
10
+
11
+ def initialize(name, options, body)
12
+ @name = name
13
+ @options = options
14
+ @costom_property = create_costom_property(@options[:body] || body)
15
+ end
16
+
17
+ attr_reader :name
18
+
19
+ def define(feature)
20
+ feature.class_exec(self) do |property|
21
+ define_method(property.name) do |*args, &block|
22
+ property.evaluate(self, args, block)
23
+ end
24
+ end
25
+ end
26
+
27
+ def evaluate(feature, args, block)
28
+ feature.verify(@options[:verify]) if @options.key?(:verify)
29
+ if proxy_property?
30
+ proxy_property(feature, args, block)
31
+ else
32
+ default_property(feature)
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def create_costom_property(body)
39
+ body && Module.new.module_eval do
40
+ define_method(:__costom_property__, &body)
41
+ instance_method(:__costom_property__)
42
+ end
43
+ end
44
+
45
+ def proxy_property?
46
+ [
47
+ @costom_property,
48
+ @options[:forward_to_helper],
49
+ @options[:forward_to]
50
+ ].any?
51
+ end
52
+
53
+ def proxy_property(feature, args, block)
54
+ receiver, method =
55
+ if @costom_property
56
+ [@costom_property.bind(feature), :call]
57
+ elsif @options[:forward_to_helper]
58
+ [feature.class, @name]
59
+ else
60
+ [feature, @options[:forward_to]]
61
+ end
62
+ receiver.__send__(method, *args, &block)
63
+ end
64
+
65
+ def default_property(feature)
66
+ varible_name = "@#{@name[-1] == '?' ? @name[0..-2] : @name}"
67
+ if feature.instance_variable_defined?(varible_name)
68
+ feature.instance_variable_get(varible_name)
69
+ else
70
+ @options[:default]
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module InputBase
6
+ class Verifier
7
+ def initialize(&block)
8
+ instance_eval(&block)
9
+ end
10
+
11
+ def check_error(&block)
12
+ @error_checker = block
13
+ end
14
+
15
+ def error_condition(&block)
16
+ @condition = block
17
+ end
18
+
19
+ def message(&block)
20
+ @message = block
21
+ end
22
+
23
+ def verify(feature)
24
+ if @error_checker
25
+ feature.instance_eval(&@error_checker)
26
+ else
27
+ default_error_check(feature)
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def default_error_check(feature)
34
+ feature.instance_exec(@condition, @message) do |condition, message|
35
+ instance_eval(&condition) && error(instance_eval(&message))
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module InputBase
6
+ module YAMLLoader
7
+ private
8
+
9
+ def load_yaml(file)
10
+ yaml = File.binread(file)
11
+ result =
12
+ if Psych::VERSION >= '3.1.0'
13
+ YAML.safe_load(yaml, aliases: true, filename: file)
14
+ else
15
+ YAML.safe_load(yaml, [], [], true, file)
16
+ end
17
+ symbolize_key(result)
18
+ end
19
+
20
+ def symbolize_key(result)
21
+ case result
22
+ when Hash
23
+ result.keys.each do |key|
24
+ result[key.to_sym] = symbolize_key(result.delete(key))
25
+ end
26
+ when Array
27
+ result.map! { |value| symbolize_key(value) }
28
+ end
29
+ result
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,181 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ class Options
6
+ extend ::Forwardable
7
+
8
+ class Option
9
+ def initialize(option_name)
10
+ @option_name = option_name
11
+ block_given? && yield(self)
12
+ end
13
+
14
+ def enable(parser, options)
15
+ options[@option_name] ||= default
16
+ parser.on(*args) { |value| handler(value, options, parser) }
17
+ end
18
+
19
+ attr_setter :short_option
20
+ attr_setter :long_option
21
+ attr_setter :option_class
22
+
23
+ def default(value = nil, &block)
24
+ if block_given?
25
+ @default = block
26
+ elsif !value.nil?
27
+ @default = -> { value }
28
+ elsif @default
29
+ instance_exec(&@default)
30
+ end
31
+ end
32
+
33
+ def description(value = nil)
34
+ if value
35
+ @description = value
36
+ else
37
+ @description
38
+ end
39
+ end
40
+
41
+ def action(&block)
42
+ if block_given?
43
+ @action = block
44
+ else
45
+ @action || default_action
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def args
52
+ [@short_option, @long_option, @option_class, description].compact
53
+ end
54
+
55
+ def default_action
56
+ proc do |value, options, option_name, _parser|
57
+ options[option_name] = value
58
+ end
59
+ end
60
+
61
+ def handler(value, options, parser)
62
+ instance_exec(value, options, @option_name, parser, &action)
63
+ end
64
+ end
65
+
66
+ def self.options
67
+ @options ||= {}
68
+ end
69
+
70
+ def self.add_option(option_name, &body)
71
+ options[option_name] = Option.new(option_name, &body)
72
+ end
73
+
74
+ def initialize
75
+ @options = {}
76
+ end
77
+
78
+ attr_reader :original_args
79
+ attr_reader :register_map_files
80
+
81
+ def_delegator :@options, :[]
82
+
83
+ def parse(args)
84
+ @original_args = args
85
+ @register_map_files = option_parser.parse(args)
86
+ end
87
+
88
+ private
89
+
90
+ def option_parser
91
+ OptionParser.new do |parser|
92
+ parser.program_name = 'rggen'
93
+ parser.version = RgGen::Core::VERSION
94
+ parser.banner = 'Usage: rggen [options] register_map_files'
95
+ define_options(parser)
96
+ end
97
+ end
98
+
99
+ def define_options(parser)
100
+ self.class.options.each_value { |o| o.enable(parser, @options) }
101
+ end
102
+ end
103
+
104
+ Options.add_option(:setup) do |option|
105
+ option.long_option '--setup FILE'
106
+ option.default { default_steup_file }
107
+ option.description 'Specify a Ruby file to set up RgGen tool'
108
+
109
+ def option.default_steup_file
110
+ ENV['RGGEN_DEFAULT_SETUP_FILE'] || define_setup_file_from_const
111
+ end
112
+
113
+ def option.define_setup_file_from_const
114
+ require 'rggen/default_setup_file'
115
+ RgGen::DEFAULT_SETUP_FILE
116
+ rescue ::LoadError
117
+ nil
118
+ end
119
+ end
120
+
121
+ Options.add_option(:configuration) do |option|
122
+ option.short_option '-c'
123
+ option.long_option '--configuration FILE'
124
+ option.default { ENV['RGGEN_DEFAULT_CONFIGURATION_FILE'] }
125
+ option.description 'Specify a configuration file'
126
+ end
127
+
128
+ Options.add_option(:output) do |option|
129
+ option.short_option '-o'
130
+ option.long_option '--output DIRECTORY'
131
+ option.default { '.' }
132
+ option.description 'Specify the directory where ' \
133
+ 'generated file(s) will be written'
134
+ end
135
+
136
+ Options.add_option(:load_only) do |option|
137
+ option.long_option '--load-only'
138
+ option.default false
139
+ option.description 'Load setup, configuration and register map ' \
140
+ 'files only; write no files'
141
+ end
142
+
143
+ Options.add_option(:enable) do |option|
144
+ option.long_option '--enable WRITER1[,WRITER2,...]'
145
+ option.option_class Array
146
+ option.default { [] }
147
+ option.action { |v, o, n| merge_enabled_writers(v, o, n) }
148
+ option.description 'Enable only the given writer(s) to write files'
149
+
150
+ def option.merge_enabled_writers(value, options, option_name)
151
+ options[option_name].concat(value.map(&:to_sym))
152
+ end
153
+ end
154
+
155
+ Options.add_option(:version) do |option|
156
+ option.short_option '-v'
157
+ option.long_option '--version'
158
+ option.action do |_value, options|
159
+ options[:runner] = VersionPrinter.new(false)
160
+ end
161
+ option.description 'Display version'
162
+ end
163
+
164
+ Options.add_option(:verbose_version) do |option|
165
+ option.long_option '--verbose-version'
166
+ option.action do |_value, options|
167
+ options[:runner] = VersionPrinter.new(true)
168
+ end
169
+ option.description 'Load a setup Ruby file and display verbose version'
170
+ end
171
+
172
+ Options.add_option(:help) do |option|
173
+ option.short_option '-h'
174
+ option.long_option '--help'
175
+ option.action do |_value, options, _name, parser|
176
+ options[:runner] = HelpPrinter.new(parser)
177
+ end
178
+ option.description 'Display this message'
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module OutputBase
6
+ class CodeGenerator
7
+ def register(kind, block)
8
+ return unless block
9
+ code_blocks[kind] << block
10
+ end
11
+
12
+ def generate(context, kind, code)
13
+ return code unless generatable?(kind)
14
+ execute_code_blocks(
15
+ context, kind, code || context.create_blank_code
16
+ )
17
+ end
18
+
19
+ def copy
20
+ generator = CodeGenerator.new
21
+ generator.copy_code_blocks(@code_blocks) if @code_blocks
22
+ generator
23
+ end
24
+
25
+ private
26
+
27
+ def code_blocks
28
+ @code_blocks ||= Hash.new { |blocks, kind| blocks[kind] = [] }
29
+ end
30
+
31
+ def generatable?(kind)
32
+ @code_blocks&.key?(kind)
33
+ end
34
+
35
+ def execute_code_blocks(context, kind, code)
36
+ code_blocks[kind].each(&code_block_executor(context, code))
37
+ code
38
+ end
39
+
40
+ def code_block_executor(context, code)
41
+ lambda do |block|
42
+ if block.arity.zero?
43
+ code << context.instance_exec(&block)
44
+ else
45
+ context.instance_exec(code, &block)
46
+ end
47
+ end
48
+ end
49
+
50
+ protected
51
+
52
+ def copy_code_blocks(original_blocks)
53
+ original_blocks
54
+ .each { |kind, blocks| code_blocks[kind] = blocks.dup }
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RgGen
4
+ module Core
5
+ module OutputBase
6
+ class Component < Base::Component
7
+ include Base::HierarchicalAccessors
8
+
9
+ attr_reader :configuration
10
+ attr_reader :source
11
+
12
+ def post_initialize(_paren, configuration, source)
13
+ @configuration = configuration
14
+ @source = source
15
+ @need_children = source.need_children?
16
+ define_hierarchical_accessors
17
+ define_property_accessors
18
+ define_children_presense_indicator
19
+ end
20
+
21
+ def children?
22
+ !source.children.empty?
23
+ end
24
+
25
+ def add_feature(feature)
26
+ super
27
+ import_feature_methods(feature, :class)
28
+ end
29
+
30
+ def pre_build
31
+ @features.each_value(&:pre_build)
32
+ end
33
+
34
+ def build
35
+ @features.each_value(&method(:build_feature))
36
+ @children.each(&:build)
37
+ end
38
+
39
+ def generate_code(kind, mode, code = nil)
40
+ code_generators(kind, mode).inject(code) { |c, g| g[c] }
41
+ end
42
+
43
+ def write_file(directory = nil)
44
+ @features.each_value { |feature| feature.write_file(directory) }
45
+ @children.each { |component| component.write_file(directory) }
46
+ end
47
+
48
+ private
49
+
50
+ def define_property_accessors
51
+ def_delegators(:@source, *@source.properties)
52
+ end
53
+
54
+ INDICATOR_NAMES = {
55
+ register_map: :register_blocks?,
56
+ register_block: :registers?,
57
+ register: :bit_fields?
58
+ }.freeze
59
+
60
+ def define_children_presense_indicator
61
+ indicator_name = INDICATOR_NAMES[hierarchy]
62
+ indicator_name &&
63
+ singleton_exec { alias_method indicator_name, :children? }
64
+ end
65
+
66
+ def build_feature(feature)
67
+ feature.build
68
+ import_feature_methods(feature, :object)
69
+ end
70
+
71
+ def import_feature_methods(feature, scope)
72
+ receiver = "@features[:#{feature.feature_name}]"
73
+ methods = feature.exported_methods(scope)
74
+ def_delegators(receiver, *methods)
75
+ end
76
+
77
+ def code_generators(kind, mode)
78
+ [
79
+ [@features.each_value, [:pre_code, kind]],
80
+ *main_code_contexts(kind, mode),
81
+ [@features.each_value, [:post_code, kind]]
82
+ ].map do |receivers, args|
83
+ lambda do |code|
84
+ receivers.inject(code) { |c, r| r.generate_code(*args, c) }
85
+ end
86
+ end
87
+ end
88
+
89
+ def main_code_contexts(kind, mode)
90
+ contexts = [
91
+ [@features.each_value, [:main_code, kind]],
92
+ [@children, [kind, mode]]
93
+ ]
94
+ contexts.reverse! if mode == :bottom_up
95
+ contexts
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end