1# Copyright (c) 2021-2022 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 Attritute < SimpleDelegator 18 def getter_name 19 r = name.capitalize 20 type == 'bool' ? 'Is' + r : 'Get' + r 21 end 22 23 def setter_name 24 'Set' + name.capitalize 25 end 26 27 def bool? 28 type == 'bool' 29 end 30 31 def enum? 32 type == 'enum' 33 end 34 35 def size? 36 type == 'size' 37 end 38 39 def multiple? 40 !bool? && multiple 41 end 42 43 def applicable_to?(item_type) 44 applicable_to.include?(item_type) 45 end 46 47 def set_flags? 48 (defined? flags) && flags.any? || enum? && values.any? { |v| v.flags && v.flags.any? } 49 end 50end 51 52module Metadata 53 module_function 54 55 def attributes 56 @data.attributes.map do |op| 57 Attritute.new(op) 58 end 59 end 60 61 def language 62 @data.language || '' 63 end 64 65 def extends_default? 66 !language.empty? 67 end 68 69 def item_types 70 ['record', 'field', 'function', 'param'] 71 end 72 73 def wrap_data(data) 74 @data = data 75 end 76end 77 78def Gen.on_require(data) 79 Metadata.wrap_data(data) 80end 81 82module MetadataGen 83 module_function 84 85 def attribute_name(attribute) 86 return attribute.name if Metadata.language.empty? 87 "#{Metadata.language.downcase}.#{attribute.name}" 88 end 89 90 def class_name(item_type) 91 item_type.capitalize + 'Metadata' 92 end 93 94 def validate_body(item_type, is_bool) 95 attributes = Metadata::attributes.select { |a| a.applicable_to?(item_type) && a.bool? == is_bool } 96 body = [] 97 indent = ' ' * 4 98 99 attributes.each do |a| 100 body << "#{indent}if (attribute == \"#{attribute_name(a)}\") {" 101 102 unless a.multiple? 103 body << "#{indent * 2}if (HasAttribute(attribute)) {" 104 body << "#{indent * 3}return Error(\"Attribute '#{attribute_name(a)}' already defined\"," 105 body << "#{indent * 3} Error::Type::MULTIPLE_ATTRIBUTE);" 106 body << "#{indent * 2}}" 107 end 108 109 if a.enum? 110 a.values.each do |v| 111 body << "#{indent * 2}if (value == \"#{v.value}\") {" 112 body << "#{indent * 3}return {};" 113 body << "#{indent * 2}}" 114 body << "" 115 end 116 117 body << "#{indent * 2}return Error(std::string(\"Attribute '#{attribute_name(a)}' have incorrect value '\").append(value) +" 118 body << "#{indent * 2} R\"('. Should be one of #{a.values.map(&:value)})\", Error::Type::INVALID_VALUE);" 119 elsif a.size? 120 body << "#{indent * 2}return ValidateSize(value);" 121 else 122 body << "#{indent * 2}return {};" 123 end 124 125 body << "#{indent}}" 126 body << "" 127 end 128 129 Metadata::attributes.select { |a| a.applicable_to?(item_type) && a.bool? != is_bool }.each do |a| 130 body << "#{indent}if (attribute == \"#{attribute_name(a)}\") {" 131 body << "#{indent * 2}return Error(\"Attribute '#{attribute_name(a)}' #{is_bool ? "must" : "must not"} have a value\"," 132 body << "#{indent * 2} #{is_bool ? "Error::Type::MISSING_VALUE" : "Error::Type::UNEXPECTED_VALUE"});" 133 body << "#{indent}}" 134 body << "" 135 end 136 137 if Metadata::extends_default? 138 args = ['attribute'] 139 args << 'value' unless is_bool 140 body << "#{indent}return pandasm::#{class_name(item_type)}::Validate(#{args.join(', ')});" 141 else 142 body << "#{indent}return Error(std::string(\"Unknown attribute '\").append(attribute) + \"'\"," 143 body << "#{indent} Error::Type::UNKNOWN_ATTRIBUTE);" 144 end 145 146 body 147 end 148 149 def set_flags_body(item_type, is_bool) 150 attributes = Metadata::attributes.select { |a| a.applicable_to?(item_type) && a.bool? == is_bool && a.set_flags? } 151 body = [] 152 indent = ' ' * 4 153 154 attributes.each do |a| 155 body << "#{indent}if (attribute == \"#{attribute_name(a)}\") {" 156 157 if defined? a.flags 158 body << "#{indent * 2}SetAccessFlags(GetAccessFlags() | #{a.flags.join(' | ')});" 159 end 160 161 if a.enum? 162 a.values.select { |v| v.flags && v.flags.any? }.each do |v| 163 body << "#{indent * 2}if (value == \"#{v.value}\") {" 164 body << "#{indent * 3}SetAccessFlags(GetAccessFlags() | #{v.flags.join(' | ')});" 165 body << "#{indent * 2}}" 166 body << "" 167 end 168 end 169 170 body << "#{indent}}" 171 end 172 173 if Metadata::extends_default? 174 args = ['attribute'] 175 args << 'value' unless is_bool 176 body << "#{indent}pandasm::#{class_name(item_type)}::SetFlags(#{args.join(', ')});" 177 end 178 179 body 180 end 181 182 def remove_flags_body(item_type, is_bool) 183 attributes = Metadata::attributes.select { |a| a.applicable_to?(item_type) && a.bool? == is_bool && a.set_flags? } 184 body = [] 185 indent = ' ' * 4 186 187 attributes.each do |a| 188 body << "#{indent}if (attribute == \"#{attribute_name(a)}\") {" 189 190 if defined? a.flags 191 body << "#{indent * 2}if ((GetAccessFlags() & #{a.flags.join(' | ')}) != 0) {" 192 body << "#{indent * 3}SetAccessFlags(GetAccessFlags() ^ (#{a.flags.join(' | ')}));" 193 body << "#{indent * 2}}" 194 end 195 196 if a.enum? 197 a.values.select { |v| v.flags && v.flags.any? }.each do |v| 198 body << "#{indent * 2}if (value == \"#{v.value}\") {" 199 body << "#{indent * 3}if ((GetAccessFlags() & (#{v.flags.join(' | ')})) != 0) {" 200 body << "#{indent * 4}SetAccessFlags(GetAccessFlags() ^ (#{v.flags.join(' | ')}));" 201 body << "#{indent * 3}}" 202 body << "#{indent * 2}}" 203 end 204 end 205 206 body << "#{indent}}" 207 end 208 209 if Metadata::extends_default? 210 args = ['attribute'] 211 args << 'value' unless is_bool 212 body << "#{indent}pandasm::#{class_name(item_type)}::RemoveFlags(#{args.join(', ')});" 213 end 214 215 body 216 end 217 218 def arg_list(is_bool) 219 args = ['const std::string_view &attribute'] 220 args << 'const std::string_view &value' if !is_bool 221 args 222 end 223 224 def add_unused_attribute(arg) 225 "[[maybe_unused]] #{arg}" 226 end 227 228 def validate_arg_list(item_type, is_bool) 229 args = arg_list(is_bool) 230 return args if Metadata::extends_default? 231 232 attributes = Metadata::attributes.select { |a| a.applicable_to?(item_type) && a.bool? == is_bool } 233 args[0] = add_unused_attribute(args[0]) if attributes.none? 234 args[1] = add_unused_attribute(args[1]) if args[1] && attributes.none? { |a| a.enum? } 235 args 236 end 237 238 def flags_arg_list(item_type, is_bool) 239 args = arg_list(is_bool) 240 return args if Metadata::extends_default? 241 242 attributes = Metadata::attributes.select { |a| a.applicable_to?(item_type) && a.bool? == is_bool && a.set_flags? } 243 use_value = attributes.any? { |a| a.enum? && a.values.any? { |v| v.flags && v.flags.any? } } 244 args[0] = add_unused_attribute(args[0]) if attributes.none? 245 args[1] = add_unused_attribute(args[1]) if args[1] && !use_value 246 args 247 end 248 249end 250