1# Copyright (c) 2024-2025 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' 15require 'ostruct' 16 17module Enums 18 class EnumData < SimpleDelegator 19 def type 20 raise 'Unsupported enum kind' unless %w[simple flags].include?(kind) 21 22 kind == 'simple' ? 'int' : 'unsigned' 23 end 24 25 def flags 26 dig(:flags) || [] 27 end 28 29 def all_flags_with_value 30 res = {} 31 dig(:flags)&.each_with_index do |flag, index| 32 if type == 'int' 33 res[flag] = index 34 else 35 res[flag] = 1 << (index - 1) 36 end 37 end 38 39 dig(:flag_unions)&.each do |union| 40 res[union.name] = union.flags.reduce(0) { |result, key| result | res[key] } 41 end 42 res 43 end 44 45 def flag_unions 46 res = {} 47 dig(:flag_unions)&.each { |union| res[union.name] = union.flags } 48 res 49 end 50 51 def namespace 52 if Enums.change_namespace.include?(dig(:namespace)) 53 return Enums.change_namespace[dig(:namespace)] 54 else 55 return dig(:namespace) 56 end 57 end 58 59 def parent_class_name 60 dig(:parent_class_name) 61 end 62 63 def name_to_upper_snake 64 dig(:name)&.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2') 65 &.gsub(/([a-z\d])([A-Z])/, '\1_\2') 66 &.upcase 67 end 68 end 69 70 def get_astnodetype_value(class_name) 71 enums['AstNodeType'].all_flags_with_value[class_name] 72 end 73 74 @enums = {} 75 @change_namespace = { 76 'ast_verifier' => 'compiler::ast_verifier', 'verifier_invariants' => 'util::gen::verifier_invariants' 77 } 78 79 attr_reader :change_namespace 80 attr_reader :enums 81 82 def wrap_data(data) 83 return unless data 84 85 data.enums&.each do |enum| 86 @enums[enum.name] = EnumData.new(enum) 87 end 88 89 node_type_enum_flags = [] 90 scope_type_enum_flags = [] 91 decl_type_enum_flags = ['NONE'] 92 data.macros&.each do |macros| 93 case macros.name 94 when 'AST_NODE_MAPPING' 95 node_type_enum_flags.concat(macros.values.map { |x| x[0] }) 96 when 'AST_NODE_REINTERPRET_MAPPING' 97 node_type_enum_flags.concat(macros.values.flat_map { |x| x[0..1] }) 98 when 'SCOPE_TYPES' 99 scope_type_enum_flags.concat(macros.values.map { |x| x[0] }) 100 end 101 end 102 data.varbinder&.macros&.each do |macros| 103 case macros.name 104 when 'SCOPE_TYPES' 105 scope_type_enum_flags.concat(macros.values.map { |x| x[0] }) 106 when 'DECLARATION_KINDS' 107 decl_type_enum_flags.concat(macros.values.map { |x| x[0] }) 108 end 109 end 110 111 unless node_type_enum_flags.empty? 112 @enums['AstNodeType'] = EnumData.new(OpenStruct.new({ 'kind' => 'simple', 'flags' => node_type_enum_flags, 113 'namespace' => 'ir', 'name' => 'AstNodeType' })) 114 end 115 116 unless scope_type_enum_flags.empty? 117 @enums['ScopeType'] = EnumData.new(OpenStruct.new({ 'kind' => 'simple', 'flags' => scope_type_enum_flags, 118 'namespace' => 'varbinder', 'name' => 'ScopeType' })) 119 end 120 121 return if decl_type_enum_flags.empty? || decl_type_enum_flags == ['NONE'] 122 123 @enums['DeclType'] = EnumData.new(OpenStruct.new({ 'kind' => 'simple', 'flags' => decl_type_enum_flags, 124 'namespace' => 'varbinder', 'name' => 'DeclType' })) 125 end 126 127 module_function :wrap_data, :enums, :change_namespace, :get_astnodetype_value 128end 129 130def Gen.on_require(data) 131 Enums.wrap_data(data) 132end 133