13af6ab5fSopenharmony_ci#!/usr/bin/env python3
23af6ab5fSopenharmony_ci# coding=utf-8
33af6ab5fSopenharmony_ci#
43af6ab5fSopenharmony_ci# Copyright (c) 2024 Huawei Device Co., Ltd.
53af6ab5fSopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License");
63af6ab5fSopenharmony_ci# you may not use this file except in compliance with the License.
73af6ab5fSopenharmony_ci# You may obtain a copy of the License at
83af6ab5fSopenharmony_ci#
93af6ab5fSopenharmony_ci# http://www.apache.org/licenses/LICENSE-2.0
103af6ab5fSopenharmony_ci#
113af6ab5fSopenharmony_ci# Unless required by applicable law or agreed to in writing, software
123af6ab5fSopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS,
133af6ab5fSopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
143af6ab5fSopenharmony_ci# See the License for the specific language governing permissions and
153af6ab5fSopenharmony_ci# limitations under the License.
163af6ab5fSopenharmony_ci
173af6ab5fSopenharmony_cifrom typing import Any, Dict, Union
183af6ab5fSopenharmony_cifrom line_iterator import LineIterator
193af6ab5fSopenharmony_cifrom runtime_collections import add_to_statistics, add_to_custom_yamls
203af6ab5fSopenharmony_cifrom parse_namespace import parse_namespace
213af6ab5fSopenharmony_cifrom parse_enum import parse_enum_class
223af6ab5fSopenharmony_cifrom parse_struct import parse_struct
233af6ab5fSopenharmony_cifrom parse_using import parse_using
243af6ab5fSopenharmony_cifrom parse_define import parse_define_macros
253af6ab5fSopenharmony_cifrom parse_class import parse_class, parse_friend_class, parse_template_prefix
263af6ab5fSopenharmony_cifrom parse_method import parse_method_or_constructor
273af6ab5fSopenharmony_cifrom parse_arguments import parse_argument
283af6ab5fSopenharmony_cifrom log_tools import warning_log
293af6ab5fSopenharmony_ci
303af6ab5fSopenharmony_ci
313af6ab5fSopenharmony_cidef deep_copy(data: Any) -> Any:
323af6ab5fSopenharmony_ci    if isinstance(data, (dict, list)):
333af6ab5fSopenharmony_ci        return data.copy()
343af6ab5fSopenharmony_ci    return data
353af6ab5fSopenharmony_ci
363af6ab5fSopenharmony_ci
373af6ab5fSopenharmony_ciclass CppParser:
383af6ab5fSopenharmony_ci    def __init__(self, data: str, namespace: str = "", parent_class_name: str = ""):
393af6ab5fSopenharmony_ci        self.it = LineIterator(data)
403af6ab5fSopenharmony_ci        self.parsed: Any = None
413af6ab5fSopenharmony_ci        self.res: Dict[str, Any] = {}
423af6ab5fSopenharmony_ci        self.template: Union[str, None] = None
433af6ab5fSopenharmony_ci
443af6ab5fSopenharmony_ci        self.parent_class_name = parent_class_name
453af6ab5fSopenharmony_ci        self.namespace = namespace
463af6ab5fSopenharmony_ci        self.current_modifier = ""
473af6ab5fSopenharmony_ci
483af6ab5fSopenharmony_ci    def parse(self) -> Dict[str, Any]:  # pylint: disable=R0912
493af6ab5fSopenharmony_ci
503af6ab5fSopenharmony_ci        while self.it.next_line():
513af6ab5fSopenharmony_ci            # Skip "#include", "#ifndef", "#undef", "template"
523af6ab5fSopenharmony_ci
533af6ab5fSopenharmony_ci            if self.it.is_skip_line():
543af6ab5fSopenharmony_ci                add_to_statistics("skip", self.it.current_line)
553af6ab5fSopenharmony_ci
563af6ab5fSopenharmony_ci            elif self.it.is_template():
573af6ab5fSopenharmony_ci                self.it.end, self.template = parse_template_prefix(self.it.data, self.it.start)
583af6ab5fSopenharmony_ci
593af6ab5fSopenharmony_ci            # Namespaces
603af6ab5fSopenharmony_ci            elif self.it.is_namespace():
613af6ab5fSopenharmony_ci                self.it.end, self.parsed = parse_namespace(self.it.data, self.it.start)
623af6ab5fSopenharmony_ci                self.res_update()
633af6ab5fSopenharmony_ci
643af6ab5fSopenharmony_ci            # Enum class
653af6ab5fSopenharmony_ci            elif self.it.is_enum():
663af6ab5fSopenharmony_ci                self.it.end, self.parsed = parse_enum_class(self.it.data, self.it.start)
673af6ab5fSopenharmony_ci                self.res_append_namespace()
683af6ab5fSopenharmony_ci
693af6ab5fSopenharmony_ci            # Struct
703af6ab5fSopenharmony_ci            elif self.it.is_struct():
713af6ab5fSopenharmony_ci                self.it.end, self.parsed = parse_struct(self.it.data, self.it.start)
723af6ab5fSopenharmony_ci                self.res_append("structs")
733af6ab5fSopenharmony_ci
743af6ab5fSopenharmony_ci            # Using
753af6ab5fSopenharmony_ci            elif self.it.is_using():
763af6ab5fSopenharmony_ci                self.it.end, self.parsed = parse_using(self.it.data, self.it.start)
773af6ab5fSopenharmony_ci                self.res_append_in_modifier("usings")
783af6ab5fSopenharmony_ci
793af6ab5fSopenharmony_ci            # define macros (from class parser)
803af6ab5fSopenharmony_ci            elif self.it.is_define_macro():
813af6ab5fSopenharmony_ci                self.it.end, self.parsed = parse_define_macros(self.it.data, self.it.start)
823af6ab5fSopenharmony_ci                self.res_append("macros")
833af6ab5fSopenharmony_ci
843af6ab5fSopenharmony_ci            # Known macroses (from class parser)
853af6ab5fSopenharmony_ci            elif self.it.is_known_macros():
863af6ab5fSopenharmony_ci                self.parsed = self.it.current_line
873af6ab5fSopenharmony_ci                self.res_append("known_macroses")
883af6ab5fSopenharmony_ci
893af6ab5fSopenharmony_ci            # Private, public, protected modifier (from class parser)
903af6ab5fSopenharmony_ci            elif self.it.is_access_modifier():
913af6ab5fSopenharmony_ci                self.update_access_modifier()
923af6ab5fSopenharmony_ci
933af6ab5fSopenharmony_ci            # Friend class
943af6ab5fSopenharmony_ci            elif self.it.is_firend_class():
953af6ab5fSopenharmony_ci                self.it.end, self.parsed = parse_friend_class(self.it.data, self.it.start)
963af6ab5fSopenharmony_ci                self.res_append("friends")
973af6ab5fSopenharmony_ci
983af6ab5fSopenharmony_ci            # Class forward declaration
993af6ab5fSopenharmony_ci            elif self.it.is_class_forward_decl():
1003af6ab5fSopenharmony_ci                self.parsed = self.it.current_line.replace("class", "").strip(" ;")
1013af6ab5fSopenharmony_ci                self.res_append("class_forward_declaration")
1023af6ab5fSopenharmony_ci
1033af6ab5fSopenharmony_ci            # Class definition
1043af6ab5fSopenharmony_ci            elif self.it.is_class_definition():
1053af6ab5fSopenharmony_ci                self.it.end, self.parsed = parse_class(
1063af6ab5fSopenharmony_ci                    self.it.data, self.it.start, self.namespace, self.parent_class_name
1073af6ab5fSopenharmony_ci                )
1083af6ab5fSopenharmony_ci                self.res_append_class_definition()
1093af6ab5fSopenharmony_ci
1103af6ab5fSopenharmony_ci            # Function, method or constructor
1113af6ab5fSopenharmony_ci            elif self.it.is_method_or_constructor():
1123af6ab5fSopenharmony_ci                self.it.end, self.parsed = parse_method_or_constructor(self.it.data, self.it.start)
1133af6ab5fSopenharmony_ci                self.res_append_method_or_constructor()
1143af6ab5fSopenharmony_ci
1153af6ab5fSopenharmony_ci            # Field
1163af6ab5fSopenharmony_ci            elif self.it.is_field():
1173af6ab5fSopenharmony_ci                self.parsed = parse_argument(self.it.data[self.it.start : self.it.next_semicolon])
1183af6ab5fSopenharmony_ci                self.it.end = self.it.next_semicolon
1193af6ab5fSopenharmony_ci                self.res_append_field()
1203af6ab5fSopenharmony_ci
1213af6ab5fSopenharmony_ci            else:
1223af6ab5fSopenharmony_ci                add_to_statistics("unreachable", self.it.current_line)
1233af6ab5fSopenharmony_ci
1243af6ab5fSopenharmony_ci        return self.res
1253af6ab5fSopenharmony_ci
1263af6ab5fSopenharmony_ci    def res_append(self, key: str) -> None:
1273af6ab5fSopenharmony_ci        if not self.parsed:
1283af6ab5fSopenharmony_ci            return
1293af6ab5fSopenharmony_ci
1303af6ab5fSopenharmony_ci        self.parsed_update_template()
1313af6ab5fSopenharmony_ci        if key not in self.res:
1323af6ab5fSopenharmony_ci            self.res[key] = []
1333af6ab5fSopenharmony_ci        self.res[key].append(deep_copy(self.parsed))
1343af6ab5fSopenharmony_ci
1353af6ab5fSopenharmony_ci    def res_append_in_modifier(self, key: str) -> None:
1363af6ab5fSopenharmony_ci        if not self.parsed:
1373af6ab5fSopenharmony_ci            return
1383af6ab5fSopenharmony_ci
1393af6ab5fSopenharmony_ci        self.parsed_update_template()
1403af6ab5fSopenharmony_ci        if self.current_modifier == "":
1413af6ab5fSopenharmony_ci            if key == "usings":
1423af6ab5fSopenharmony_ci                self.res_append("usings")
1433af6ab5fSopenharmony_ci                return
1443af6ab5fSopenharmony_ci            raise RuntimeError("Unreachable")
1453af6ab5fSopenharmony_ci
1463af6ab5fSopenharmony_ci        if key not in self.res[self.current_modifier]:
1473af6ab5fSopenharmony_ci            self.res[self.current_modifier][key] = []
1483af6ab5fSopenharmony_ci
1493af6ab5fSopenharmony_ci        self.res[self.current_modifier][key].append(deep_copy(self.parsed))
1503af6ab5fSopenharmony_ci
1513af6ab5fSopenharmony_ci    def res_update(self) -> None:
1523af6ab5fSopenharmony_ci        if self.parsed:
1533af6ab5fSopenharmony_ci            self.parsed_update_template()
1543af6ab5fSopenharmony_ci            self.res.update(self.parsed)
1553af6ab5fSopenharmony_ci
1563af6ab5fSopenharmony_ci    def res_append_namespace(self) -> None:
1573af6ab5fSopenharmony_ci        self.parsed["namespace"] = self.namespace
1583af6ab5fSopenharmony_ci
1593af6ab5fSopenharmony_ci        if self.parent_class_name != "":
1603af6ab5fSopenharmony_ci            self.parsed["parent_class_name"] = self.parent_class_name
1613af6ab5fSopenharmony_ci
1623af6ab5fSopenharmony_ci        if "flags" in self.parsed or "flag_unions" in self.parsed:
1633af6ab5fSopenharmony_ci            self.res_append("enums")
1643af6ab5fSopenharmony_ci            add_to_custom_yamls("allEnums", "enums", self.parsed)
1653af6ab5fSopenharmony_ci
1663af6ab5fSopenharmony_ci    def update_access_modifier(self) -> None:
1673af6ab5fSopenharmony_ci        if self.parent_class_name == "":
1683af6ab5fSopenharmony_ci            raise RuntimeError("Found modifier not in class")
1693af6ab5fSopenharmony_ci        self.current_modifier = self.it.current_line.strip(" :")
1703af6ab5fSopenharmony_ci        if self.current_modifier not in self.res:
1713af6ab5fSopenharmony_ci            self.res[self.current_modifier] = {}
1723af6ab5fSopenharmony_ci
1733af6ab5fSopenharmony_ci    def res_append_method_or_constructor(self) -> None:
1743af6ab5fSopenharmony_ci        # Constructor
1753af6ab5fSopenharmony_ci        if self.parsed["name"] == self.parent_class_name:
1763af6ab5fSopenharmony_ci            self.res_append_in_modifier("constructors")
1773af6ab5fSopenharmony_ci
1783af6ab5fSopenharmony_ci        # Destructor
1793af6ab5fSopenharmony_ci        elif self.parsed["name"] == "~" + self.parent_class_name:
1803af6ab5fSopenharmony_ci            self.res_append_in_modifier("destructors")
1813af6ab5fSopenharmony_ci
1823af6ab5fSopenharmony_ci        # Method
1833af6ab5fSopenharmony_ci        elif self.current_modifier != "":
1843af6ab5fSopenharmony_ci            self.res_append_in_modifier("methods")
1853af6ab5fSopenharmony_ci
1863af6ab5fSopenharmony_ci        # Function
1873af6ab5fSopenharmony_ci        else:
1883af6ab5fSopenharmony_ci            self.res_append("functions")
1893af6ab5fSopenharmony_ci
1903af6ab5fSopenharmony_ci    def res_append_field(self) -> None:
1913af6ab5fSopenharmony_ci        # Class field
1923af6ab5fSopenharmony_ci        if self.current_modifier != "":
1933af6ab5fSopenharmony_ci            self.res_append_in_modifier("fields")
1943af6ab5fSopenharmony_ci
1953af6ab5fSopenharmony_ci        # Top level variable
1963af6ab5fSopenharmony_ci        else:
1973af6ab5fSopenharmony_ci            self.res_append("vars")
1983af6ab5fSopenharmony_ci
1993af6ab5fSopenharmony_ci    def res_append_class_definition(self) -> None:
2003af6ab5fSopenharmony_ci        self.res_append("class_definitions")
2013af6ab5fSopenharmony_ci
2023af6ab5fSopenharmony_ci    def parsed_update_template(self) -> None:
2033af6ab5fSopenharmony_ci        if self.template and self.parsed:
2043af6ab5fSopenharmony_ci            if isinstance(self.parsed, dict):
2053af6ab5fSopenharmony_ci                self.parsed["template"] = self.template
2063af6ab5fSopenharmony_ci                self.template = None
2073af6ab5fSopenharmony_ci            else:
2083af6ab5fSopenharmony_ci                warning_log("Skipping template for '" + self.parsed + "'")
209