• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (c) 2021-2022 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 'strscan'
15
16Message = Struct.new(:name, :component, :number, :level, :args, :short_message, :message, keyword_init: true) do
17  def macro_name
18    ['LOG', component, Messages.split_words(name)].flatten.join('_').upcase
19  end
20
21  def scan_until_exclusive(scanner, pattern)
22    scanner.scan_until(Regexp.new(Regexp.escape(pattern)))&.delete_suffix(pattern)
23  end
24
25  def escape_string_literal(string)
26    %("#{string.gsub('"', '\\"').gsub("\n", '\\n').gsub("\t", '\\t').gsub('\\', '\\\\')}")
27  end
28
29  def stream_ops(is_short)
30    msg = is_short ? "#{component} #{level} #{number}: #{short_message}" : message
31    scanner = StringScanner.new(msg)
32    parts = []
33    until scanner.eos?
34      str_part = scan_until_exclusive(scanner, '${')
35      if str_part
36        parts << escape_string_literal(str_part) unless str_part.empty?
37        expr_part = scan_until_exclusive(scanner, '}')
38        if expr_part
39          parts << expr_part
40        else
41          raise "Message template '#{msg}' has a '${' not followed by a '}'"
42        end
43      elsif !scanner.eos?
44        parts << escape_string_literal(scanner.rest)
45        scanner.terminate
46      end
47    end
48    parts.join(' << ')
49  end
50end
51
52module Messages
53  module_function
54
55  def split_words(string)
56    scanner = StringScanner.new(string)
57    words = []
58    until scanner.eos?
59      word = scanner.scan(/[A-Z0-9][a-z0-9]*/)
60      if word.empty?
61        raise "Message name '#{string}' is not in UpperCamelCase"
62      else
63        words << word
64      end
65    end
66    words
67  end
68
69  def load_messages(data)
70    @component = data.component.capitalize
71    @namespace = data.namespace
72    @enum_name = data.enum_name
73    @messages = data.messages.each_pair.map do |name, msg_data|
74      name = name.to_s
75      level = msg_data.level || data.default_level
76      short_message = msg_data.short_message&.strip || split_words(name).join(' ').capitalize
77      Message.new(
78        name: name,
79        component: @component,
80        number: msg_data.number,
81        level: level,
82        args: msg_data.args || '',
83        short_message: short_message,
84        message: msg_data.message&.strip
85      )
86    end
87  end
88
89  [:component, :enum_name, :namespace, :messages].each do |attr|
90    # equivalent to attr_reader(attr), but that gives a warning in JRuby 9.2.17.0
91    define_method(attr) do
92      instance_variable_get("@#{attr}")
93    end
94  end
95end
96
97def Gen.on_require(data)
98  Messages.load_messages(data)
99end
100