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