• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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