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, List, Any
193af6ab5fSopenharmony_cifrom log_tools import dump_to_file
203af6ab5fSopenharmony_cifrom text_tools import (
213af6ab5fSopenharmony_ci    find_first_of_characters,
223af6ab5fSopenharmony_ci    rfind_first_of_characters,
233af6ab5fSopenharmony_ci    smart_find_first_of_characters,
243af6ab5fSopenharmony_ci    find_scope_borders,
253af6ab5fSopenharmony_ci    find_first_not_restricted_character,
263af6ab5fSopenharmony_ci)
273af6ab5fSopenharmony_cifrom parse_arguments import parse_arguments, parse_type
283af6ab5fSopenharmony_ci
293af6ab5fSopenharmony_ci
303af6ab5fSopenharmony_cidef parse_method_or_constructor(data: str, start: int = 0) -> Tuple[int, Dict]:
313af6ab5fSopenharmony_ci    """
323af6ab5fSopenharmony_ci    Returns end-pos, dict-parsed method or constructor
333af6ab5fSopenharmony_ci    Note: 'function' in names of variables is alias for 'method or constructor'
343af6ab5fSopenharmony_ci    """
353af6ab5fSopenharmony_ci    res: Dict[str, Any] = {}
363af6ab5fSopenharmony_ci    end_of_args = parse_declaration_without_postfix(data, start, res)
373af6ab5fSopenharmony_ci
383af6ab5fSopenharmony_ci    # Defines is it declaration or definition:
393af6ab5fSopenharmony_ci    next_semicolon = find_first_of_characters(";", data, start)  # <---  for declaration
403af6ab5fSopenharmony_ci    start_of_body = smart_find_first_of_characters("{", data, start)  # <---  for definition
413af6ab5fSopenharmony_ci
423af6ab5fSopenharmony_ci    if next_semicolon <= start_of_body:  # <---  declaration case
433af6ab5fSopenharmony_ci        end_of_function_declaration = next_semicolon
443af6ab5fSopenharmony_ci        end_of_function = next_semicolon
453af6ab5fSopenharmony_ci
463af6ab5fSopenharmony_ci    elif start_of_body != len(data):  # <---  definition case
473af6ab5fSopenharmony_ci        start_of_body, end_of_body = find_scope_borders(data, start_of_body)
483af6ab5fSopenharmony_ci        end_of_function_declaration = start_of_body
493af6ab5fSopenharmony_ci        end_of_function = end_of_body
503af6ab5fSopenharmony_ci
513af6ab5fSopenharmony_ci    else:
523af6ab5fSopenharmony_ci        raise RuntimeError("Error! End of function declaration not found\n")
533af6ab5fSopenharmony_ci
543af6ab5fSopenharmony_ci    # Defines is it constructor or method
553af6ab5fSopenharmony_ci    colon_pos = find_first_of_characters(":", data, end_of_args, end_of_function_declaration)
563af6ab5fSopenharmony_ci
573af6ab5fSopenharmony_ci    # Function postfix
583af6ab5fSopenharmony_ci    if colon_pos == len(data):
593af6ab5fSopenharmony_ci        # Postfix if method
603af6ab5fSopenharmony_ci        function_declaration_postfix = data[end_of_args + 1 : end_of_function_declaration].strip(" \n")
613af6ab5fSopenharmony_ci        res["raw_declaration"] = data[start:end_of_function_declaration].strip(" \n")
623af6ab5fSopenharmony_ci    else:
633af6ab5fSopenharmony_ci        # Postfix if constructor
643af6ab5fSopenharmony_ci        function_declaration_postfix = data[end_of_args + 1 : colon_pos].strip(" \n")
653af6ab5fSopenharmony_ci        res["raw_declaration"] = data[start:colon_pos].strip(" \n")
663af6ab5fSopenharmony_ci
673af6ab5fSopenharmony_ci        start_of_body, initializers = parse_initializers(data, colon_pos + 1)
683af6ab5fSopenharmony_ci        start_of_body, end_of_body = find_scope_borders(data, start_of_body, "{")
693af6ab5fSopenharmony_ci        end_of_function = end_of_body
703af6ab5fSopenharmony_ci        updated_args, other_initializers = extract_init_args(res["args"], initializers)
713af6ab5fSopenharmony_ci
723af6ab5fSopenharmony_ci        if updated_args != []:
733af6ab5fSopenharmony_ci            res["args"] = updated_args
743af6ab5fSopenharmony_ci        if other_initializers != []:
753af6ab5fSopenharmony_ci            res["other_initializers"] = other_initializers
763af6ab5fSopenharmony_ci
773af6ab5fSopenharmony_ci    if len(function_declaration_postfix):
783af6ab5fSopenharmony_ci        res["postfix"] = function_declaration_postfix
793af6ab5fSopenharmony_ci
803af6ab5fSopenharmony_ci    return end_of_function + 1, res
813af6ab5fSopenharmony_ci
823af6ab5fSopenharmony_ci
833af6ab5fSopenharmony_cidef parse_declaration_without_postfix(data: str, start: int, res: Dict[str, Any]) -> int:
843af6ab5fSopenharmony_ci    # Arguments
853af6ab5fSopenharmony_ci    start_of_args = find_first_of_characters("(", data, start)
863af6ab5fSopenharmony_ci
873af6ab5fSopenharmony_ci    if start_of_args >= len("operator") and data[start_of_args - len("operator") : start_of_args] == "operator":
883af6ab5fSopenharmony_ci        start_of_args = find_first_of_characters("(", data, start_of_args + 1)
893af6ab5fSopenharmony_ci
903af6ab5fSopenharmony_ci    if (
913af6ab5fSopenharmony_ci        start_of_args > find_first_of_characters(";", data, start)
923af6ab5fSopenharmony_ci        and data[start : data.find("\n", start)].find("operator==") == -1
933af6ab5fSopenharmony_ci    ):
943af6ab5fSopenharmony_ci        raise RuntimeError("Not method or constructor!")
953af6ab5fSopenharmony_ci
963af6ab5fSopenharmony_ci    end_of_args, res["args"] = parse_arguments(data, start_of_args)
973af6ab5fSopenharmony_ci
983af6ab5fSopenharmony_ci    # Name
993af6ab5fSopenharmony_ci    start_of_function_name = rfind_first_of_characters(" *&", data, start_of_args - 1) + 1
1003af6ab5fSopenharmony_ci    if start_of_function_name > len(data):
1013af6ab5fSopenharmony_ci        start_of_function_name = 0
1023af6ab5fSopenharmony_ci    res["name"] = data[start_of_function_name:start_of_args]
1033af6ab5fSopenharmony_ci
1043af6ab5fSopenharmony_ci    if res["name"].isupper():
1053af6ab5fSopenharmony_ci        dump_to_file("/gen/new_defines.txt", res["name"])
1063af6ab5fSopenharmony_ci        raise RuntimeError("New macros found: '" + res["name"] + "'. Please add it to list.")
1073af6ab5fSopenharmony_ci
1083af6ab5fSopenharmony_ci    # Prefix
1093af6ab5fSopenharmony_ci    res["return_type"] = parse_type(data[start:start_of_function_name].strip(" \n"))
1103af6ab5fSopenharmony_ci    if not res["return_type"]:
1113af6ab5fSopenharmony_ci        del res["return_type"]
1123af6ab5fSopenharmony_ci
1133af6ab5fSopenharmony_ci    return end_of_args
1143af6ab5fSopenharmony_ci
1153af6ab5fSopenharmony_ci
1163af6ab5fSopenharmony_cidef parse_initializer(init: str) -> dict:
1173af6ab5fSopenharmony_ci    """
1183af6ab5fSopenharmony_ci    ' left_(left_init) ' ---> {'class_field': 'left_', 'init_value': 'left_init'}
1193af6ab5fSopenharmony_ci    """
1203af6ab5fSopenharmony_ci    init = init.strip(" \n")
1213af6ab5fSopenharmony_ci    res = {}
1223af6ab5fSopenharmony_ci
1233af6ab5fSopenharmony_ci    parenthese_open = find_first_of_characters("{(", init, 0)
1243af6ab5fSopenharmony_ci
1253af6ab5fSopenharmony_ci    if parenthese_open != -1:
1263af6ab5fSopenharmony_ci        parenthese_open, parenthese_close = find_scope_borders(init, parenthese_open, "")
1273af6ab5fSopenharmony_ci    else:
1283af6ab5fSopenharmony_ci        raise RuntimeError("Error! Can't find '(' or '{' in parse_initializer: '" + init + "'")
1293af6ab5fSopenharmony_ci
1303af6ab5fSopenharmony_ci    res["class_field"] = init[:parenthese_open].strip(" \n")
1313af6ab5fSopenharmony_ci    res["init_value"] = init[parenthese_open + 1 : parenthese_close]
1323af6ab5fSopenharmony_ci
1333af6ab5fSopenharmony_ci    return res
1343af6ab5fSopenharmony_ci
1353af6ab5fSopenharmony_ci
1363af6ab5fSopenharmony_cidef parse_initializers(data: str, start: int = 0) -> Tuple[int, List]:  # pylint: disable=C0116
1373af6ab5fSopenharmony_ci    res = []
1383af6ab5fSopenharmony_ci    current_pos = find_first_not_restricted_character(" \n", data, start)
1393af6ab5fSopenharmony_ci    parethese_open = find_first_of_characters("{(", data, current_pos)
1403af6ab5fSopenharmony_ci
1413af6ab5fSopenharmony_ci    while data[current_pos] != "{" and parethese_open != -1:
1423af6ab5fSopenharmony_ci
1433af6ab5fSopenharmony_ci        parethese_open, parenthese_close = find_scope_borders(data, parethese_open, "")
1443af6ab5fSopenharmony_ci        res.append(parse_initializer(data[current_pos : parenthese_close + 1]))
1453af6ab5fSopenharmony_ci
1463af6ab5fSopenharmony_ci        current_pos = find_first_not_restricted_character(", \n", data, parenthese_close + 1)
1473af6ab5fSopenharmony_ci        parethese_open = find_first_of_characters("{(", data, current_pos)
1483af6ab5fSopenharmony_ci
1493af6ab5fSopenharmony_ci    return current_pos, res
1503af6ab5fSopenharmony_ci
1513af6ab5fSopenharmony_ci
1523af6ab5fSopenharmony_cidef extract_init_args(args: list, initializers: list) -> Tuple[List, List]:
1533af6ab5fSopenharmony_ci    """
1543af6ab5fSopenharmony_ci    If some argument is init value for class field, it adds property for this argument
1553af6ab5fSopenharmony_ci    and remove it from initializer list:
1563af6ab5fSopenharmony_ci
1573af6ab5fSopenharmony_ci    Constructor(char *a, ...) : class_field_(a), ... {}
1583af6ab5fSopenharmony_ci
1593af6ab5fSopenharmony_ci    Args list:
1603af6ab5fSopenharmony_ci    Before: {'name': 'a', 'type': 'char *'}
1613af6ab5fSopenharmony_ci    After:  {'name': 'a', 'type': 'char *', 'initializer_for': 'class_field_'}
1623af6ab5fSopenharmony_ci
1633af6ab5fSopenharmony_ci    Initializers list:
1643af6ab5fSopenharmony_ci    Before: {'class_field': 'class_field_', 'init_value': 'a'}
1653af6ab5fSopenharmony_ci    After:  {}
1663af6ab5fSopenharmony_ci    """
1673af6ab5fSopenharmony_ci
1683af6ab5fSopenharmony_ci    i = 0
1693af6ab5fSopenharmony_ci    j = 0
1703af6ab5fSopenharmony_ci
1713af6ab5fSopenharmony_ci    while i < len(initializers):
1723af6ab5fSopenharmony_ci        while j < len(args) and i < len(initializers):
1733af6ab5fSopenharmony_ci
1743af6ab5fSopenharmony_ci            if args[j]["name"] == initializers[i]["init_value"]:
1753af6ab5fSopenharmony_ci                args[j]["initializer_for"] = initializers[i]["class_field"]
1763af6ab5fSopenharmony_ci                initializers.pop(i)
1773af6ab5fSopenharmony_ci                j = 0
1783af6ab5fSopenharmony_ci                continue
1793af6ab5fSopenharmony_ci
1803af6ab5fSopenharmony_ci            j += 1
1813af6ab5fSopenharmony_ci
1823af6ab5fSopenharmony_ci        i += 1
1833af6ab5fSopenharmony_ci        j = 0
1843af6ab5fSopenharmony_ci
1853af6ab5fSopenharmony_ci    return args, initializers
186