15f9996aaSopenharmony_ci#!/usr/bin/env python
25f9996aaSopenharmony_ci# -*- coding: utf-8 -*-
35f9996aaSopenharmony_ci# Copyright (c) 2024 Huawei Device Co., Ltd.
45f9996aaSopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License");
55f9996aaSopenharmony_ci# you may not use this file except in compliance with the License.
65f9996aaSopenharmony_ci# You may obtain a copy of the License at
75f9996aaSopenharmony_ci#
85f9996aaSopenharmony_ci#     http://www.apache.org/licenses/LICENSE-2.0
95f9996aaSopenharmony_ci#
105f9996aaSopenharmony_ci# Unless required by applicable law or agreed to in writing, software
115f9996aaSopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS,
125f9996aaSopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135f9996aaSopenharmony_ci# See the License for the specific language governing permissions and
145f9996aaSopenharmony_ci# limitations under the License.
155f9996aaSopenharmony_ci
165f9996aaSopenharmony_ciimport os
175f9996aaSopenharmony_ciimport sys
185f9996aaSopenharmony_cifrom queue import Queue
195f9996aaSopenharmony_ci
205f9996aaSopenharmony_ci
215f9996aaSopenharmony_ciclass TokenType(object):
225f9996aaSopenharmony_ci    UNKNOWN = 0
235f9996aaSopenharmony_ci    END_OF_FILE = 1
245f9996aaSopenharmony_ci    COMMENT = 2  # comment
255f9996aaSopenharmony_ci    INCLUDE = 3  # include
265f9996aaSopenharmony_ci    STRING = 4   # character string
275f9996aaSopenharmony_ci
285f9996aaSopenharmony_ci
295f9996aaSopenharmony_ciclass Token(object):
305f9996aaSopenharmony_ci    def __init__(self, file_name, token_type, value):
315f9996aaSopenharmony_ci        self.token_type = token_type
325f9996aaSopenharmony_ci        self.value = value
335f9996aaSopenharmony_ci        self.row = 1
345f9996aaSopenharmony_ci        self.col = 1
355f9996aaSopenharmony_ci        self.file_name = file_name
365f9996aaSopenharmony_ci
375f9996aaSopenharmony_ci    def clean(self):
385f9996aaSopenharmony_ci        self.token_type = TokenType.UNKNOWN
395f9996aaSopenharmony_ci        self.value = ""
405f9996aaSopenharmony_ci        self.row = 1
415f9996aaSopenharmony_ci        self.col = 1
425f9996aaSopenharmony_ci
435f9996aaSopenharmony_ci    def dump(self):
445f9996aaSopenharmony_ci        return "<{}:{}:{}: {},'{}'>".format(self.file_name, self.row, self.col,
455f9996aaSopenharmony_ci                                            self.token_type, self.value)
465f9996aaSopenharmony_ci
475f9996aaSopenharmony_ci    def info(self):
485f9996aaSopenharmony_ci        return "{}:{}:{}".format(self.file_name, self.row, self.col)
495f9996aaSopenharmony_ci
505f9996aaSopenharmony_ci
515f9996aaSopenharmony_ciclass Char(object):
525f9996aaSopenharmony_ci    def __init__(self, is_eof, char):
535f9996aaSopenharmony_ci        self.is_eof = is_eof
545f9996aaSopenharmony_ci        self.char = char
555f9996aaSopenharmony_ci
565f9996aaSopenharmony_ci    def dump(self):
575f9996aaSopenharmony_ci        return "{%s, %s}" % (self.is_eof, self.char)
585f9996aaSopenharmony_ci
595f9996aaSopenharmony_ci
605f9996aaSopenharmony_ciclass Lexer(object):
615f9996aaSopenharmony_ci    def __init__(self, idl_file_path):
625f9996aaSopenharmony_ci        self.have_peek = False
635f9996aaSopenharmony_ci        with open(idl_file_path, 'r') as idl_file:
645f9996aaSopenharmony_ci            file_info = idl_file.read()
655f9996aaSopenharmony_ci        self.data = file_info
665f9996aaSopenharmony_ci        self.data_len = len(self.data)
675f9996aaSopenharmony_ci        self.read_index = 0
685f9996aaSopenharmony_ci        self.cur_token = Token(os.path.basename(idl_file_path),
695f9996aaSopenharmony_ci                               TokenType.UNKNOWN, "")
705f9996aaSopenharmony_ci        self.cur_row = 1
715f9996aaSopenharmony_ci        self.cur_col = 1
725f9996aaSopenharmony_ci
735f9996aaSopenharmony_ci    def peek_char(self, peek_count=0):
745f9996aaSopenharmony_ci        index = self.read_index + peek_count
755f9996aaSopenharmony_ci        if index >= self.data_len:
765f9996aaSopenharmony_ci            return Char(True, '0')
775f9996aaSopenharmony_ci        return Char(False, self.data[index])
785f9996aaSopenharmony_ci
795f9996aaSopenharmony_ci    def get_char(self):
805f9996aaSopenharmony_ci        if self.read_index >= self.data_len:
815f9996aaSopenharmony_ci            return Char(True, '0')
825f9996aaSopenharmony_ci        read_index = self.read_index
835f9996aaSopenharmony_ci        self.read_index += 1
845f9996aaSopenharmony_ci        if self.data[read_index] == '\n':
855f9996aaSopenharmony_ci            self.cur_row += 1
865f9996aaSopenharmony_ci            self.cur_col = 1
875f9996aaSopenharmony_ci        else:
885f9996aaSopenharmony_ci            self.cur_col += 1
895f9996aaSopenharmony_ci        return Char(False, self.data[read_index])
905f9996aaSopenharmony_ci
915f9996aaSopenharmony_ci    def peek_token(self):
925f9996aaSopenharmony_ci        if not self.have_peek:
935f9996aaSopenharmony_ci            self.read_token()
945f9996aaSopenharmony_ci            self.have_peek = True
955f9996aaSopenharmony_ci        return self.cur_token
965f9996aaSopenharmony_ci
975f9996aaSopenharmony_ci    def get_token(self):
985f9996aaSopenharmony_ci        if not self.have_peek:
995f9996aaSopenharmony_ci            self.read_token()
1005f9996aaSopenharmony_ci        self.have_peek = False
1015f9996aaSopenharmony_ci        return self.cur_token
1025f9996aaSopenharmony_ci
1035f9996aaSopenharmony_ci    def read_token(self):
1045f9996aaSopenharmony_ci        self.cur_token.clean()
1055f9996aaSopenharmony_ci        while not self.peek_char().is_eof:
1065f9996aaSopenharmony_ci            new_char = self.peek_char()
1075f9996aaSopenharmony_ci            if new_char.char.isspace():
1085f9996aaSopenharmony_ci                self.get_char()
1095f9996aaSopenharmony_ci                continue
1105f9996aaSopenharmony_ci            self.cur_token.row = self.cur_row
1115f9996aaSopenharmony_ci            self.cur_token.col = self.cur_col
1125f9996aaSopenharmony_ci            if new_char.char == '#':
1135f9996aaSopenharmony_ci                self.read_include()
1145f9996aaSopenharmony_ci                return
1155f9996aaSopenharmony_ci            if new_char.char == '"':
1165f9996aaSopenharmony_ci                self.read_string()
1175f9996aaSopenharmony_ci                return
1185f9996aaSopenharmony_ci            if new_char.char == '/':
1195f9996aaSopenharmony_ci                self.read_comment()
1205f9996aaSopenharmony_ci                return
1215f9996aaSopenharmony_ci            self.cur_token.value = new_char.char
1225f9996aaSopenharmony_ci            self.cur_token.token_type = TokenType.UNKNOWN
1235f9996aaSopenharmony_ci            self.get_char()
1245f9996aaSopenharmony_ci            return
1255f9996aaSopenharmony_ci        self.cur_token.token_type = TokenType.END_OF_FILE
1265f9996aaSopenharmony_ci
1275f9996aaSopenharmony_ci    def read_include(self):
1285f9996aaSopenharmony_ci        token_value = []
1295f9996aaSopenharmony_ci        token_value.append(self.get_char().char)
1305f9996aaSopenharmony_ci        while not self.peek_char().is_eof:
1315f9996aaSopenharmony_ci            new_char = self.peek_char()
1325f9996aaSopenharmony_ci            if new_char.char.isalpha():
1335f9996aaSopenharmony_ci                token_value.append(new_char.char)
1345f9996aaSopenharmony_ci                self.get_char()
1355f9996aaSopenharmony_ci                continue
1365f9996aaSopenharmony_ci            break
1375f9996aaSopenharmony_ci        key_str = "".join(token_value)
1385f9996aaSopenharmony_ci        if key_str == "#include":
1395f9996aaSopenharmony_ci            self.cur_token.token_type = TokenType.INCLUDE
1405f9996aaSopenharmony_ci        else:
1415f9996aaSopenharmony_ci            self.cur_token.token_type = TokenType.UNKNOWN
1425f9996aaSopenharmony_ci        self.cur_token.value = key_str
1435f9996aaSopenharmony_ci
1445f9996aaSopenharmony_ci    def read_string(self):
1455f9996aaSopenharmony_ci        token_value = []
1465f9996aaSopenharmony_ci        self.get_char()
1475f9996aaSopenharmony_ci        while not self.peek_char().is_eof and self.peek_char().char != '"':
1485f9996aaSopenharmony_ci            token_value.append(self.get_char().char)
1495f9996aaSopenharmony_ci
1505f9996aaSopenharmony_ci        if self.peek_char().char == '"':
1515f9996aaSopenharmony_ci            self.cur_token.token_type = TokenType.STRING
1525f9996aaSopenharmony_ci            self.get_char()
1535f9996aaSopenharmony_ci        else:
1545f9996aaSopenharmony_ci            self.cur_token.token_type = TokenType.UNKNOWN
1555f9996aaSopenharmony_ci        self.cur_token.value = "".join(token_value)
1565f9996aaSopenharmony_ci
1575f9996aaSopenharmony_ci    def read_comment(self):
1585f9996aaSopenharmony_ci        token_value = []
1595f9996aaSopenharmony_ci        token_value.append(self.get_char().char)
1605f9996aaSopenharmony_ci        new_char = self.peek_char()
1615f9996aaSopenharmony_ci        if not new_char.is_eof:
1625f9996aaSopenharmony_ci            if new_char.char == '/':
1635f9996aaSopenharmony_ci                self.read_line_comment(token_value)
1645f9996aaSopenharmony_ci                return
1655f9996aaSopenharmony_ci            elif new_char.char == '*':
1665f9996aaSopenharmony_ci                self.read_block_comment(token_value)
1675f9996aaSopenharmony_ci                return
1685f9996aaSopenharmony_ci        self.cur_token.token_type = TokenType.UNKNOWN
1695f9996aaSopenharmony_ci        self.cur_token.value = "".join(token_value)
1705f9996aaSopenharmony_ci
1715f9996aaSopenharmony_ci    def read_line_comment(self, token_value):
1725f9996aaSopenharmony_ci        token_value.append(self.get_char().char)
1735f9996aaSopenharmony_ci        while not self.peek_char().is_eof:
1745f9996aaSopenharmony_ci            new_char = self.get_char()
1755f9996aaSopenharmony_ci            if new_char.char == '\n':
1765f9996aaSopenharmony_ci                break
1775f9996aaSopenharmony_ci            token_value.append(new_char.char)
1785f9996aaSopenharmony_ci        self.cur_token.token_type = TokenType.COMMENT
1795f9996aaSopenharmony_ci        self.cur_token.value = "".join(token_value)
1805f9996aaSopenharmony_ci
1815f9996aaSopenharmony_ci    def read_block_comment(self, token_value):
1825f9996aaSopenharmony_ci        # read *
1835f9996aaSopenharmony_ci        token_value.append(self.get_char().char)
1845f9996aaSopenharmony_ci        while not self.peek_char().is_eof:
1855f9996aaSopenharmony_ci            new_char = self.get_char()
1865f9996aaSopenharmony_ci            token_value.append(new_char.char)
1875f9996aaSopenharmony_ci            if new_char.char == '*' and self.peek_char().char == '/':
1885f9996aaSopenharmony_ci                token_value.append(self.get_char().char)
1895f9996aaSopenharmony_ci                break
1905f9996aaSopenharmony_ci        value = "".join(token_value)
1915f9996aaSopenharmony_ci        if value.endswith("*/"):
1925f9996aaSopenharmony_ci            self.cur_token.token_type = TokenType.COMMENT
1935f9996aaSopenharmony_ci        else:
1945f9996aaSopenharmony_ci            self.cur_token.token_type = TokenType.UNKNOWN
1955f9996aaSopenharmony_ci        self.cur_token.value = value
1965f9996aaSopenharmony_ci
1975f9996aaSopenharmony_ci
1985f9996aaSopenharmony_ciclass HcsParser(object):
1995f9996aaSopenharmony_ci    def __init__(self):
2005f9996aaSopenharmony_ci        self.all_hcs_files = set()
2015f9996aaSopenharmony_ci        self.src_queue = Queue()
2025f9996aaSopenharmony_ci
2035f9996aaSopenharmony_ci    # get all hcs files by root hcs file
2045f9996aaSopenharmony_ci    def get_hcs_info(self):
2055f9996aaSopenharmony_ci        result_str = ""
2065f9996aaSopenharmony_ci        all_hcs_files_list = sorted(list(self.all_hcs_files))
2075f9996aaSopenharmony_ci        for file_path in all_hcs_files_list:
2085f9996aaSopenharmony_ci            result_str += "{}\n".format(file_path)
2095f9996aaSopenharmony_ci        return result_str
2105f9996aaSopenharmony_ci
2115f9996aaSopenharmony_ci    def parse(self, root_hcs_file):
2125f9996aaSopenharmony_ci        if not os.path.exists(root_hcs_file):
2135f9996aaSopenharmony_ci            return
2145f9996aaSopenharmony_ci        self.src_queue.put(os.path.abspath(root_hcs_file))
2155f9996aaSopenharmony_ci        while not self.src_queue.empty():
2165f9996aaSopenharmony_ci            cur_hcs_file = self.src_queue.get()
2175f9996aaSopenharmony_ci            self.all_hcs_files.add(cur_hcs_file)
2185f9996aaSopenharmony_ci            self.parse_one(cur_hcs_file)
2195f9996aaSopenharmony_ci
2205f9996aaSopenharmony_ci    def parse_one(self, cur_hcs_file_path):
2215f9996aaSopenharmony_ci        hcs_file_dir = os.path.dirname(cur_hcs_file_path)
2225f9996aaSopenharmony_ci        lex = Lexer(cur_hcs_file_path)
2235f9996aaSopenharmony_ci        while lex.peek_token().token_type != TokenType.END_OF_FILE:
2245f9996aaSopenharmony_ci            cur_token_type = lex.peek_token().token_type
2255f9996aaSopenharmony_ci            if cur_token_type == TokenType.INCLUDE:
2265f9996aaSopenharmony_ci                self.parse_include(lex, hcs_file_dir)
2275f9996aaSopenharmony_ci            else:
2285f9996aaSopenharmony_ci                lex.get_token()
2295f9996aaSopenharmony_ci
2305f9996aaSopenharmony_ci    def parse_include(self, lex, hcs_file_dir):
2315f9996aaSopenharmony_ci        lex.get_token()  # include token
2325f9996aaSopenharmony_ci        token = lex.peek_token()
2335f9996aaSopenharmony_ci        if token.token_type == TokenType.STRING:
2345f9996aaSopenharmony_ci            hcs_file_path = os.path.join(hcs_file_dir, token.value)
2355f9996aaSopenharmony_ci            # do not parse the hcs file that does not exist
2365f9996aaSopenharmony_ci            if not os.path.exists(hcs_file_path):
2375f9996aaSopenharmony_ci                return
2385f9996aaSopenharmony_ci            self.src_queue.put(os.path.abspath(hcs_file_path))
2395f9996aaSopenharmony_ci
2405f9996aaSopenharmony_ci
2415f9996aaSopenharmony_cidef check_python_version():
2425f9996aaSopenharmony_ci    if sys.version_info < (3, 0):
2435f9996aaSopenharmony_ci        raise Exception("Please run with python version >= 3.0")
2445f9996aaSopenharmony_ci
2455f9996aaSopenharmony_ci
2465f9996aaSopenharmony_ciif __name__ == "__main__":
2475f9996aaSopenharmony_ci    check_python_version()
2485f9996aaSopenharmony_ci    if len(sys.argv) < 2:
2495f9996aaSopenharmony_ci        raise Exception("No hcs source files, please check input")
2505f9996aaSopenharmony_ci    all_hcs_files = sys.argv[1:]
2515f9996aaSopenharmony_ci    parser = HcsParser()
2525f9996aaSopenharmony_ci    for hcs_file in all_hcs_files:
2535f9996aaSopenharmony_ci        parser.parse(hcs_file)
2545f9996aaSopenharmony_ci
2555f9996aaSopenharmony_ci    sys.stdout.write(parser.get_hcs_info())
2565f9996aaSopenharmony_ci    sys.stdout.flush()
257