• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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