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