1# Copyright (c) 2016 Nuxi (https://nuxi.nl/) and contributors. 2# 3# SPDX-License-Identifier: BSD-2-Clause 4 5from .itf import read_itf, Node 6from .abi import * 7 8 9class AbiParser: 10 def parse_abi_file(self, file_name): 11 return self.parse_abi(read_itf(file_name)) 12 13 def parse_abi(self, nodes): 14 abi = Abi() 15 16 abi.doc = self.pop_documentation(Node(text='ROOT', children=nodes)) 17 18 for node in nodes: 19 decl = node.text.split() 20 21 doc = self.pop_documentation(node) 22 23 thing = None 24 25 if decl[0] in int_like_types: 26 t = self.parse_int_like_type(abi, decl, node.children) 27 abi.types[t.name] = t 28 thing = t 29 30 elif decl[0] == 'struct': 31 t = self.parse_struct(abi, decl, node.children) 32 abi.types[t.name] = t 33 thing = t 34 35 elif decl[0] == 'function': 36 t = self.parse_function(abi, decl, node.children) 37 abi.types[t.name] = t 38 thing = t 39 40 elif decl[0] == 'syscall': 41 s = self.parse_syscall(abi, decl, node.children) 42 abi.syscalls[s.name] = s 43 thing = s 44 45 else: 46 print('Invalid top level declaration: {}'.format(node.text)) 47 48 thing.doc = doc 49 50 for type in abi.types.values(): 51 type.used_by = { 52 t 53 for t in abi.types.values() 54 if type in getattr(t, 'dependencies', set()) 55 } 56 57 type.used_by.update({ 58 s 59 for s in abi.syscalls.values() 60 if type in getattr(s, 'dependencies', set()) 61 }) 62 63 return abi 64 65 def parse_int_like_type(self, abi, decl, children): 66 if len(decl) != 3: 67 raise Exception('Invalid {} declaration: {}'.format( 68 decl[0], ' '.join(decl))) 69 70 name = decl[2] 71 if name in abi.types: 72 raise Exception('Duplicate definition of {}'.format(name)) 73 74 int_type = decl[1] 75 if int_type not in int_types: 76 raise Exception('Invalid int type: {}'.format(int_type)) 77 78 values = [] 79 attr = {} 80 81 for node in children: 82 value_decl = node.text.split() 83 if value_decl[0] == '@cprefix' and len(value_decl) <= 2: 84 self.__expect_no_children(node) 85 attr['cprefix'] = (value_decl[1] 86 if len(value_decl) == 2 else '') 87 elif len(value_decl) == 2: 88 v = SpecialValue(value_decl[1], int(value_decl[0], 0)) 89 v.doc = self.pop_documentation(node) 90 self.__expect_no_children(node) 91 values.append(v) 92 else: 93 raise Exception('Invalid value: {}'.format(child.text)) 94 95 return int_like_types[decl[0]](name, int_types[int_type], values, 96 **attr) 97 98 def parse_struct(self, abi, decl, children): 99 if len(decl) != 2: 100 raise Exception('Invalid struct declaration: {}'.format( 101 decl, ' '.join(decl))) 102 103 name = decl[1] 104 if name in abi.types: 105 raise Exception('Duplicate definition of {}'.format(name)) 106 107 members = self.parse_struct_members(abi, children) 108 109 return StructType(name, members) 110 111 def parse_struct_members(self, abi, children): 112 members = [] 113 114 for node in children: 115 mem_decl = node.text.split() 116 mem = None 117 118 if mem_decl[0] == 'variant' and len(mem_decl) == 2: 119 tag_member_name = mem_decl[1] 120 tag_member = None 121 for m in members: 122 if m.name == tag_member_name: 123 if (isinstance(m, SimpleStructMember) 124 and (isinstance(m.type, EnumType) 125 or isinstance(m.type, AliasType))): 126 tag_member = m 127 break 128 else: 129 raise Exception( 130 'Variant tag ({}) must be an enum or ' 131 'an alias type.'.format(m.name)) 132 if tag_member is None: 133 raise Exception('No such member to use as variant tag: ' 134 '{}.'.format(tag_member_name)) 135 mem = self.parse_variant(abi, tag_member, node.children) 136 137 elif mem_decl[0] in {'range', 'crange'}: 138 doc = self.pop_documentation(node) 139 self.__expect_no_children(node) 140 if len(mem_decl) < 3: 141 raise Exception('Invalid range: {}'.format(node.text)) 142 mem_type = self.parse_type(abi, mem_decl[1:-1]) 143 mem_name = mem_decl[-1] 144 mem = RangeStructMember(mem_name, mem_decl[0] == 'crange', 145 mem_type) 146 mem.doc = doc 147 mem.raw_members[0].doc = doc 148 149 else: 150 mem_name = mem_decl[-1] 151 mem_type = self.parse_type(abi, mem_decl[:-1]) 152 mem_vals = [] 153 if isinstance(mem_type, IntLikeType): 154 doc = self.pop_documentation(node, optional=True) 155 for n in node.children: 156 vname = n.text 157 val = [v for v in mem_type.values if vname == v.name] 158 if len(val) != 1: 159 raise Exception( 160 'Struct member type {} has no value {}'.format( 161 mem_type.name, vname)) 162 v = SpecialValue(val[0].name, val[0].value) 163 v.doc = self.pop_documentation(n) 164 self.__expect_no_children(n) 165 mem_vals.append(v) 166 else: 167 doc = self.pop_documentation(node) 168 self.__expect_no_children(node) 169 mem = SimpleStructMember(mem_name, mem_type, mem_vals) 170 mem.doc = doc 171 172 members.append(mem) 173 174 return members 175 176 def parse_function(self, abi, decl, children): 177 if len(decl) != 2: 178 raise Exception('Invalid function declaration: {}'.format( 179 ' '.join(decl))) 180 181 name = decl[1] 182 if name in abi.types: 183 raise Exception('Duplicate definition of {}'.format(name)) 184 185 parameters = StructType(None, []) 186 return_type = VoidType() 187 188 if len(children) > 0 and children[0].text == 'in': 189 param_spec = children.pop(0) 190 parameters = StructType(None, 191 self.parse_struct_members( 192 abi, param_spec.children)) 193 194 if len(children) > 0 and children[0].text == 'out': 195 out_spec = children.pop(0) 196 doc = self.pop_documentation(out_spec) 197 if len(out_spec.children) != 1: 198 raise Exception('Expected a single return type in ' 199 '`out\' section of function.') 200 self.__expect_no_children(out_spec.children[0]) 201 return_type = (self.parse_type(abi, 202 out_spec.children[0].text.split())) 203 return_type.doc = doc 204 205 return FunctionType(name, parameters, return_type) 206 207 def parse_syscall(self, abi, decl, children): 208 if len(decl) != 2: 209 raise Exception('Invalid declaration: {}'.format(' '.join(decl))) 210 211 name = decl[1] 212 if name in abi.syscalls: 213 raise Exception('Duplicate syscall name: {}'.format(name)) 214 215 input = StructType('', []) 216 output = StructType('', []) 217 attr = {} 218 219 if len(children) > 0 and children[0].text == 'in': 220 in_spec = children.pop(0) 221 input = StructType(None, 222 self.parse_struct_members( 223 abi, in_spec.children)) 224 225 if len(children) > 0: 226 if children[0].text == 'out': 227 out_spec = children.pop(0) 228 output = StructType(None, 229 self.parse_struct_members( 230 abi, out_spec.children)) 231 232 elif children[0].text == 'noreturn': 233 noreturn_spec = children.pop(0) 234 self.__expect_no_children(noreturn_spec) 235 attr['noreturn'] = True 236 237 if children != []: 238 raise Exception('Invalid node under syscall: {}'.format( 239 children[0].text)) 240 241 syscall = Syscall(name, input, output, **attr) 242 243 return syscall 244 245 def parse_variant(self, abi, tag_member, children): 246 tag_type = tag_member.type 247 members = [] 248 249 for node in children: 250 tag_value_names = node.text.split() 251 tag_values = [] 252 for vname in tag_value_names: 253 val = [v for v in tag_type.values if vname == v.name] 254 if len(val) != 1: 255 raise Exception( 256 'Variant tag type {} has no value {}'.format( 257 tag_type.name, vname)) 258 tag_values.append(val[0]) 259 if len(node.children) != 1: 260 raise Exception( 261 'Excepted a single member in variant member `{}\'.'.format( 262 node.text)) 263 decl = node.children[0].text.split() 264 if len(decl) == 2 and decl[0] == 'struct': 265 name = decl[1] 266 spec = node.children[0] 267 else: 268 name = None 269 spec = node 270 type = StructType(None, 271 self.parse_struct_members(abi, spec.children)) 272 members.append(VariantMember(name, tag_values, type)) 273 274 return VariantStructMember(tag_member, members) 275 276 def parse_type(self, abi, decl): 277 if decl == ['void']: 278 return VoidType() 279 elif len(decl) == 1: 280 if decl[0] in int_types: 281 return int_types[decl[0]] 282 if decl[0] in abi.types: 283 return abi.types[decl[0]] 284 raise Exception('Unknown type {}'.format(' '.join(decl))) 285 elif decl[:1] == ['array'] and len(decl) > 2: 286 return ArrayType(int(decl[1], 0), self.parse_type(abi, decl[2:])) 287 elif decl[:1] == ['ptr']: 288 return PointerType(self.parse_type(abi, decl[1:])) 289 elif decl[:1] == ['cptr']: 290 return PointerType(self.parse_type(abi, decl[1:]), const=True) 291 elif decl[:1] == ['atomic']: 292 return AtomicType(self.parse_type(abi, decl[1:])) 293 else: 294 raise Exception('Invalid type: {}'.format(' '.join(decl))) 295 296 def pop_documentation(self, node, optional=False): 297 doc = '' 298 while len( 299 node.children) > 0 and (node.children[0].text.startswith('| ') 300 or node.children[0].text == '|'): 301 n = node.children.pop(0) 302 if n.children != []: 303 raise Exception( 304 'Documentation nodes should not have children.') 305 doc += n.text[2:] + '\n' 306 if doc == '' and not optional: 307 import sys 308 sys.stderr.write('Missing documentation for: {}\n'.format( 309 node.text)) 310 return doc 311 312 @staticmethod 313 def __expect_no_children(node): 314 if len(node.children) > 0: 315 raise Exception('Unexpected node inside {}: {}'.format( 316 node.text, node.children[0].text)) 317