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