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 18""" 19Provides: 20- parse_type 21- parse_argument 22- parse_arguments 23""" 24 25from typing import Tuple, List, Any, Dict 26from log_tools import warning_log 27from cpp_keywords import modifiers_list 28from text_tools import ( 29 find_first_of_characters, 30 find_first_not_restricted_character, 31 find_scope_borders, 32 smart_find_first_of_characters, 33 rfind_first_not_restricted_character, 34 smart_split_by, 35 rfind_first_of_characters, 36) 37 38 39def parse_type(data: str) -> dict: 40 data = data.strip(" \n") 41 if len(data) > 100: 42 warning_log("Parsing big type!\n---\n" + data + "\n---\n") 43 44 if data == "": 45 return {} 46 47 res: Dict[str, Any] = {} 48 current_pos = extract_type_name(data, res) 49 50 for modifier in modifiers_list: 51 if data.find(modifier, current_pos) != -1: 52 if "other_modifiers" not in res: 53 res["other_modifiers"] = "" 54 55 res["other_modifiers"] = f"{res['other_modifiers']} {modifier}".strip(" ") 56 57 # Weakness (<>) 58 start_of_parenthes = data.find("(") 59 if start_of_parenthes != -1: 60 start_of_parenthes, end_of_parenthes = find_scope_borders(data, start_of_parenthes, "(") 61 res["cast_from"] = data[start_of_parenthes + 1 : end_of_parenthes] 62 current_pos = end_of_parenthes + 1 63 64 # Template in arg 65 template_open_pos = data.find("<", current_pos) 66 if template_open_pos != -1: 67 template_open_pos, template_close_pos = find_scope_borders(data, 0, "<") 68 69 offset, res["template_args"] = parse_arguments(data[template_open_pos + 1 : template_close_pos], 0, "types") 70 current_pos = template_open_pos + 1 + offset + 1 71 72 # Ptr 73 ptr_start = data.find("*", current_pos) 74 if ptr_start != -1: 75 76 ptr_end = find_first_not_restricted_character("*", data, ptr_start) 77 78 res["ptr_depth"] = ptr_end - ptr_start 79 current_pos = ptr_end 80 81 # Ref 82 ref_start = data.find("&", current_pos) 83 if ref_start != -1: 84 85 ref_end = find_first_not_restricted_character("&", data, ref_start) 86 87 res["ref_depth"] = ref_end - ref_start 88 current_pos = ref_end 89 90 postfix = data[current_pos:].strip(" \n") 91 if postfix != "": 92 res["postfix"] = postfix 93 94 return res 95 96 97def extract_type_name(data: str, res: Dict[str, Any]) -> int: 98 prefix_modifiers = "" 99 type_name_start = 0 100 type_name_end = find_first_of_characters(" <([{&*", data, type_name_start) 101 type_name = data[type_name_start:type_name_end].strip(" \n") 102 103 # Extract type name 104 while type_name in modifiers_list or type_name == "": 105 prefix_modifiers += f" {type_name}" 106 107 type_name_start = find_first_not_restricted_character(" <*", data, type_name_end) 108 type_name_end = find_first_of_characters(" <(*", data, type_name_start) 109 110 if type_name_start == len(data): 111 type_name = "" 112 break 113 114 type_name = data[type_name_start:type_name_end].strip(" \n") 115 116 # 'varbinder::LocalVariable' -> 'LocalVariable' 117 if type_name.find("::") != -1: 118 namespace = type_name[: type_name.rfind("::")] 119 type_name = type_name[type_name.rfind("::") + 2 :] 120 res["namespace"] = namespace 121 122 if type_name != "": 123 res["name"] = type_name 124 125 prefix_modifiers = prefix_modifiers.strip(" ") 126 if prefix_modifiers != "": 127 res["prefix"] = prefix_modifiers 128 129 return type_name_end 130 131 132def parse_argument(arg: str, mode: str = "args") -> Dict: 133 """ 134 modes: 135 - args: <type> <var_name> 136 - types: <only_type> 137 """ 138 139 res: Dict[str, Any] = {} 140 arg = arg.strip(" \n") 141 142 if arg == "": 143 return {} 144 145 # Default value 146 equally_pos = smart_find_first_of_characters("=", arg, 0) 147 if equally_pos != len(arg): 148 default_value_start = find_first_not_restricted_character(" ", arg, equally_pos + 1) 149 default_value_end = rfind_first_not_restricted_character("\n; ", arg, len(arg) - 1) 150 res["default_value"] = arg[default_value_start : default_value_end + 1] 151 152 arg = arg[:equally_pos].strip(" \n") 153 154 # Default constructor 155 if smart_find_first_of_characters("{", arg, 0) != len(arg): 156 start_of_constr, end_of_constr = find_scope_borders(arg) 157 res["default_constructor"] = arg[start_of_constr + 1 : end_of_constr] 158 arg = arg[:start_of_constr].strip(" \n") 159 160 # Name 161 if mode == "args": 162 name_start = rfind_first_of_characters(" *&>)}", arg, len(arg) - 1) 163 if name_start != len(arg) and name_start != len(arg) - 1: 164 name = arg[name_start + 1 :].strip(" \n") 165 if name != "": 166 res["name"] = name 167 else: 168 raise RuntimeError("Error! Argument without name!") 169 170 res["type"] = parse_type(arg[: name_start + 1]) 171 else: 172 res["type"] = parse_type(arg) 173 174 return res 175 176 177def parse_arguments(data: str, start: int = 0, mode: str = "args") -> Tuple[int, List]: 178 """ 179 data: 180 - (some arguments, ...) ... some code ... 181 - arg1, arg2, ..., arg_k 182 mode: 183 - args: TYPE ARG_NAME, ... 184 - types: TYPE, ... 185 """ 186 res = [] 187 188 start_of_args = 0 189 end_of_args = len(data) 190 191 if data[start] == "(": 192 start_of_args, end_of_args = find_scope_borders(data, start, "(") 193 start_of_args += 1 194 195 args = data[start_of_args:end_of_args] 196 args_list = smart_split_by(args, ",") 197 198 for arg in args_list: 199 parsed_arg = parse_argument(arg, mode) 200 201 if parsed_arg: 202 res.append(parsed_arg) 203 204 return end_of_args, res 205