rggen-core 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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