1#!/usr/bin/env python3 2# coding=utf-8 3# 4# Copyright (c) 2024-2025 Huawei Device Co., Ltd. 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17 18from typing import Tuple, Dict, List, Any 19from text_tools import ( 20 find_first_of_characters, 21 rfind_first_of_characters, 22 smart_find_first_of_characters, 23 find_scope_borders, 24 find_first_not_restricted_character, 25) 26from parse_arguments import parse_arguments, parse_type 27 28 29def parse_method_or_constructor(data: str, start: int = 0) -> Tuple[int, Dict]: 30 """ 31 Returns end-pos, dict-parsed method or constructor 32 Note: 'function' in names of variables is alias for 'method or constructor' 33 """ 34 res: Dict[str, Any] = {} 35 36 # Defines is it declaration or definition: 37 next_semicolon = smart_find_first_of_characters(";", data, start) # <--- for declaration 38 start_of_body = smart_find_first_of_characters("{", data, start) # <--- for definition 39 40 if next_semicolon <= start_of_body: # <--- declaration case 41 end_of_function_declaration = next_semicolon 42 end_of_function = next_semicolon 43 44 elif start_of_body != len(data): # <--- definition case 45 start_of_body, end_of_body = find_scope_borders(data, start_of_body) 46 end_of_function_declaration = start_of_body 47 end_of_function = end_of_body 48 49 else: 50 raise RuntimeError("Error! End of function declaration not found\n") 51 52 # Skip operator overloading 53 if data[start: find_first_of_characters("(", data, start)].find("operator") != -1: 54 return end_of_function + 1, {} 55 56 end_of_args = parse_declaration_without_postfix(data, start, res) 57 58 # Defines is it constructor or method 59 colon_pos = find_first_of_characters(":", data, end_of_args, end_of_function_declaration) 60 61 # Function postfix 62 if colon_pos == len(data): 63 # Postfix if method 64 function_declaration_postfix = data[end_of_args + 1 : end_of_function_declaration].strip(" \n") 65 res["raw_declaration"] = data[start:end_of_function_declaration].strip(" \n") 66 else: 67 # Postfix if constructor 68 function_declaration_postfix = data[end_of_args + 1 : colon_pos].strip(" \n") 69 res["raw_declaration"] = data[start:colon_pos].strip(" \n") 70 71 end_of_initializers, initializers = parse_initializers(data, colon_pos + 1) 72 # CC-OFFNXT(G.TYP.07) dict key exist 73 updated_args, other_initializers = extract_init_args(res["args"], initializers) 74 75 if updated_args != []: 76 res["args"] = updated_args 77 if other_initializers != []: 78 res["other_initializers"] = other_initializers 79 80 if data[end_of_initializers] == '{': 81 start_of_body, end_of_body = find_scope_borders(data, end_of_initializers, "{") 82 end_of_function = end_of_body 83 84 if len(function_declaration_postfix): 85 res["postfix"] = function_declaration_postfix 86 87 if end_of_function < len(data) and data[end_of_function] != ';': 88 first_body_token_pos = find_first_not_restricted_character(' \n\t', data, start_of_body + 1) 89 if data[first_body_token_pos: first_body_token_pos + len('return')] == 'return': 90 res["additional_attributes"] = "get" 91 92 return end_of_function + 1, res 93 94 95def parse_declaration_without_postfix(data: str, start: int, res: Dict[str, Any]) -> int: 96 # Arguments 97 start_of_args = smart_find_first_of_characters("(", data, start) 98 99 if start_of_args >= len("operator") and data[start_of_args - len("operator") : start_of_args] == "operator": 100 start_of_args = find_first_of_characters("(", data, start_of_args + 1) 101 102 if ( 103 start_of_args > find_first_of_characters(";", data, start) 104 and data[start : data.find("\n", start)].find("operator==") == -1 105 ): 106 raise RuntimeError("Not method or constructor!") 107 108 end_of_args, res["args"] = parse_arguments(data, start_of_args) 109 110 # Name 111 start_of_function_name = rfind_first_of_characters(" *&\n", data, start_of_args - 1) + 1 112 if start_of_function_name > len(data): 113 start_of_function_name = 0 114 res["name"] = data[start_of_function_name:start_of_args] 115 116 if res["name"].isupper(): 117 raise RuntimeError("New macros found: '" + res["name"] + "'. Please add it to list.") 118 119 # Prefix 120 res["return_type"] = parse_type(data[start:start_of_function_name].strip(" \n")) 121 if not res["return_type"]: 122 del res["return_type"] 123 124 return end_of_args 125 126 127def parse_initializer(init: str) -> dict: 128 129 """ 130 Note ' left (left init) ' ---> 'class field': 'left', 'init value': 'left init' 131 """ 132 init = init.strip(" \n") 133 res = {} 134 135 parenthese_open = find_first_of_characters("{(", init, 0) 136 137 if parenthese_open != -1: 138 parenthese_open, parenthese_close = find_scope_borders(init, parenthese_open, "") 139 else: 140 raise RuntimeError("Error! Can't find '(' or '{' in parse_initializer: '" + init + "'") 141 142 res["class_field"] = init[:parenthese_open].strip(" \n") 143 res["init_value"] = init[parenthese_open + 1 : parenthese_close] 144 145 return res 146 147 148def parse_initializers(data: str, start: int = 0) -> Tuple[int, List]: # pylint: disable=C0116 149 res = [] 150 current_pos = find_first_not_restricted_character(" \n", data, start) 151 parethese_open = find_first_of_characters("{(", data, current_pos) 152 153 while data[current_pos] != "{" and data[current_pos] != ';' and parethese_open != len(data): 154 155 parethese_open, parenthese_close = find_scope_borders(data, parethese_open, "") 156 res.append(parse_initializer(data[current_pos : parenthese_close + 1])) 157 158 current_pos = find_first_not_restricted_character(", \n", data, parenthese_close + 1) 159 parethese_open = find_first_of_characters("{(", data, current_pos) 160 161 return current_pos, res 162 163 164def extract_init_args(args: list, initializers: list) -> Tuple[List, List]: 165 """ 166 If some argument is init value for class field, it adds property for this argument 167 and remove it from initializer list: 168 169 Constructor(char *a, ...) : class_field_(a), ... {} 170 171 Args list: 172 Before: {'name': 'a', 'type': 'char *'} 173 After: {'name': 'a', 'type': 'char *', 'initializer_for': 'class_field_'} 174 175 Initializers list: 176 Before: {'class_field': 'class_field_', 'init_value': 'a'} 177 After: {} 178 """ 179 180 i = 0 181 j = 0 182 183 while i < len(initializers): 184 while j < len(args) and i < len(initializers): 185 186 if args[j]["name"] == initializers[i]["init_value"]: 187 args[j]["initializer_for"] = initializers[i]["class_field"] 188 initializers.pop(i) 189 j = 0 190 continue 191 192 j += 1 193 194 i += 1 195 j = 0 196 197 return args, initializers 198