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_ci
183af6ab5fSopenharmony_cifrom typing import Tuple, Dict, Any
193af6ab5fSopenharmony_cifrom log_tools import console_log, warning_log
203af6ab5fSopenharmony_cifrom text_tools import (
213af6ab5fSopenharmony_ci    find_first_of_characters,
223af6ab5fSopenharmony_ci    find_first_not_restricted_character,
233af6ab5fSopenharmony_ci    smart_find_first_of_characters,
243af6ab5fSopenharmony_ci    find_scope_borders,
253af6ab5fSopenharmony_ci)
263af6ab5fSopenharmony_ci
273af6ab5fSopenharmony_ci
283af6ab5fSopenharmony_cidef parse_enum_union(data: str) -> list:
293af6ab5fSopenharmony_ci    equally_pos = data.find("=")
303af6ab5fSopenharmony_ci    if equally_pos == -1:
313af6ab5fSopenharmony_ci        raise RuntimeError("Can't find '='.")
323af6ab5fSopenharmony_ci
333af6ab5fSopenharmony_ci    if data.find("~") != -1 or data.find("&") != -1:
343af6ab5fSopenharmony_ci        union = [] # NOTE(morlovsky): instead of using [data[equally_pos + 1:].strip(" \n")]
353af6ab5fSopenharmony_ci    else:
363af6ab5fSopenharmony_ci        union = [x for x in data[equally_pos + 1 :].split(" ") if x.strip(" \n") != "" and x.strip(" \n") != "|"]
373af6ab5fSopenharmony_ci    return union
383af6ab5fSopenharmony_ci
393af6ab5fSopenharmony_ci
403af6ab5fSopenharmony_cidef is_union_value(data: str) -> bool:
413af6ab5fSopenharmony_ci    if data.find("=") == -1 or data.find("<<") != -1:
423af6ab5fSopenharmony_ci        return False
433af6ab5fSopenharmony_ci    if data.find("|") != -1:
443af6ab5fSopenharmony_ci        return True
453af6ab5fSopenharmony_ci
463af6ab5fSopenharmony_ci    value = data[data.find("=") + 1 :].strip(" ")
473af6ab5fSopenharmony_ci    if value[0].isdigit() or value[0] == "(" and value[1].isdigit():
483af6ab5fSopenharmony_ci        return False
493af6ab5fSopenharmony_ci
503af6ab5fSopenharmony_ci    if find_first_of_characters("1234567890-+", value, 0) != len(value):
513af6ab5fSopenharmony_ci        return False
523af6ab5fSopenharmony_ci
533af6ab5fSopenharmony_ci    return True
543af6ab5fSopenharmony_ci
553af6ab5fSopenharmony_ci
563af6ab5fSopenharmony_cidef parse_enum_class_body(data: str) -> dict:
573af6ab5fSopenharmony_ci    console_log("Parsing enum body...")
583af6ab5fSopenharmony_ci
593af6ab5fSopenharmony_ci    res: Dict[str, Any] = {}
603af6ab5fSopenharmony_ci
613af6ab5fSopenharmony_ci    value_start = 0
623af6ab5fSopenharmony_ci    value_end = data.find(",", value_start)
633af6ab5fSopenharmony_ci
643af6ab5fSopenharmony_ci    if data.find("#define") != -1:
653af6ab5fSopenharmony_ci        warning_log("Defines in enum not realized yet. Can't parse enum body with define:\n---\n" + data + "\n---\n")
663af6ab5fSopenharmony_ci        return {}
673af6ab5fSopenharmony_ci
683af6ab5fSopenharmony_ci    if value_end == -1:
693af6ab5fSopenharmony_ci        value_end = len(data)
703af6ab5fSopenharmony_ci
713af6ab5fSopenharmony_ci    while value_start != -1 and value_start < len(data):
723af6ab5fSopenharmony_ci        value = data[value_start:value_end].strip(" \n")
733af6ab5fSopenharmony_ci
743af6ab5fSopenharmony_ci        if value != "":
753af6ab5fSopenharmony_ci            if not is_union_value(value):
763af6ab5fSopenharmony_ci                if "flags" not in res:
773af6ab5fSopenharmony_ci                    res["flags"] = []
783af6ab5fSopenharmony_ci                res["flags"].append(get_name_of_enum_value(value))
793af6ab5fSopenharmony_ci            else:
803af6ab5fSopenharmony_ci
813af6ab5fSopenharmony_ci                union_flag: Dict[str, Any] = {}
823af6ab5fSopenharmony_ci                union_flag["name"] = get_name_of_enum_value(value)
833af6ab5fSopenharmony_ci                union_flag["flags"] = parse_enum_union(value)
843af6ab5fSopenharmony_ci
853af6ab5fSopenharmony_ci                if union_flag["flags"] != []:
863af6ab5fSopenharmony_ci                    if "flag_unions" not in res:
873af6ab5fSopenharmony_ci                        res["flag_unions"] = []
883af6ab5fSopenharmony_ci
893af6ab5fSopenharmony_ci                    res["flag_unions"].append(union_flag)
903af6ab5fSopenharmony_ci
913af6ab5fSopenharmony_ci        if value_end == len(data):
923af6ab5fSopenharmony_ci            break
933af6ab5fSopenharmony_ci
943af6ab5fSopenharmony_ci        value_start = value_end + 1
953af6ab5fSopenharmony_ci        value_end = data.find(",", value_start)
963af6ab5fSopenharmony_ci
973af6ab5fSopenharmony_ci        if value_end == -1:
983af6ab5fSopenharmony_ci            value_end = len(data)
993af6ab5fSopenharmony_ci
1003af6ab5fSopenharmony_ci    return res
1013af6ab5fSopenharmony_ci
1023af6ab5fSopenharmony_ci
1033af6ab5fSopenharmony_cidef parse_enum_class(data: str, start: int = 0) -> Tuple[int, Dict]:
1043af6ab5fSopenharmony_ci    res = {}
1053af6ab5fSopenharmony_ci
1063af6ab5fSopenharmony_ci    start_of_name = data.find("enum class", start)
1073af6ab5fSopenharmony_ci    start_of_name = find_first_not_restricted_character(" ", data, start_of_name + len("enum class"))
1083af6ab5fSopenharmony_ci    end_of_name = find_first_of_characters(" ;{\n", data, start_of_name)
1093af6ab5fSopenharmony_ci    enum_name = data[start_of_name:end_of_name]
1103af6ab5fSopenharmony_ci
1113af6ab5fSopenharmony_ci    if enum_name == "":
1123af6ab5fSopenharmony_ci        raise RuntimeError("Error! No name in enum\n")
1133af6ab5fSopenharmony_ci
1143af6ab5fSopenharmony_ci    res["name"] = enum_name
1153af6ab5fSopenharmony_ci    start_of_body = smart_find_first_of_characters("{", data, end_of_name)
1163af6ab5fSopenharmony_ci
1173af6ab5fSopenharmony_ci    if start_of_body == -1:
1183af6ab5fSopenharmony_ci        raise RuntimeError("Error! Empty body in enum class.")
1193af6ab5fSopenharmony_ci
1203af6ab5fSopenharmony_ci    start_of_body, end_of_body = find_scope_borders(data, start_of_body)
1213af6ab5fSopenharmony_ci
1223af6ab5fSopenharmony_ci    if data.find("<<", start_of_body, end_of_body) != -1:
1233af6ab5fSopenharmony_ci        res["kind"] = "flags"
1243af6ab5fSopenharmony_ci    else:
1253af6ab5fSopenharmony_ci        res["kind"] = "simple"
1263af6ab5fSopenharmony_ci
1273af6ab5fSopenharmony_ci    parsed_flags = parse_enum_class_body(data[start_of_body + 1 : end_of_body])
1283af6ab5fSopenharmony_ci
1293af6ab5fSopenharmony_ci    if "flags" in parsed_flags:
1303af6ab5fSopenharmony_ci        res["flags"] = parsed_flags["flags"]
1313af6ab5fSopenharmony_ci
1323af6ab5fSopenharmony_ci    if "flag_unions" in parsed_flags:
1333af6ab5fSopenharmony_ci        res["flag_unions"] = parsed_flags["flag_unions"]
1343af6ab5fSopenharmony_ci
1353af6ab5fSopenharmony_ci    console_log("parsed enum: '" + enum_name + "'")
1363af6ab5fSopenharmony_ci
1373af6ab5fSopenharmony_ci    end_of_body = data.find(";", end_of_body)
1383af6ab5fSopenharmony_ci
1393af6ab5fSopenharmony_ci    return end_of_body, res
1403af6ab5fSopenharmony_ci
1413af6ab5fSopenharmony_ci
1423af6ab5fSopenharmony_cidef get_name_of_enum_value(data: str) -> str:
1433af6ab5fSopenharmony_ci    equally_pos = data.find("=")
1443af6ab5fSopenharmony_ci
1453af6ab5fSopenharmony_ci    if equally_pos == -1:
1463af6ab5fSopenharmony_ci        return data
1473af6ab5fSopenharmony_ci
1483af6ab5fSopenharmony_ci    return data[:equally_pos].strip(" ")
149