1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/idl-parser/xpidl.py Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1421 @@ 1.4 +#!/usr/bin/env python 1.5 +# xpidl.py - A parser for cross-platform IDL (XPIDL) files. 1.6 +# 1.7 +# This Source Code Form is subject to the terms of the Mozilla Public 1.8 +# License, v. 2.0. If a copy of the MPL was not distributed with this 1.9 +# file, You can obtain one at http://mozilla.org/MPL/2.0/. 1.10 + 1.11 +"""A parser for cross-platform IDL (XPIDL) files.""" 1.12 + 1.13 +import sys, os.path, re 1.14 +from ply import lex, yacc 1.15 + 1.16 +"""A type conforms to the following pattern: 1.17 + 1.18 + def isScriptable(self): 1.19 + 'returns True or False' 1.20 + 1.21 + def nativeType(self, calltype): 1.22 + 'returns a string representation of the native type 1.23 + calltype must be 'in', 'out', or 'inout' 1.24 + 1.25 +Interface members const/method/attribute conform to the following pattern: 1.26 + 1.27 + name = 'string' 1.28 + 1.29 + def toIDL(self): 1.30 + 'returns the member signature as IDL' 1.31 +""" 1.32 + 1.33 +def attlistToIDL(attlist): 1.34 + if len(attlist) == 0: 1.35 + return '' 1.36 + 1.37 + attlist = list(attlist) 1.38 + attlist.sort(cmp=lambda a,b: cmp(a[0], b[0])) 1.39 + 1.40 + return '[%s] ' % ','.join(["%s%s" % (name, value is not None and '(%s)' % value or '') 1.41 + for name, value, aloc in attlist]) 1.42 + 1.43 +_paramsHardcode = { 1.44 + 2: ('array', 'shared', 'iid_is', 'size_is', 'retval'), 1.45 + 3: ('array', 'size_is', 'const'), 1.46 +} 1.47 + 1.48 +def paramAttlistToIDL(attlist): 1.49 + if len(attlist) == 0: 1.50 + return '' 1.51 + 1.52 + # Hack alert: g_hash_table_foreach is pretty much unimitatable... hardcode 1.53 + # quirk 1.54 + attlist = list(attlist) 1.55 + sorted = [] 1.56 + if len(attlist) in _paramsHardcode: 1.57 + for p in _paramsHardcode[len(attlist)]: 1.58 + i = 0 1.59 + while i < len(attlist): 1.60 + if attlist[i][0] == p: 1.61 + sorted.append(attlist[i]) 1.62 + del attlist[i] 1.63 + continue 1.64 + 1.65 + i += 1 1.66 + 1.67 + sorted.extend(attlist) 1.68 + 1.69 + return '[%s] ' % ', '.join(["%s%s" % (name, value is not None and ' (%s)' % value or '') 1.70 + for name, value, aloc in sorted]) 1.71 + 1.72 +def unaliasType(t): 1.73 + while t.kind == 'typedef': 1.74 + t = t.realtype 1.75 + assert t is not None 1.76 + return t 1.77 + 1.78 +def getBuiltinOrNativeTypeName(t): 1.79 + t = unaliasType(t) 1.80 + if t.kind == 'builtin': 1.81 + return t.name 1.82 + elif t.kind == 'native': 1.83 + assert t.specialtype is not None 1.84 + return '[%s]' % t.specialtype 1.85 + else: 1.86 + return None 1.87 + 1.88 +class BuiltinLocation(object): 1.89 + def get(self): 1.90 + return "<builtin type>" 1.91 + 1.92 + def __str__(self): 1.93 + return self.get() 1.94 + 1.95 +class Builtin(object): 1.96 + kind = 'builtin' 1.97 + location = BuiltinLocation 1.98 + 1.99 + def __init__(self, name, nativename, signed=False, maybeConst=False): 1.100 + self.name = name 1.101 + self.nativename = nativename 1.102 + self.signed = signed 1.103 + self.maybeConst = maybeConst 1.104 + 1.105 + def isScriptable(self): 1.106 + return True 1.107 + 1.108 + def nativeType(self, calltype, shared=False, const=False): 1.109 + if const: 1.110 + print >>sys.stderr, IDLError("[const] doesn't make sense on builtin types.", self.location, warning=True) 1.111 + const = 'const ' 1.112 + elif calltype == 'in' and self.nativename.endswith('*'): 1.113 + const = 'const ' 1.114 + elif shared: 1.115 + if not self.nativename.endswith('*'): 1.116 + raise IDLError("[shared] not applicable to non-pointer types.", self.location) 1.117 + const = 'const ' 1.118 + else: 1.119 + const = '' 1.120 + return "%s%s %s" % (const, self.nativename, 1.121 + calltype != 'in' and '*' or '') 1.122 + 1.123 +builtinNames = [ 1.124 + Builtin('boolean', 'bool'), 1.125 + Builtin('void', 'void'), 1.126 + Builtin('octet', 'uint8_t'), 1.127 + Builtin('short', 'int16_t', True, True), 1.128 + Builtin('long', 'int32_t', True, True), 1.129 + Builtin('long long', 'int64_t', True, False), 1.130 + Builtin('unsigned short', 'uint16_t', False, True), 1.131 + Builtin('unsigned long', 'uint32_t', False, True), 1.132 + Builtin('unsigned long long', 'uint64_t', False, False), 1.133 + Builtin('float', 'float', True, False), 1.134 + Builtin('double', 'double', True, False), 1.135 + Builtin('char', 'char', True, False), 1.136 + Builtin('string', 'char *', False, False), 1.137 + Builtin('wchar', 'char16_t', False, False), 1.138 + Builtin('wstring', 'char16_t *', False, False), 1.139 +] 1.140 + 1.141 +builtinMap = {} 1.142 +for b in builtinNames: 1.143 + builtinMap[b.name] = b 1.144 + 1.145 +class Location(object): 1.146 + _line = None 1.147 + 1.148 + def __init__(self, lexer, lineno, lexpos): 1.149 + self._lineno = lineno 1.150 + self._lexpos = lexpos 1.151 + self._lexdata = lexer.lexdata 1.152 + self._file = getattr(lexer, 'filename', "<unknown>") 1.153 + 1.154 + def __eq__(self, other): 1.155 + return self._lexpos == other._lexpos and \ 1.156 + self._file == other._file 1.157 + 1.158 + def resolve(self): 1.159 + if self._line: 1.160 + return 1.161 + 1.162 + startofline = self._lexdata.rfind('\n', 0, self._lexpos) + 1 1.163 + endofline = self._lexdata.find('\n', self._lexpos, self._lexpos + 80) 1.164 + self._line = self._lexdata[startofline:endofline] 1.165 + self._colno = self._lexpos - startofline 1.166 + 1.167 + def pointerline(self): 1.168 + def i(): 1.169 + for i in xrange(0, self._colno): 1.170 + yield " " 1.171 + yield "^" 1.172 + 1.173 + return "".join(i()) 1.174 + 1.175 + def get(self): 1.176 + self.resolve() 1.177 + return "%s line %s:%s" % (self._file, self._lineno, self._colno) 1.178 + 1.179 + def __str__(self): 1.180 + self.resolve() 1.181 + return "%s line %s:%s\n%s\n%s" % (self._file, self._lineno, self._colno, 1.182 + self._line, self.pointerline()) 1.183 + 1.184 +class NameMap(object): 1.185 + """Map of name -> object. Each object must have a .name and .location property. 1.186 + Setting the same name twice throws an error.""" 1.187 + def __init__(self): 1.188 + self._d = {} 1.189 + 1.190 + def __getitem__(self, key): 1.191 + if key in builtinMap: 1.192 + return builtinMap[key] 1.193 + return self._d[key] 1.194 + 1.195 + def __iter__(self): 1.196 + return self._d.itervalues() 1.197 + 1.198 + def __contains__(self, key): 1.199 + return key in builtinMap or key in self._d 1.200 + 1.201 + def set(self, object): 1.202 + if object.name in builtinMap: 1.203 + raise IDLError("name '%s' is a builtin and cannot be redeclared" % (object.name), object.location) 1.204 + if object.name.startswith("_"): 1.205 + object.name = object.name[1:] 1.206 + if object.name in self._d: 1.207 + old = self._d[object.name] 1.208 + if old == object: return 1.209 + if isinstance(old, Forward) and isinstance(object, Interface): 1.210 + self._d[object.name] = object 1.211 + elif isinstance(old, Interface) and isinstance(object, Forward): 1.212 + pass 1.213 + else: 1.214 + raise IDLError("name '%s' specified twice. Previous location: %s" % (object.name, self._d[object.name].location), object.location) 1.215 + else: 1.216 + self._d[object.name] = object 1.217 + 1.218 + def get(self, id, location): 1.219 + try: 1.220 + return self[id] 1.221 + except KeyError: 1.222 + raise IDLError("Name '%s' not found", location) 1.223 + 1.224 +class IDLError(Exception): 1.225 + def __init__(self, message, location, warning=False): 1.226 + self.message = message 1.227 + self.location = location 1.228 + self.warning = warning 1.229 + 1.230 + def __str__(self): 1.231 + return "%s: %s, %s" % (self.warning and 'warning' or 'error', 1.232 + self.message, self.location) 1.233 + 1.234 +class Include(object): 1.235 + kind = 'include' 1.236 + 1.237 + def __init__(self, filename, location): 1.238 + self.filename = filename 1.239 + self.location = location 1.240 + 1.241 + def __str__(self): 1.242 + return "".join(["include '%s'\n" % self.filename]) 1.243 + 1.244 + def resolve(self, parent): 1.245 + def incfiles(): 1.246 + yield self.filename 1.247 + for dir in parent.incdirs: 1.248 + yield os.path.join(dir, self.filename) 1.249 + 1.250 + for file in incfiles(): 1.251 + if not os.path.exists(file): continue 1.252 + 1.253 + self.IDL = parent.parser.parse(open(file).read(), filename=file) 1.254 + self.IDL.resolve(parent.incdirs, parent.parser) 1.255 + for type in self.IDL.getNames(): 1.256 + parent.setName(type) 1.257 + parent.deps.extend(self.IDL.deps) 1.258 + return 1.259 + 1.260 + raise IDLError("File '%s' not found" % self.filename, self.location) 1.261 + 1.262 +class IDL(object): 1.263 + def __init__(self, productions): 1.264 + self.productions = productions 1.265 + self.deps = [] 1.266 + 1.267 + def setName(self, object): 1.268 + self.namemap.set(object) 1.269 + 1.270 + def getName(self, id, location): 1.271 + try: 1.272 + return self.namemap[id] 1.273 + except KeyError: 1.274 + raise IDLError("type '%s' not found" % id, location) 1.275 + 1.276 + def hasName(self, id): 1.277 + return id in self.namemap 1.278 + 1.279 + def getNames(self): 1.280 + return iter(self.namemap) 1.281 + 1.282 + def __str__(self): 1.283 + return "".join([str(p) for p in self.productions]) 1.284 + 1.285 + def resolve(self, incdirs, parser): 1.286 + self.namemap = NameMap() 1.287 + self.incdirs = incdirs 1.288 + self.parser = parser 1.289 + for p in self.productions: 1.290 + p.resolve(self) 1.291 + 1.292 + def includes(self): 1.293 + for p in self.productions: 1.294 + if p.kind == 'include': 1.295 + yield p 1.296 + 1.297 + def needsJSTypes(self): 1.298 + for p in self.productions: 1.299 + if p.kind == 'interface' and p.needsJSTypes(): 1.300 + return True 1.301 + return False 1.302 + 1.303 +class CDATA(object): 1.304 + kind = 'cdata' 1.305 + _re = re.compile(r'\n+') 1.306 + 1.307 + def __init__(self, data, location): 1.308 + self.data = self._re.sub('\n', data) 1.309 + self.location = location 1.310 + 1.311 + def resolve(self, parent): 1.312 + pass 1.313 + 1.314 + def __str__(self): 1.315 + return "cdata: %s\n\t%r\n" % (self.location.get(), self.data) 1.316 + 1.317 + def count(self): 1.318 + return 0 1.319 + 1.320 +class Typedef(object): 1.321 + kind = 'typedef' 1.322 + 1.323 + def __init__(self, type, name, location, doccomments): 1.324 + self.type = type 1.325 + self.name = name 1.326 + self.location = location 1.327 + self.doccomments = doccomments 1.328 + 1.329 + def __eq__(self, other): 1.330 + return self.name == other.name and self.type == other.type 1.331 + 1.332 + def resolve(self, parent): 1.333 + parent.setName(self) 1.334 + self.realtype = parent.getName(self.type, self.location) 1.335 + 1.336 + def isScriptable(self): 1.337 + return self.realtype.isScriptable() 1.338 + 1.339 + def nativeType(self, calltype): 1.340 + return "%s %s" % (self.name, 1.341 + calltype != 'in' and '*' or '') 1.342 + 1.343 + def __str__(self): 1.344 + return "typedef %s %s\n" % (self.type, self.name) 1.345 + 1.346 +class Forward(object): 1.347 + kind = 'forward' 1.348 + 1.349 + def __init__(self, name, location, doccomments): 1.350 + self.name = name 1.351 + self.location = location 1.352 + self.doccomments = doccomments 1.353 + 1.354 + def __eq__(self, other): 1.355 + return other.kind == 'forward' and other.name == self.name 1.356 + 1.357 + def resolve(self, parent): 1.358 + # Hack alert: if an identifier is already present, move the doccomments 1.359 + # forward. 1.360 + if parent.hasName(self.name): 1.361 + for i in xrange(0, len(parent.productions)): 1.362 + if parent.productions[i] is self: break 1.363 + for i in xrange(i + 1, len(parent.productions)): 1.364 + if hasattr(parent.productions[i], 'doccomments'): 1.365 + parent.productions[i].doccomments[0:0] = self.doccomments 1.366 + break 1.367 + 1.368 + parent.setName(self) 1.369 + 1.370 + def isScriptable(self): 1.371 + return True 1.372 + 1.373 + def nativeType(self, calltype): 1.374 + return "%s %s" % (self.name, 1.375 + calltype != 'in' and '* *' or '*') 1.376 + 1.377 + def __str__(self): 1.378 + return "forward-declared %s\n" % self.name 1.379 + 1.380 +class Native(object): 1.381 + kind = 'native' 1.382 + 1.383 + modifier = None 1.384 + specialtype = None 1.385 + 1.386 + specialtypes = { 1.387 + 'nsid': None, 1.388 + 'domstring': 'nsAString', 1.389 + 'utf8string': 'nsACString', 1.390 + 'cstring': 'nsACString', 1.391 + 'astring': 'nsAString', 1.392 + 'jsval': 'JS::Value' 1.393 + } 1.394 + 1.395 + def __init__(self, name, nativename, attlist, location): 1.396 + self.name = name 1.397 + self.nativename = nativename 1.398 + self.location = location 1.399 + 1.400 + for name, value, aloc in attlist: 1.401 + if value is not None: 1.402 + raise IDLError("Unexpected attribute value", aloc) 1.403 + if name in ('ptr', 'ref'): 1.404 + if self.modifier is not None: 1.405 + raise IDLError("More than one ptr/ref modifier", aloc) 1.406 + self.modifier = name 1.407 + elif name in self.specialtypes.keys(): 1.408 + if self.specialtype is not None: 1.409 + raise IDLError("More than one special type", aloc) 1.410 + self.specialtype = name 1.411 + if self.specialtypes[name] is not None: 1.412 + self.nativename = self.specialtypes[name] 1.413 + else: 1.414 + raise IDLError("Unexpected attribute", aloc) 1.415 + 1.416 + def __eq__(self, other): 1.417 + return self.name == other.name and \ 1.418 + self.nativename == other.nativename and \ 1.419 + self.modifier == other.modifier and \ 1.420 + self.specialtype == other.specialtype 1.421 + 1.422 + def resolve(self, parent): 1.423 + parent.setName(self) 1.424 + 1.425 + def isScriptable(self): 1.426 + if self.specialtype is None: 1.427 + return False 1.428 + 1.429 + if self.specialtype == 'nsid': 1.430 + return self.modifier is not None 1.431 + 1.432 + return self.modifier == 'ref' 1.433 + 1.434 + def isPtr(self, calltype): 1.435 + return self.modifier == 'ptr' 1.436 + 1.437 + def isRef(self, calltype): 1.438 + return self.modifier == 'ref' 1.439 + 1.440 + def nativeType(self, calltype, const=False, shared=False): 1.441 + if shared: 1.442 + if calltype != 'out': 1.443 + raise IDLError("[shared] only applies to out parameters.") 1.444 + const = True 1.445 + 1.446 + if self.specialtype is not None and calltype == 'in': 1.447 + const = True 1.448 + 1.449 + if self.specialtype == 'jsval': 1.450 + if calltype == 'out' or calltype == 'inout': 1.451 + return "JS::MutableHandleValue " 1.452 + return "JS::HandleValue " 1.453 + 1.454 + if self.isRef(calltype): 1.455 + m = '& ' 1.456 + elif self.isPtr(calltype): 1.457 + m = '*' + ((self.modifier == 'ptr' and calltype != 'in') and '*' or '') 1.458 + else: 1.459 + m = calltype != 'in' and '*' or '' 1.460 + return "%s%s %s" % (const and 'const ' or '', self.nativename, m) 1.461 + 1.462 + def __str__(self): 1.463 + return "native %s(%s)\n" % (self.name, self.nativename) 1.464 + 1.465 +class Interface(object): 1.466 + kind = 'interface' 1.467 + 1.468 + def __init__(self, name, attlist, base, members, location, doccomments): 1.469 + self.name = name 1.470 + self.attributes = InterfaceAttributes(attlist, location) 1.471 + self.base = base 1.472 + self.members = members 1.473 + self.location = location 1.474 + self.namemap = NameMap() 1.475 + self.doccomments = doccomments 1.476 + self.nativename = name 1.477 + 1.478 + for m in members: 1.479 + if not isinstance(m, CDATA): 1.480 + self.namemap.set(m) 1.481 + 1.482 + def __eq__(self, other): 1.483 + return self.name == other.name and self.location == other.location 1.484 + 1.485 + def resolve(self, parent): 1.486 + self.idl = parent 1.487 + 1.488 + # Hack alert: if an identifier is already present, libIDL assigns 1.489 + # doc comments incorrectly. This is quirks-mode extraordinaire! 1.490 + if parent.hasName(self.name): 1.491 + for member in self.members: 1.492 + if hasattr(member, 'doccomments'): 1.493 + member.doccomments[0:0] = self.doccomments 1.494 + break 1.495 + self.doccomments = parent.getName(self.name, None).doccomments 1.496 + 1.497 + if self.attributes.function: 1.498 + has_method = False 1.499 + for member in self.members: 1.500 + if member.kind is 'method': 1.501 + if has_method: 1.502 + raise IDLError("interface '%s' has multiple methods, but marked 'function'" % self.name, self.location) 1.503 + else: 1.504 + has_method = True 1.505 + 1.506 + parent.setName(self) 1.507 + if self.base is not None: 1.508 + realbase = parent.getName(self.base, self.location) 1.509 + if realbase.kind != 'interface': 1.510 + raise IDLError("interface '%s' inherits from non-interface type '%s'" % (self.name, self.base), self.location) 1.511 + 1.512 + if self.attributes.scriptable and not realbase.attributes.scriptable: 1.513 + print >>sys.stderr, IDLError("interface '%s' is scriptable but derives from non-scriptable '%s'" % (self.name, self.base), self.location, warning=True) 1.514 + 1.515 + if self.attributes.scriptable and realbase.attributes.builtinclass and not self.attributes.builtinclass: 1.516 + raise IDLError("interface '%s' is not builtinclass but derives from builtinclass '%s'" % (self.name, self.base), self.location) 1.517 + 1.518 + for member in self.members: 1.519 + member.resolve(self) 1.520 + 1.521 + # The number 250 is NOT arbitrary; this number is the maximum number of 1.522 + # stub entries defined in xpcom/reflect/xptcall/public/genstubs.pl 1.523 + # Do not increase this value without increasing the number in that 1.524 + # location, or you WILL cause otherwise unknown problems! 1.525 + if self.countEntries() > 250 and not self.attributes.builtinclass: 1.526 + raise IDLError("interface '%s' has too many entries" % self.name, 1.527 + self.location) 1.528 + 1.529 + def isScriptable(self): 1.530 + # NOTE: this is not whether *this* interface is scriptable... it's 1.531 + # whether, when used as a type, it's scriptable, which is true of all 1.532 + # interfaces. 1.533 + return True 1.534 + 1.535 + def nativeType(self, calltype, const=False): 1.536 + return "%s%s %s" % (const and 'const ' or '', 1.537 + self.name, 1.538 + calltype != 'in' and '* *' or '*') 1.539 + 1.540 + def __str__(self): 1.541 + l = ["interface %s\n" % self.name] 1.542 + if self.base is not None: 1.543 + l.append("\tbase %s\n" % self.base) 1.544 + l.append(str(self.attributes)) 1.545 + if self.members is None: 1.546 + l.append("\tincomplete type\n") 1.547 + else: 1.548 + for m in self.members: 1.549 + l.append(str(m)) 1.550 + return "".join(l) 1.551 + 1.552 + def getConst(self, name, location): 1.553 + # The constant may be in a base class 1.554 + iface = self 1.555 + while name not in iface.namemap and iface is not None: 1.556 + iface = self.idl.getName(self.base, self.location) 1.557 + if iface is None: 1.558 + raise IDLError("cannot find symbol '%s'" % name, c.location) 1.559 + c = iface.namemap.get(name, location) 1.560 + if c.kind != 'const': 1.561 + raise IDLError("symbol '%s' is not a constant", c.location) 1.562 + 1.563 + return c.getValue() 1.564 + 1.565 + def needsJSTypes(self): 1.566 + for m in self.members: 1.567 + if m.kind == "attribute" and m.type == "jsval": 1.568 + return True 1.569 + if m.kind == "method" and m.needsJSTypes(): 1.570 + return True 1.571 + return False 1.572 + 1.573 + def countEntries(self): 1.574 + ''' Returns the number of entries in the vtable for this interface. ''' 1.575 + total = sum(member.count() for member in self.members) 1.576 + if self.base is not None: 1.577 + realbase = self.idl.getName(self.base, self.location) 1.578 + total += realbase.countEntries() 1.579 + return total 1.580 + 1.581 +class InterfaceAttributes(object): 1.582 + uuid = None 1.583 + scriptable = False 1.584 + builtinclass = False 1.585 + function = False 1.586 + deprecated = False 1.587 + noscript = False 1.588 + 1.589 + def setuuid(self, value): 1.590 + self.uuid = value.lower() 1.591 + 1.592 + def setscriptable(self): 1.593 + self.scriptable = True 1.594 + 1.595 + def setfunction(self): 1.596 + self.function = True 1.597 + 1.598 + def setnoscript(self): 1.599 + self.noscript = True 1.600 + 1.601 + def setbuiltinclass(self): 1.602 + self.builtinclass = True 1.603 + 1.604 + def setdeprecated(self): 1.605 + self.deprecated = True 1.606 + 1.607 + actions = { 1.608 + 'uuid': (True, setuuid), 1.609 + 'scriptable': (False, setscriptable), 1.610 + 'builtinclass': (False, setbuiltinclass), 1.611 + 'function': (False, setfunction), 1.612 + 'noscript': (False, setnoscript), 1.613 + 'deprecated': (False, setdeprecated), 1.614 + 'object': (False, lambda self: True), 1.615 + } 1.616 + 1.617 + def __init__(self, attlist, location): 1.618 + def badattribute(self): 1.619 + raise IDLError("Unexpected interface attribute '%s'" % name, location) 1.620 + 1.621 + for name, val, aloc in attlist: 1.622 + hasval, action = self.actions.get(name, (False, badattribute)) 1.623 + if hasval: 1.624 + if val is None: 1.625 + raise IDLError("Expected value for attribute '%s'" % name, 1.626 + aloc) 1.627 + 1.628 + action(self, val) 1.629 + else: 1.630 + if val is not None: 1.631 + raise IDLError("Unexpected value for attribute '%s'" % name, 1.632 + aloc) 1.633 + 1.634 + action(self) 1.635 + 1.636 + if self.uuid is None: 1.637 + raise IDLError("interface has no uuid", location) 1.638 + 1.639 + def __str__(self): 1.640 + l = [] 1.641 + if self.uuid: 1.642 + l.append("\tuuid: %s\n" % self.uuid) 1.643 + if self.scriptable: 1.644 + l.append("\tscriptable\n") 1.645 + if self.builtinclass: 1.646 + l.append("\tbuiltinclass\n") 1.647 + if self.function: 1.648 + l.append("\tfunction\n") 1.649 + return "".join(l) 1.650 + 1.651 +class ConstMember(object): 1.652 + kind = 'const' 1.653 + def __init__(self, type, name, value, location, doccomments): 1.654 + self.type = type 1.655 + self.name = name 1.656 + self.value = value 1.657 + self.location = location 1.658 + self.doccomments = doccomments 1.659 + 1.660 + def resolve(self, parent): 1.661 + self.realtype = parent.idl.getName(self.type, self.location) 1.662 + self.iface = parent 1.663 + basetype = self.realtype 1.664 + while isinstance(basetype, Typedef): 1.665 + basetype = basetype.realtype 1.666 + if not isinstance(basetype, Builtin) or not basetype.maybeConst: 1.667 + raise IDLError("const may only be a short or long type, not %s" % self.type, self.location) 1.668 + 1.669 + self.basetype = basetype 1.670 + 1.671 + def getValue(self): 1.672 + return self.value(self.iface) 1.673 + 1.674 + def __str__(self): 1.675 + return "\tconst %s %s = %s\n" % (self.type, self.name, self.getValue()) 1.676 + 1.677 + def count(self): 1.678 + return 0 1.679 + 1.680 +class Attribute(object): 1.681 + kind = 'attribute' 1.682 + noscript = False 1.683 + readonly = False 1.684 + implicit_jscontext = False 1.685 + nostdcall = False 1.686 + binaryname = None 1.687 + null = None 1.688 + undefined = None 1.689 + deprecated = False 1.690 + infallible = False 1.691 + 1.692 + def __init__(self, type, name, attlist, readonly, location, doccomments): 1.693 + self.type = type 1.694 + self.name = name 1.695 + self.attlist = attlist 1.696 + self.readonly = readonly 1.697 + self.location = location 1.698 + self.doccomments = doccomments 1.699 + 1.700 + for name, value, aloc in attlist: 1.701 + if name == 'binaryname': 1.702 + if value is None: 1.703 + raise IDLError("binaryname attribute requires a value", 1.704 + aloc) 1.705 + 1.706 + self.binaryname = value 1.707 + continue 1.708 + 1.709 + if name == 'Null': 1.710 + if value is None: 1.711 + raise IDLError("'Null' attribute requires a value", aloc) 1.712 + if readonly: 1.713 + raise IDLError("'Null' attribute only makes sense for setters", 1.714 + aloc); 1.715 + if value not in ('Empty', 'Null', 'Stringify'): 1.716 + raise IDLError("'Null' attribute value must be 'Empty', 'Null' or 'Stringify'", 1.717 + aloc); 1.718 + self.null = value 1.719 + elif name == 'Undefined': 1.720 + if value is None: 1.721 + raise IDLError("'Undefined' attribute requires a value", aloc) 1.722 + if readonly: 1.723 + raise IDLError("'Undefined' attribute only makes sense for setters", 1.724 + aloc); 1.725 + if value not in ('Empty', 'Null'): 1.726 + raise IDLError("'Undefined' attribute value must be 'Empty' or 'Null'", 1.727 + aloc); 1.728 + self.undefined = value 1.729 + else: 1.730 + if value is not None: 1.731 + raise IDLError("Unexpected attribute value", aloc) 1.732 + 1.733 + if name == 'noscript': 1.734 + self.noscript = True 1.735 + elif name == 'implicit_jscontext': 1.736 + self.implicit_jscontext = True 1.737 + elif name == 'deprecated': 1.738 + self.deprecated = True 1.739 + elif name == 'nostdcall': 1.740 + self.nostdcall = True 1.741 + elif name == 'infallible': 1.742 + self.infallible = True 1.743 + else: 1.744 + raise IDLError("Unexpected attribute '%s'" % name, aloc) 1.745 + 1.746 + def resolve(self, iface): 1.747 + self.iface = iface 1.748 + self.realtype = iface.idl.getName(self.type, self.location) 1.749 + if (self.null is not None and 1.750 + getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'): 1.751 + raise IDLError("'Null' attribute can only be used on DOMString", 1.752 + self.location) 1.753 + if (self.undefined is not None and 1.754 + getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'): 1.755 + raise IDLError("'Undefined' attribute can only be used on DOMString", 1.756 + self.location) 1.757 + if self.infallible and not self.realtype.kind == 'builtin': 1.758 + raise IDLError('[infallible] only works on builtin types ' 1.759 + '(numbers, booleans, and raw char types)', 1.760 + self.location) 1.761 + if self.infallible and not iface.attributes.builtinclass: 1.762 + raise IDLError('[infallible] attributes are only allowed on ' 1.763 + '[builtinclass] interfaces', 1.764 + self.location) 1.765 + 1.766 + 1.767 + def toIDL(self): 1.768 + attribs = attlistToIDL(self.attlist) 1.769 + readonly = self.readonly and 'readonly ' or '' 1.770 + return "%s%sattribute %s %s;" % (attribs, readonly, self.type, self.name) 1.771 + 1.772 + def isScriptable(self): 1.773 + if not self.iface.attributes.scriptable: return False 1.774 + return not self.noscript 1.775 + 1.776 + def __str__(self): 1.777 + return "\t%sattribute %s %s\n" % (self.readonly and 'readonly ' or '', 1.778 + self.type, self.name) 1.779 + 1.780 + def count(self): 1.781 + return self.readonly and 1 or 2 1.782 + 1.783 +class Method(object): 1.784 + kind = 'method' 1.785 + noscript = False 1.786 + notxpcom = False 1.787 + binaryname = None 1.788 + implicit_jscontext = False 1.789 + nostdcall = False 1.790 + optional_argc = False 1.791 + deprecated = False 1.792 + 1.793 + def __init__(self, type, name, attlist, paramlist, location, doccomments, raises): 1.794 + self.type = type 1.795 + self.name = name 1.796 + self.attlist = attlist 1.797 + self.params = paramlist 1.798 + self.location = location 1.799 + self.doccomments = doccomments 1.800 + self.raises = raises 1.801 + 1.802 + for name, value, aloc in attlist: 1.803 + if name == 'binaryname': 1.804 + if value is None: 1.805 + raise IDLError("binaryname attribute requires a value", 1.806 + aloc) 1.807 + 1.808 + self.binaryname = value 1.809 + continue 1.810 + 1.811 + if value is not None: 1.812 + raise IDLError("Unexpected attribute value", aloc) 1.813 + 1.814 + if name == 'noscript': 1.815 + self.noscript = True 1.816 + elif name == 'notxpcom': 1.817 + self.notxpcom = True 1.818 + elif name == 'implicit_jscontext': 1.819 + self.implicit_jscontext = True 1.820 + elif name == 'optional_argc': 1.821 + self.optional_argc = True 1.822 + elif name == 'deprecated': 1.823 + self.deprecated = True 1.824 + elif name == 'nostdcall': 1.825 + self.nostdcall = True 1.826 + else: 1.827 + raise IDLError("Unexpected attribute '%s'" % name, aloc) 1.828 + 1.829 + self.namemap = NameMap() 1.830 + for p in paramlist: 1.831 + self.namemap.set(p) 1.832 + 1.833 + def resolve(self, iface): 1.834 + self.iface = iface 1.835 + self.realtype = self.iface.idl.getName(self.type, self.location) 1.836 + for p in self.params: 1.837 + p.resolve(self) 1.838 + for p in self.params: 1.839 + if p.retval and p != self.params[-1]: 1.840 + raise IDLError("'retval' parameter '%s' is not the last parameter" % p.name, self.location) 1.841 + if p.size_is: 1.842 + found_size_param = False 1.843 + for size_param in self.params: 1.844 + if p.size_is == size_param.name: 1.845 + found_size_param = True 1.846 + if getBuiltinOrNativeTypeName(size_param.realtype) != 'unsigned long': 1.847 + raise IDLError("is_size parameter must have type 'unsigned long'", self.location) 1.848 + if not found_size_param: 1.849 + raise IDLError("could not find is_size parameter '%s'" % p.size_is, self.location) 1.850 + 1.851 + def isScriptable(self): 1.852 + if not self.iface.attributes.scriptable: return False 1.853 + return not (self.noscript or self.notxpcom) 1.854 + 1.855 + def __str__(self): 1.856 + return "\t%s %s(%s)\n" % (self.type, self.name, ", ".join([p.name for p in self.params])) 1.857 + 1.858 + def toIDL(self): 1.859 + if len(self.raises): 1.860 + raises = ' raises (%s)' % ','.join(self.raises) 1.861 + else: 1.862 + raises = '' 1.863 + 1.864 + return "%s%s %s (%s)%s;" % (attlistToIDL(self.attlist), 1.865 + self.type, 1.866 + self.name, 1.867 + ", ".join([p.toIDL() 1.868 + for p in self.params]), 1.869 + raises) 1.870 + 1.871 + def needsJSTypes(self): 1.872 + if self.implicit_jscontext: 1.873 + return True 1.874 + if self.type == "jsval": 1.875 + return True 1.876 + for p in self.params: 1.877 + t = p.realtype 1.878 + if isinstance(t, Native) and t.specialtype == "jsval": 1.879 + return True 1.880 + return False 1.881 + 1.882 + def count(self): 1.883 + return 1 1.884 + 1.885 +class Param(object): 1.886 + size_is = None 1.887 + iid_is = None 1.888 + const = False 1.889 + array = False 1.890 + retval = False 1.891 + shared = False 1.892 + optional = False 1.893 + null = None 1.894 + undefined = None 1.895 + 1.896 + def __init__(self, paramtype, type, name, attlist, location, realtype=None): 1.897 + self.paramtype = paramtype 1.898 + self.type = type 1.899 + self.name = name 1.900 + self.attlist = attlist 1.901 + self.location = location 1.902 + self.realtype = realtype 1.903 + 1.904 + for name, value, aloc in attlist: 1.905 + # Put the value-taking attributes first! 1.906 + if name == 'size_is': 1.907 + if value is None: 1.908 + raise IDLError("'size_is' must specify a parameter", aloc) 1.909 + self.size_is = value 1.910 + elif name == 'iid_is': 1.911 + if value is None: 1.912 + raise IDLError("'iid_is' must specify a parameter", aloc) 1.913 + self.iid_is = value 1.914 + elif name == 'Null': 1.915 + if value is None: 1.916 + raise IDLError("'Null' must specify a parameter", aloc) 1.917 + if value not in ('Empty', 'Null', 'Stringify'): 1.918 + raise IDLError("'Null' parameter value must be 'Empty', 'Null', or 'Stringify'", 1.919 + aloc); 1.920 + self.null = value 1.921 + elif name == 'Undefined': 1.922 + if value is None: 1.923 + raise IDLError("'Undefined' must specify a parameter", aloc) 1.924 + if value not in ('Empty', 'Null'): 1.925 + raise IDLError("'Undefined' parameter value must be 'Empty' or 'Null'", 1.926 + aloc); 1.927 + self.undefined = value 1.928 + else: 1.929 + if value is not None: 1.930 + raise IDLError("Unexpected value for attribute '%s'" % name, 1.931 + aloc) 1.932 + 1.933 + if name == 'const': 1.934 + self.const = True 1.935 + elif name == 'array': 1.936 + self.array = True 1.937 + elif name == 'retval': 1.938 + self.retval = True 1.939 + elif name == 'shared': 1.940 + self.shared = True 1.941 + elif name == 'optional': 1.942 + self.optional = True 1.943 + else: 1.944 + raise IDLError("Unexpected attribute '%s'" % name, aloc) 1.945 + 1.946 + def resolve(self, method): 1.947 + self.realtype = method.iface.idl.getName(self.type, self.location) 1.948 + if self.array: 1.949 + self.realtype = Array(self.realtype) 1.950 + if (self.null is not None and 1.951 + getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'): 1.952 + raise IDLError("'Null' attribute can only be used on DOMString", 1.953 + self.location) 1.954 + if (self.undefined is not None and 1.955 + getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'): 1.956 + raise IDLError("'Undefined' attribute can only be used on DOMString", 1.957 + self.location) 1.958 + 1.959 + def nativeType(self): 1.960 + kwargs = {} 1.961 + if self.shared: kwargs['shared'] = True 1.962 + if self.const: kwargs['const'] = True 1.963 + 1.964 + try: 1.965 + return self.realtype.nativeType(self.paramtype, **kwargs) 1.966 + except IDLError, e: 1.967 + raise IDLError(e.message, self.location) 1.968 + except TypeError, e: 1.969 + raise IDLError("Unexpected parameter attribute", self.location) 1.970 + 1.971 + def toIDL(self): 1.972 + return "%s%s %s %s" % (paramAttlistToIDL(self.attlist), 1.973 + self.paramtype, 1.974 + self.type, 1.975 + self.name) 1.976 + 1.977 +class Array(object): 1.978 + def __init__(self, basetype): 1.979 + self.type = basetype 1.980 + 1.981 + def isScriptable(self): 1.982 + return self.type.isScriptable() 1.983 + 1.984 + def nativeType(self, calltype, const=False): 1.985 + return "%s%s*" % (const and 'const ' or '', 1.986 + self.type.nativeType(calltype)) 1.987 + 1.988 +class IDLParser(object): 1.989 + keywords = { 1.990 + 'const': 'CONST', 1.991 + 'interface': 'INTERFACE', 1.992 + 'in': 'IN', 1.993 + 'inout': 'INOUT', 1.994 + 'out': 'OUT', 1.995 + 'attribute': 'ATTRIBUTE', 1.996 + 'raises': 'RAISES', 1.997 + 'readonly': 'READONLY', 1.998 + 'native': 'NATIVE', 1.999 + 'typedef': 'TYPEDEF', 1.1000 + 'Infinity': 'INFINITY' 1.1001 + } 1.1002 + 1.1003 + tokens = [ 1.1004 + 'IDENTIFIER', 1.1005 + 'CDATA', 1.1006 + 'INCLUDE', 1.1007 + 'IID', 1.1008 + 'NUMBER', 1.1009 + 'HEXNUM', 1.1010 + 'LSHIFT', 1.1011 + 'RSHIFT', 1.1012 + 'NATIVEID', 1.1013 + ] 1.1014 + 1.1015 + tokens.extend(keywords.values()) 1.1016 + 1.1017 + states = ( 1.1018 + ('nativeid', 'exclusive'), 1.1019 + ) 1.1020 + 1.1021 + hexchar = r'[a-fA-F0-9]' 1.1022 + 1.1023 + t_NUMBER = r'-?\d+' 1.1024 + t_HEXNUM = r'0x%s+' % hexchar 1.1025 + t_LSHIFT = r'<<' 1.1026 + t_RSHIFT= r'>>' 1.1027 + 1.1028 + literals = '"(){}[],;:=|+-*' 1.1029 + 1.1030 + t_ignore = ' \t' 1.1031 + 1.1032 + def t_multilinecomment(self, t): 1.1033 + r'/\*(?s).*?\*/' 1.1034 + t.lexer.lineno += t.value.count('\n') 1.1035 + if t.value.startswith("/**"): 1.1036 + self._doccomments.append(t.value) 1.1037 + 1.1038 + def t_singlelinecomment(self, t): 1.1039 + r'(?m)//.*?$' 1.1040 + 1.1041 + def t_IID(self, t): 1.1042 + return t 1.1043 + t_IID.__doc__ = r'%(c)s{8}-%(c)s{4}-%(c)s{4}-%(c)s{4}-%(c)s{12}' % {'c': hexchar} 1.1044 + 1.1045 + def t_IDENTIFIER(self, t): 1.1046 + r'(unsigned\ long\ long|unsigned\ short|unsigned\ long|long\ long)(?!_?[A-Za-z][A-Za-z_0-9])|_?[A-Za-z][A-Za-z_0-9]*' 1.1047 + t.type = self.keywords.get(t.value, 'IDENTIFIER') 1.1048 + return t 1.1049 + 1.1050 + def t_LCDATA(self, t): 1.1051 + r'(?s)%\{[ ]*C\+\+[ ]*\n(?P<cdata>.*?\n?)%\}[ ]*(C\+\+)?' 1.1052 + t.type = 'CDATA' 1.1053 + t.value = t.lexer.lexmatch.group('cdata') 1.1054 + t.lexer.lineno += t.value.count('\n') 1.1055 + return t 1.1056 + 1.1057 + def t_INCLUDE(self, t): 1.1058 + r'\#include[ \t]+"[^"\n]+"' 1.1059 + inc, value, end = t.value.split('"') 1.1060 + t.value = value 1.1061 + return t 1.1062 + 1.1063 + def t_directive(self, t): 1.1064 + r'\#(?P<directive>[a-zA-Z]+)[^\n]+' 1.1065 + raise IDLError("Unrecognized directive %s" % t.lexer.lexmatch.group('directive'), 1.1066 + Location(lexer=self.lexer, lineno=self.lexer.lineno, 1.1067 + lexpos=self.lexer.lexpos)) 1.1068 + 1.1069 + def t_newline(self, t): 1.1070 + r'\n+' 1.1071 + t.lexer.lineno += len(t.value) 1.1072 + 1.1073 + def t_nativeid_NATIVEID(self, t): 1.1074 + r'[^()\n]+(?=\))' 1.1075 + t.lexer.begin('INITIAL') 1.1076 + return t 1.1077 + 1.1078 + t_nativeid_ignore = '' 1.1079 + 1.1080 + def t_ANY_error(self, t): 1.1081 + raise IDLError("unrecognized input", 1.1082 + Location(lexer=self.lexer, 1.1083 + lineno=self.lexer.lineno, 1.1084 + lexpos=self.lexer.lexpos)) 1.1085 + 1.1086 + precedence = ( 1.1087 + ('left', '|'), 1.1088 + ('left', 'LSHIFT', 'RSHIFT'), 1.1089 + ('left', '+', '-'), 1.1090 + ('left', '*'), 1.1091 + ('left', 'UMINUS'), 1.1092 + ) 1.1093 + 1.1094 + def p_idlfile(self, p): 1.1095 + """idlfile : productions""" 1.1096 + p[0] = IDL(p[1]) 1.1097 + 1.1098 + def p_productions_start(self, p): 1.1099 + """productions : """ 1.1100 + p[0] = [] 1.1101 + 1.1102 + def p_productions_cdata(self, p): 1.1103 + """productions : CDATA productions""" 1.1104 + p[0] = list(p[2]) 1.1105 + p[0].insert(0, CDATA(p[1], self.getLocation(p, 1))) 1.1106 + 1.1107 + def p_productions_include(self, p): 1.1108 + """productions : INCLUDE productions""" 1.1109 + p[0] = list(p[2]) 1.1110 + p[0].insert(0, Include(p[1], self.getLocation(p, 1))) 1.1111 + 1.1112 + def p_productions_interface(self, p): 1.1113 + """productions : interface productions 1.1114 + | typedef productions 1.1115 + | native productions""" 1.1116 + p[0] = list(p[2]) 1.1117 + p[0].insert(0, p[1]) 1.1118 + 1.1119 + def p_typedef(self, p): 1.1120 + """typedef : TYPEDEF IDENTIFIER IDENTIFIER ';'""" 1.1121 + p[0] = Typedef(type=p[2], 1.1122 + name=p[3], 1.1123 + location=self.getLocation(p, 1), 1.1124 + doccomments=p.slice[1].doccomments) 1.1125 + 1.1126 + def p_native(self, p): 1.1127 + """native : attributes NATIVE IDENTIFIER afternativeid '(' NATIVEID ')' ';'""" 1.1128 + p[0] = Native(name=p[3], 1.1129 + nativename=p[6], 1.1130 + attlist=p[1]['attlist'], 1.1131 + location=self.getLocation(p, 2)) 1.1132 + 1.1133 + def p_afternativeid(self, p): 1.1134 + """afternativeid : """ 1.1135 + # this is a place marker: we switch the lexer into literal identifier 1.1136 + # mode here, to slurp up everything until the closeparen 1.1137 + self.lexer.begin('nativeid') 1.1138 + 1.1139 + def p_anyident(self, p): 1.1140 + """anyident : IDENTIFIER 1.1141 + | CONST""" 1.1142 + p[0] = {'value': p[1], 1.1143 + 'location': self.getLocation(p, 1)} 1.1144 + 1.1145 + def p_attributes(self, p): 1.1146 + """attributes : '[' attlist ']' 1.1147 + | """ 1.1148 + if len(p) == 1: 1.1149 + p[0] = {'attlist': []} 1.1150 + else: 1.1151 + p[0] = {'attlist': p[2], 1.1152 + 'doccomments': p.slice[1].doccomments} 1.1153 + 1.1154 + def p_attlist_start(self, p): 1.1155 + """attlist : attribute""" 1.1156 + p[0] = [p[1]] 1.1157 + 1.1158 + def p_attlist_continue(self, p): 1.1159 + """attlist : attribute ',' attlist""" 1.1160 + p[0] = list(p[3]) 1.1161 + p[0].insert(0, p[1]) 1.1162 + 1.1163 + def p_attribute(self, p): 1.1164 + """attribute : anyident attributeval""" 1.1165 + p[0] = (p[1]['value'], p[2], p[1]['location']) 1.1166 + 1.1167 + def p_attributeval(self, p): 1.1168 + """attributeval : '(' IDENTIFIER ')' 1.1169 + | '(' IID ')' 1.1170 + | """ 1.1171 + if len(p) > 1: 1.1172 + p[0] = p[2] 1.1173 + 1.1174 + def p_interface(self, p): 1.1175 + """interface : attributes INTERFACE IDENTIFIER ifacebase ifacebody ';'""" 1.1176 + atts, INTERFACE, name, base, body, SEMI = p[1:] 1.1177 + attlist = atts['attlist'] 1.1178 + doccomments = [] 1.1179 + if 'doccomments' in atts: 1.1180 + doccomments.extend(atts['doccomments']) 1.1181 + doccomments.extend(p.slice[2].doccomments) 1.1182 + 1.1183 + l = lambda: self.getLocation(p, 2) 1.1184 + 1.1185 + if body is None: 1.1186 + # forward-declared interface... must not have attributes! 1.1187 + if len(attlist) != 0: 1.1188 + raise IDLError("Forward-declared interface must not have attributes", 1.1189 + list[0][3]) 1.1190 + 1.1191 + if base is not None: 1.1192 + raise IDLError("Forward-declared interface must not have a base", 1.1193 + l()) 1.1194 + p[0] = Forward(name=name, location=l(), doccomments=doccomments) 1.1195 + else: 1.1196 + p[0] = Interface(name=name, 1.1197 + attlist=attlist, 1.1198 + base=base, 1.1199 + members=body, 1.1200 + location=l(), 1.1201 + doccomments=doccomments) 1.1202 + 1.1203 + def p_ifacebody(self, p): 1.1204 + """ifacebody : '{' members '}' 1.1205 + | """ 1.1206 + if len(p) > 1: 1.1207 + p[0] = p[2] 1.1208 + 1.1209 + def p_ifacebase(self, p): 1.1210 + """ifacebase : ':' IDENTIFIER 1.1211 + | """ 1.1212 + if len(p) == 3: 1.1213 + p[0] = p[2] 1.1214 + 1.1215 + def p_members_start(self, p): 1.1216 + """members : """ 1.1217 + p[0] = [] 1.1218 + 1.1219 + def p_members_continue(self, p): 1.1220 + """members : member members""" 1.1221 + p[0] = list(p[2]) 1.1222 + p[0].insert(0, p[1]) 1.1223 + 1.1224 + def p_member_cdata(self, p): 1.1225 + """member : CDATA""" 1.1226 + p[0] = CDATA(p[1], self.getLocation(p, 1)) 1.1227 + 1.1228 + def p_member_const(self, p): 1.1229 + """member : CONST IDENTIFIER IDENTIFIER '=' number ';' """ 1.1230 + p[0] = ConstMember(type=p[2], name=p[3], 1.1231 + value=p[5], location=self.getLocation(p, 1), 1.1232 + doccomments=p.slice[1].doccomments) 1.1233 + 1.1234 +# All "number" products return a function(interface) 1.1235 + 1.1236 + def p_number_decimal(self, p): 1.1237 + """number : NUMBER""" 1.1238 + n = int(p[1]) 1.1239 + p[0] = lambda i: n 1.1240 + 1.1241 + def p_number_hex(self, p): 1.1242 + """number : HEXNUM""" 1.1243 + n = int(p[1], 16) 1.1244 + p[0] = lambda i: n 1.1245 + 1.1246 + def p_number_identifier(self, p): 1.1247 + """number : IDENTIFIER""" 1.1248 + id = p[1] 1.1249 + loc = self.getLocation(p, 1) 1.1250 + p[0] = lambda i: i.getConst(id, loc) 1.1251 + 1.1252 + def p_number_paren(self, p): 1.1253 + """number : '(' number ')'""" 1.1254 + p[0] = p[2] 1.1255 + 1.1256 + def p_number_neg(self, p): 1.1257 + """number : '-' number %prec UMINUS""" 1.1258 + n = p[2] 1.1259 + p[0] = lambda i: - n(i) 1.1260 + 1.1261 + def p_number_add(self, p): 1.1262 + """number : number '+' number 1.1263 + | number '-' number 1.1264 + | number '*' number""" 1.1265 + n1 = p[1] 1.1266 + n2 = p[3] 1.1267 + if p[2] == '+': 1.1268 + p[0] = lambda i: n1(i) + n2(i) 1.1269 + elif p[2] == '-': 1.1270 + p[0] = lambda i: n1(i) - n2(i) 1.1271 + else: 1.1272 + p[0] = lambda i: n1(i) * n2(i) 1.1273 + 1.1274 + def p_number_shift(self, p): 1.1275 + """number : number LSHIFT number 1.1276 + | number RSHIFT number""" 1.1277 + n1 = p[1] 1.1278 + n2 = p[3] 1.1279 + if p[2] == '<<': 1.1280 + p[0] = lambda i: n1(i) << n2(i) 1.1281 + else: 1.1282 + p[0] = lambda i: n1(i) >> n2(i) 1.1283 + 1.1284 + def p_number_bitor(self, p): 1.1285 + """number : number '|' number""" 1.1286 + n1 = p[1] 1.1287 + n2 = p[3] 1.1288 + p[0] = lambda i: n1(i) | n2(i) 1.1289 + 1.1290 + def p_member_att(self, p): 1.1291 + """member : attributes optreadonly ATTRIBUTE IDENTIFIER IDENTIFIER ';'""" 1.1292 + if 'doccomments' in p[1]: 1.1293 + doccomments = p[1]['doccomments'] 1.1294 + elif p[2] is not None: 1.1295 + doccomments = p[2] 1.1296 + else: 1.1297 + doccomments = p.slice[3].doccomments 1.1298 + 1.1299 + p[0] = Attribute(type=p[4], 1.1300 + name=p[5], 1.1301 + attlist=p[1]['attlist'], 1.1302 + readonly=p[2] is not None, 1.1303 + location=self.getLocation(p, 3), 1.1304 + doccomments=doccomments) 1.1305 + 1.1306 + def p_member_method(self, p): 1.1307 + """member : attributes IDENTIFIER IDENTIFIER '(' paramlist ')' raises ';'""" 1.1308 + if 'doccomments' in p[1]: 1.1309 + doccomments = p[1]['doccomments'] 1.1310 + else: 1.1311 + doccomments = p.slice[2].doccomments 1.1312 + 1.1313 + p[0] = Method(type=p[2], 1.1314 + name=p[3], 1.1315 + attlist=p[1]['attlist'], 1.1316 + paramlist=p[5], 1.1317 + location=self.getLocation(p, 3), 1.1318 + doccomments=doccomments, 1.1319 + raises=p[7]) 1.1320 + 1.1321 + def p_paramlist(self, p): 1.1322 + """paramlist : param moreparams 1.1323 + | """ 1.1324 + if len(p) == 1: 1.1325 + p[0] = [] 1.1326 + else: 1.1327 + p[0] = list(p[2]) 1.1328 + p[0].insert(0, p[1]) 1.1329 + 1.1330 + def p_moreparams_start(self, p): 1.1331 + """moreparams :""" 1.1332 + p[0] = [] 1.1333 + 1.1334 + def p_moreparams_continue(self, p): 1.1335 + """moreparams : ',' param moreparams""" 1.1336 + p[0] = list(p[3]) 1.1337 + p[0].insert(0, p[2]) 1.1338 + 1.1339 + def p_param(self, p): 1.1340 + """param : attributes paramtype IDENTIFIER IDENTIFIER""" 1.1341 + p[0] = Param(paramtype=p[2], 1.1342 + type=p[3], 1.1343 + name=p[4], 1.1344 + attlist=p[1]['attlist'], 1.1345 + location=self.getLocation(p, 3)) 1.1346 + 1.1347 + def p_paramtype(self, p): 1.1348 + """paramtype : IN 1.1349 + | INOUT 1.1350 + | OUT""" 1.1351 + p[0] = p[1] 1.1352 + 1.1353 + def p_optreadonly(self, p): 1.1354 + """optreadonly : READONLY 1.1355 + | """ 1.1356 + if len(p) > 1: 1.1357 + p[0] = p.slice[1].doccomments 1.1358 + else: 1.1359 + p[0] = None 1.1360 + 1.1361 + def p_raises(self, p): 1.1362 + """raises : RAISES '(' idlist ')' 1.1363 + | """ 1.1364 + if len(p) == 1: 1.1365 + p[0] = [] 1.1366 + else: 1.1367 + p[0] = p[3] 1.1368 + 1.1369 + def p_idlist(self, p): 1.1370 + """idlist : IDENTIFIER""" 1.1371 + p[0] = [p[1]] 1.1372 + 1.1373 + def p_idlist_continue(self, p): 1.1374 + """idlist : IDENTIFIER ',' idlist""" 1.1375 + p[0] = list(p[3]) 1.1376 + p[0].insert(0, p[1]) 1.1377 + 1.1378 + def p_error(self, t): 1.1379 + if not t: 1.1380 + raise IDLError("Syntax Error at end of file. Possibly due to missing semicolon(;), braces(}) or both", None) 1.1381 + else: 1.1382 + location = Location(self.lexer, t.lineno, t.lexpos) 1.1383 + raise IDLError("invalid syntax", location) 1.1384 + 1.1385 + def __init__(self, outputdir=''): 1.1386 + self._doccomments = [] 1.1387 + self.lexer = lex.lex(object=self, 1.1388 + outputdir=outputdir, 1.1389 + lextab='xpidllex', 1.1390 + optimize=1) 1.1391 + self.parser = yacc.yacc(module=self, 1.1392 + outputdir=outputdir, 1.1393 + debug=0, 1.1394 + tabmodule='xpidlyacc', 1.1395 + optimize=1) 1.1396 + 1.1397 + def clearComments(self): 1.1398 + self._doccomments = [] 1.1399 + 1.1400 + def token(self): 1.1401 + t = self.lexer.token() 1.1402 + if t is not None and t.type != 'CDATA': 1.1403 + t.doccomments = self._doccomments 1.1404 + self._doccomments = [] 1.1405 + return t 1.1406 + 1.1407 + def parse(self, data, filename=None): 1.1408 + if filename is not None: 1.1409 + self.lexer.filename = filename 1.1410 + self.lexer.lineno = 1 1.1411 + self.lexer.input(data) 1.1412 + idl = self.parser.parse(lexer=self) 1.1413 + if filename is not None: 1.1414 + idl.deps.append(filename) 1.1415 + return idl 1.1416 + 1.1417 + def getLocation(self, p, i): 1.1418 + return Location(self.lexer, p.lineno(i), p.lexpos(i)) 1.1419 + 1.1420 +if __name__ == '__main__': 1.1421 + p = IDLParser() 1.1422 + for f in sys.argv[1:]: 1.1423 + print "Parsing %s" % f 1.1424 + p.parse(open(f).read(), filename=f)