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