• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (c) 2021-2024 Huawei Device Co., Ltd.
2# Licensed under the Apache License, Version 2.0 (the "License");
3# you may not use this file except in compliance with the License.
4# You may obtain a copy of the License at
5#
6# http://www.apache.org/licenses/LICENSE-2.0
7#
8# Unless required by applicable law or agreed to in writing, software
9# distributed under the License is distributed on an "AS IS" BASIS,
10# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11# See the License for the specific language governing permissions and
12# limitations under the License.
13
14require 'ostruct'
15require 'delegate'
16
17class String
18  def snakecase
19    gsub(/::/, '/')
20      .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
21      .gsub(/([a-z\d])([A-Z])/, '\1_\2')
22      .tr('-', '_')
23      .downcase
24  end
25end
26
27class Option < SimpleDelegator
28  def initialize(data)
29    super
30    if has_sub_options
31      raise "Compound option should not have `type` field, it is always bool" if respond_to?(:type)
32      raise "Compound option should not have `default` field, it is always `false``" if respond_to?(:default)
33      self[:type] = 'bool'
34      self[:default] = 'false'
35    end
36  end
37
38  def fix_references(options)
39    if respond_to?(:possible_values) && possible_values.is_a?(String)
40      raise "Wrong reference syntax: #{possible_values}" if possible_values[0] != '$'
41      p = possible_values[1..-1]
42      target = options.find {|x| x.name == p }
43      raise "Invalid reference #{possible_values}" if target.nil?
44      self["possible_values"] = target["possible_values"]
45    end
46  end
47
48  def field_name
49    name.tr('-', '_').tr('.', '_') + '_'
50  end
51
52  def camel_name
53    n = name.split(Regexp.union(['-', '.'])).map(&:capitalize).join
54    sub_option? ? (self.parent.camel_name + n) : n
55  end
56
57  def getter_name
58    type == 'bool' ? 'Is' + camel_name : 'Get' + camel_name
59  end
60
61  def setter_name
62    'Set' + camel_name
63  end
64
65  def sub_option?
66    respond_to?(:parent)
67  end
68
69  def has_sub_options
70    respond_to?(:sub_options)
71  end
72
73  def deprecated?
74    respond_to?(:deprecated) && deprecated
75  end
76
77  def lang_specific?
78    respond_to?(:lang_specific)
79  end
80
81  def has_lang_suboptions?
82    respond_to?(:lang)
83  end
84
85  def lang_field_name(lang)
86    "#{lang}.#{name}".tr('-', '_').tr('.', '_') + '_'
87  end
88
89  def lang_camel_name(lang)
90    n = "#{lang}.#{name}".split(Regexp.union(['-', '.'])).map(&:capitalize).join
91    sub_option? ? (self.parent.camel_name + n) : n
92  end
93
94  def default_value
95    return default.to_h if (default.is_a?(Hash) || default.is_a?(OpenStruct))
96    return default_constant_name if need_default_constant
97    return '{' + default.map { |e| expand_string(e) }.join(', ') + '}' if type == 'arg_list_t'
98    return expand_string(default) if type == 'std::string'
99    default
100  end
101
102  def full_description
103    full_desc = description
104    full_desc.prepend("[DEPRECATED] ") if deprecated?
105    if defined? possible_values
106      full_desc += '. Possible values: ' + possible_values.inspect
107    end
108    if (default.is_a?(Hash) || default.is_a?(OpenStruct))
109      Common::to_raw(full_desc + '. Default: {' + default.to_h.map{ |k, v| "#{k}: #{v}" }.join(", ") + '}')
110    else
111      Common::to_raw(full_desc + '. Default: ' + default.inspect)
112    end
113  end
114
115  def expand_string(s)
116    @expansion_map ||= {
117      '$ORIGIN' => 'exe_dir_'
118    }
119    @expansion_map.each do |k, v|
120      ret = ""
121      if s.include?(k)
122        split = s.split(k);
123        for i in 1..split.length() - 1
124          ret += v + ' + ' + Common::to_raw(split[i])+ ' + '
125        end
126        return ret.delete_suffix(' + ')
127      end
128    end
129    Common::to_raw(s)
130  end
131
132  def need_default_constant
133    type == 'int' || type == 'double' || type == 'uint32_t' || type == 'uint64_t'
134  end
135
136  def default_constant_name
137    name.tr('-', '_').tr('.', '_').upcase + '_DEFAULT'
138  end
139end
140
141class Event < SimpleDelegator
142  def method_name
143    'Event' + name.split('-').map(&:capitalize).join
144  end
145
146  def args_list
147    args = ''
148    delim = ''
149    fields.each do |field|
150      args.concat(delim, field.type, ' ', field.name)
151      delim = ', '
152    end
153    return args
154  end
155
156  def print_line
157    qoute = '"'
158    line = 'events_file_'
159    delim = ' << '
160    fields.each do |field|
161      line.concat(delim, qoute, field.name, qoute)
162      delim = ' << ":" << '
163      line.concat(delim, field.name)
164      delim = ' << "," << '
165    end
166    return line
167  end
168
169end
170
171module Common
172  module_function
173
174  def create_sub_options(option, options)
175    return unless option.has_sub_options
176    raise "Only boolean option can have sub options: #{option.name}" unless option.type == 'bool'
177    sub_options = []
178    option.sub_options.each_with_object(sub_options) do |sub_option, sub_options|
179      sub_option[:parent] = option
180      sub_options << Option.new(sub_option)
181    end
182    options.concat sub_options
183    option[:sub_options] = sub_options
184  end
185
186  def options
187    @options ||= @data.options.each_with_object([]) do |option, options|
188      option_hash = option.to_h
189      if option_hash.include?(:lang)
190        lang_spec_option = option_hash.clone
191        lang_spec_option.delete(:lang)
192        lang_spec_option[:lang_specific] = true
193        option.lang.each do |lang|
194          lang_spec_option[:description] = "#{option.description}. Only for #{lang}"
195          lang_spec_option[:name] = "#{lang}.#{option.name}"
196          options << Option.new(OpenStruct.new(lang_spec_option))
197          create_sub_options(options[-1], options)
198        end
199        main_option = option_hash.clone
200        main_option[:name] = "#{option.name}"
201        options << Option.new(OpenStruct.new(main_option))
202        create_sub_options(options[-1], options)
203      else
204        options << Option.new(option)
205        create_sub_options(options[-1], options)
206      end
207      options.last.fix_references(@data.options)
208    end
209    @options
210  end
211
212  def events
213    @data.events.map do |op|
214      Event.new(op)
215    end
216  end
217
218  def module
219    @data.module
220  end
221
222  def to_raw(s)
223    'R"(' + s + ')"'
224  end
225
226  def wrap_data(data)
227    @data = data
228  end
229end
230
231def Gen.on_require(data)
232  Common.wrap_data(data)
233end
234