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