1#!/usr/bin/env python3 2# coding=utf-8 3# 4# Copyright (c) 2024 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 log_tools import dump_to_file 20from text_tools import ( 21 find_first_of_characters, 22 rfind_first_of_characters, 23 smart_find_first_of_characters, 24 find_scope_borders, 25 find_first_not_restricted_character, 26) 27from parse_arguments import parse_arguments, parse_type 28 29 30def parse_method_or_constructor(data: str, start: int = 0) -> Tuple[int, Dict]: 31 """ 32 Returns end-pos, dict-parsed method or constructor 33 Note: 'function' in names of variables is alias for 'method or constructor' 34 """ 35 res: Dict[str, Any] = {} 36 end_of_args = parse_declaration_without_postfix(data, start, res) 37 38 # Defines is it declaration or definition: 39 next_semicolon = find_first_of_characters(";", data, start) # <--- for declaration 40 start_of_body = smart_find_first_of_characters("{", data, start) # <--- for definition 41 42 if next_semicolon <= start_of_body: # <--- declaration case 43 end_of_function_declaration = next_semicolon 44 end_of_function = next_semicolon 45 46 elif start_of_body != len(data): # <--- definition case 47 start_of_body, end_of_body = find_scope_borders(data, start_of_body) 48 end_of_function_declaration = start_of_body 49 end_of_function = end_of_body 50 51 else: 52 raise RuntimeError("Error! End of function declaration not found\n") 53 54 # Defines is it constructor or method 55 colon_pos = find_first_of_characters(":", data, end_of_args, end_of_function_declaration) 56 57 # Function postfix 58 if colon_pos == len(data): 59 # Postfix if method 60 function_declaration_postfix = data[end_of_args + 1 : end_of_function_declaration].strip(" \n") 61 res["raw_declaration"] = data[start:end_of_function_declaration].strip(" \n") 62 else: 63 # Postfix if constructor 64 function_declaration_postfix = data[end_of_args + 1 : colon_pos].strip(" \n") 65 res["raw_declaration"] = data[start:colon_pos].strip(" \n") 66 67 start_of_body, initializers = parse_initializers(data, colon_pos + 1) 68 start_of_body, end_of_body = find_scope_borders(data, start_of_body, "{") 69 end_of_function = end_of_body 70 updated_args, other_initializers = extract_init_args(res["args"], initializers) 71 72 if updated_args != []: 73 res["args"] = updated_args 74 if other_initializers != []: 75 res["other_initializers"] = other_initializers 76 77 if len(function_declaration_postfix): 78 res["postfix"] = function_declaration_postfix 79 80 return end_of_function + 1, res 81 82 83def parse_declaration_without_postfix(data: str, start: int, res: Dict[str, Any]) -> int: 84 # Arguments 85 start_of_args = find_first_of_characters("(", data, start) 86 87 if start_of_args >= len("operator") and data[start_of_args - len("operator") : start_of_args] == "operator": 88 start_of_args = find_first_of_characters("(", data, start_of_args + 1) 89 90 if ( 91 start_of_args > find_first_of_characters(";", data, start) 92 and data[start : data.find("\n", start)].find("operator==") == -1 93 ): 94 raise RuntimeError("Not method or constructor!") 95 96 end_of_args, res["args"] = parse_arguments(data, start_of_args) 97 98 # Name 99 start_of_function_name = rfind_first_of_characters(" *&", data, start_of_args - 1) + 1 100 if start_of_function_name > len(data): 101 start_of_function_name = 0 102 res["name"] = data[start_of_function_name:start_of_args] 103 104 if res["name"].isupper(): 105 dump_to_file("/gen/new_defines.txt", res["name"]) 106 raise RuntimeError("New macros found: '" + res["name"] + "'. Please add it to list.") 107 108 # Prefix 109 res["return_type"] = parse_type(data[start:start_of_function_name].strip(" \n")) 110 if not res["return_type"]: 111 del res["return_type"] 112 113 return end_of_args 114 115 116def parse_initializer(init: str) -> dict: 117 """ 118 ' left_(left_init) ' ---> {'class_field': 'left_', 'init_value': 'left_init'} 119 """ 120 init = init.strip(" \n") 121 res = {} 122 123 parenthese_open = find_first_of_characters("{(", init, 0) 124 125 if parenthese_open != -1: 126 parenthese_open, parenthese_close = find_scope_borders(init, parenthese_open, "") 127 else: 128 raise RuntimeError("Error! Can't find '(' or '{' in parse_initializer: '" + init + "'") 129 130 res["class_field"] = init[:parenthese_open].strip(" \n") 131 res["init_value"] = init[parenthese_open + 1 : parenthese_close] 132 133 return res 134 135 136def parse_initializers(data: str, start: int = 0) -> Tuple[int, List]: # pylint: disable=C0116 137 res = [] 138 current_pos = find_first_not_restricted_character(" \n", data, start) 139 parethese_open = find_first_of_characters("{(", data, current_pos) 140 141 while data[current_pos] != "{" and parethese_open != -1: 142 143 parethese_open, parenthese_close = find_scope_borders(data, parethese_open, "") 144 res.append(parse_initializer(data[current_pos : parenthese_close + 1])) 145 146 current_pos = find_first_not_restricted_character(", \n", data, parenthese_close + 1) 147 parethese_open = find_first_of_characters("{(", data, current_pos) 148 149 return current_pos, res 150 151 152def extract_init_args(args: list, initializers: list) -> Tuple[List, List]: 153 """ 154 If some argument is init value for class field, it adds property for this argument 155 and remove it from initializer list: 156 157 Constructor(char *a, ...) : class_field_(a), ... {} 158 159 Args list: 160 Before: {'name': 'a', 'type': 'char *'} 161 After: {'name': 'a', 'type': 'char *', 'initializer_for': 'class_field_'} 162 163 Initializers list: 164 Before: {'class_field': 'class_field_', 'init_value': 'a'} 165 After: {} 166 """ 167 168 i = 0 169 j = 0 170 171 while i < len(initializers): 172 while j < len(args) and i < len(initializers): 173 174 if args[j]["name"] == initializers[i]["init_value"]: 175 args[j]["initializer_for"] = initializers[i]["class_field"] 176 initializers.pop(i) 177 j = 0 178 continue 179 180 j += 1 181 182 i += 1 183 j = 0 184 185 return args, initializers 186