• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (C) 2020 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#   http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14"""Functions to build and parse directives from CFG files."""
15
16import re
17
18from typing import Iterable, List
19
20from perf2cfg import exceptions
21
22
23def build_flags(flags: Iterable[str]) -> str:
24    """Builds a flags directive from a list of arguments.
25
26    Args:
27        flags (Iterable[str]): An iterable of flags.
28
29    Returns:
30        str: A flags directive with the given arguments.
31
32    Examples:
33        >>> parse_flags(['catch_block', 'critical'])
34        '    flags "catch_block" "critical"'
35    """
36    if not flags:
37        return '    flags'
38
39    args = ' '.join(f'"{flag}"' for flag in flags)
40    return f'    flags {args}'
41
42
43def build_name(name: str) -> str:
44    """Builds a name directive from an argument.
45
46    Args:
47        name (str): An argument.
48
49    Returns:
50        str: A name directive with the given argument.
51    """
52    return f'  name "{name}"'
53
54
55def parse_address(line: str) -> int:
56    """Parses an address from a line.
57
58    Args:
59        line (str): A line to parse an address from.
60
61    Returns:
62        int: An instruction address.
63
64    Raises:
65        exceptions.ParseError: An error occurred during parsing.
66
67    Examples:
68        >>> parse_address('0x0000001c: d503201f nop')
69        28
70    """
71    parts = line.split(':', 1)
72    addr = parts[0]
73
74    try:
75        return int(addr, 16)
76    except ValueError:
77        raise exceptions.ParseError('Expected an address')
78
79
80def parse_flags(line: str) -> List[str]:
81    """Parses a flags directive from a line.
82
83    Args:
84        line (str): A line to parse a flags directive from.
85
86    Returns:
87        List[str]: A list of unquoted arguments from a flags directive, or an
88            empty list if no arguments were found.
89
90    Raises:
91        exceptions.ParseError: An error occurred during parsing.
92
93    Example:
94        >>> parse_flags('flags "catch_block" "critical"')
95        ['catch_block', 'critical']
96    """
97    parts = line.split(None, 1)
98    if parts[0] != 'flags':
99        raise exceptions.ParseError('Expected a `flags` directive')
100
101    if len(parts) < 2:
102        return []
103
104    return re.findall(r'\"([^\"]+)\"', parts[1])
105
106
107def parse_name(line: str) -> str:
108    """Parses a name directive from a line.
109
110    Args:
111        line (str): A line to parse a name directive from.
112
113    Returns:
114        str: The unquoted argument of a name directive.
115
116    Raises:
117        exceptions.ParseError: An error occurred during parsing.
118
119    Examples:
120        >>> parse_name('name "disassembly (after)"')
121        'disassembly (after)'
122    """
123    parts = line.split(None, 1)
124    if parts[0] != 'name':
125        raise exceptions.ParseError('Expected a `name` directive')
126
127    if len(parts) < 2:
128        raise exceptions.ParseError(
129            'Expected an argument to the `name` directive')
130
131    return parts[1].strip('"')
132