1#!/usr/bin/env ruby
2# Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15require 'ostruct'
16require 'set'
17require 'delegate'
18
19module Keywords
20  module_function
21
22  def extensions
23    @extensions
24  end
25
26  def build_tree(keys)
27    tree = Hash.new()
28    offset = 0
29
30    while true
31      has_more = false
32      keys.each do |key|
33          if key.length < offset + 1
34            next
35          end
36
37        has_more = true
38        func_name = key[0..offset];
39        if tree.has_key?(func_name)
40          tree[func_name].add(key[offset + 1])
41        else
42          tree[func_name] = Set[key[offset + 1]]
43        end
44      end
45
46      if has_more
47        offset += 1
48        next
49      end
50      break
51    end
52
53    return tree
54  end
55
56  def wrap_data(data)
57    @extensions = Hash.new()
58
59    if !data || !data.extensions || !data.keywords
60      return
61    end
62
63    data.extensions.each do |extension|
64      @extensions[extension.name] = Hash.new()
65      all_words = data.keywords.select do |desc|
66        s_kw = Set.new(desc&.keyword)
67        groups = [s_kw, Set.new(desc&.keyword_like), Set.new(desc&.custom_handler)]
68        groups.combination(2).each { |a,b| raise "Conflicting keyword type" unless (a & b).empty? }
69
70        active = Set.new();
71        groups.each { |group| active.merge(group) }
72
73        raise "Unknown extension" unless active.subset?(Set.new(data.extensions.map { |ext| ext.name }))
74        active.include? extension.name
75      end
76
77      keywords = data.keywords.select do |desc|
78        desc&.keyword&.include? extension.name or desc&.custom_handler&.include? extension.name
79      end
80
81      @extensions[extension.name]['keywords'] = keywords
82      @extensions[extension.name]['keyword_starts'] = Set.new(keywords.map { |desc| desc.name[0] })
83      @extensions[extension.name]['all_words'] = all_words
84      @extensions[extension.name]['all_word_starts'] = Set.new(all_words.map { |desc| desc.name[0] })
85      @extensions[extension.name]['tree'] = build_tree(all_words.map { |desc| desc.name })
86    end
87  end
88end
89
90def Gen.on_require(data)
91  Keywords.wrap_data(data)
92end
93
94