1# This Source Code Form is subject to the terms of the Mozilla Public 2# License, v. 2.0. If a copy of the MPL was not distributed with this 3# file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 5import sys 6 7NOT_NESTED = 1 8INSIDE_SYNC_NESTED = 2 9INSIDE_CPOW_NESTED = 3 10 11NORMAL_PRIORITY = 1 12HIGH_PRIORITY = 2 13 14class Visitor: 15 def defaultVisit(self, node): 16 raise Exception, "INTERNAL ERROR: no visitor for node type `%s'"% ( 17 node.__class__.__name__) 18 19 def visitTranslationUnit(self, tu): 20 for cxxInc in tu.cxxIncludes: 21 cxxInc.accept(self) 22 for inc in tu.includes: 23 inc.accept(self) 24 for su in tu.structsAndUnions: 25 su.accept(self) 26 for using in tu.builtinUsing: 27 using.accept(self) 28 for using in tu.using: 29 using.accept(self) 30 if tu.protocol: 31 tu.protocol.accept(self) 32 33 34 def visitCxxInclude(self, inc): 35 pass 36 37 def visitInclude(self, inc): 38 # Note: we don't visit the child AST here, because that needs delicate 39 # and pass-specific handling 40 pass 41 42 def visitStructDecl(self, struct): 43 for f in struct.fields: 44 f.accept(self) 45 46 def visitStructField(self, field): 47 field.typespec.accept(self) 48 49 def visitUnionDecl(self, union): 50 for t in union.components: 51 t.accept(self) 52 53 def visitUsingStmt(self, using): 54 pass 55 56 def visitProtocol(self, p): 57 for namespace in p.namespaces: 58 namespace.accept(self) 59 for spawns in p.spawnsStmts: 60 spawns.accept(self) 61 for bridges in p.bridgesStmts: 62 bridges.accept(self) 63 for opens in p.opensStmts: 64 opens.accept(self) 65 for mgr in p.managers: 66 mgr.accept(self) 67 for managed in p.managesStmts: 68 managed.accept(self) 69 for msgDecl in p.messageDecls: 70 msgDecl.accept(self) 71 for transitionStmt in p.transitionStmts: 72 transitionStmt.accept(self) 73 74 def visitNamespace(self, ns): 75 pass 76 77 def visitSpawnsStmt(self, spawns): 78 pass 79 80 def visitBridgesStmt(self, bridges): 81 pass 82 83 def visitOpensStmt(self, opens): 84 pass 85 86 def visitManager(self, mgr): 87 pass 88 89 def visitManagesStmt(self, mgs): 90 pass 91 92 def visitMessageDecl(self, md): 93 for inParam in md.inParams: 94 inParam.accept(self) 95 for outParam in md.outParams: 96 outParam.accept(self) 97 98 def visitTransitionStmt(self, ts): 99 ts.state.accept(self) 100 for trans in ts.transitions: 101 trans.accept(self) 102 103 def visitTransition(self, t): 104 for toState in t.toStates: 105 toState.accept(self) 106 107 def visitState(self, s): 108 pass 109 110 def visitParam(self, decl): 111 pass 112 113 def visitTypeSpec(self, ts): 114 pass 115 116 def visitDecl(self, d): 117 pass 118 119class Loc: 120 def __init__(self, filename='<??>', lineno=0): 121 assert filename 122 self.filename = filename 123 self.lineno = lineno 124 def __repr__(self): 125 return '%r:%r'% (self.filename, self.lineno) 126 def __str__(self): 127 return '%s:%s'% (self.filename, self.lineno) 128 129Loc.NONE = Loc(filename='<??>', lineno=0) 130 131class _struct: 132 pass 133 134class Node: 135 def __init__(self, loc=Loc.NONE): 136 self.loc = loc 137 138 def accept(self, visitor): 139 visit = getattr(visitor, 'visit'+ self.__class__.__name__, None) 140 if visit is None: 141 return getattr(visitor, 'defaultVisit')(self) 142 return visit(self) 143 144 def addAttrs(self, attrsName): 145 if not hasattr(self, attrsName): 146 setattr(self, attrsName, _struct()) 147 148 149class NamespacedNode(Node): 150 def __init__(self, loc=Loc.NONE, name=None): 151 Node.__init__(self, loc) 152 self.name = name 153 self.namespaces = [ ] 154 155 def addOuterNamespace(self, namespace): 156 self.namespaces.insert(0, namespace) 157 158 def qname(self): 159 return QualifiedId(self.loc, self.name, 160 [ ns.name for ns in self.namespaces ]) 161 162class TranslationUnit(NamespacedNode): 163 def __init__(self, type, name): 164 NamespacedNode.__init__(self, name=name) 165 self.filetype = type 166 self.filename = None 167 self.cxxIncludes = [ ] 168 self.includes = [ ] 169 self.builtinUsing = [ ] 170 self.using = [ ] 171 self.structsAndUnions = [ ] 172 self.protocol = None 173 174 def addCxxInclude(self, cxxInclude): self.cxxIncludes.append(cxxInclude) 175 def addInclude(self, inc): self.includes.append(inc) 176 def addStructDecl(self, struct): self.structsAndUnions.append(struct) 177 def addUnionDecl(self, union): self.structsAndUnions.append(union) 178 def addUsingStmt(self, using): self.using.append(using) 179 180 def setProtocol(self, protocol): self.protocol = protocol 181 182class CxxInclude(Node): 183 def __init__(self, loc, cxxFile): 184 Node.__init__(self, loc) 185 self.file = cxxFile 186 187class Include(Node): 188 def __init__(self, loc, type, name): 189 Node.__init__(self, loc) 190 suffix = 'ipdl' 191 if type == 'header': 192 suffix += 'h' 193 self.file = "%s.%s" % (name, suffix) 194 195class UsingStmt(Node): 196 def __init__(self, loc, cxxTypeSpec, cxxHeader=None, kind=None): 197 Node.__init__(self, loc) 198 assert not isinstance(cxxTypeSpec, str) 199 assert cxxHeader is None or isinstance(cxxHeader, str); 200 assert kind is None or kind == 'class' or kind == 'struct' 201 self.type = cxxTypeSpec 202 self.header = cxxHeader 203 self.kind = kind 204 def canBeForwardDeclared(self): 205 return self.isClass() or self.isStruct() 206 def isClass(self): 207 return self.kind == 'class' 208 def isStruct(self): 209 return self.kind == 'struct' 210 211# "singletons" 212class PrettyPrinted: 213 @classmethod 214 def __hash__(cls): return hash(cls.pretty) 215 @classmethod 216 def __str__(cls): return cls.pretty 217 218class ASYNC(PrettyPrinted): 219 pretty = 'async' 220class INTR(PrettyPrinted): 221 pretty = 'intr' 222class SYNC(PrettyPrinted): 223 pretty = 'sync' 224 225class INOUT(PrettyPrinted): 226 pretty = 'inout' 227class IN(PrettyPrinted): 228 pretty = 'in' 229class OUT(PrettyPrinted): 230 pretty = 'out' 231 232 233class Namespace(Node): 234 def __init__(self, loc, namespace): 235 Node.__init__(self, loc) 236 self.name = namespace 237 238class Protocol(NamespacedNode): 239 def __init__(self, loc): 240 NamespacedNode.__init__(self, loc) 241 self.sendSemantics = ASYNC 242 self.nested = NOT_NESTED 243 self.spawnsStmts = [ ] 244 self.bridgesStmts = [ ] 245 self.opensStmts = [ ] 246 self.managers = [ ] 247 self.managesStmts = [ ] 248 self.messageDecls = [ ] 249 self.transitionStmts = [ ] 250 self.startStates = [ ] 251 252class StructField(Node): 253 def __init__(self, loc, type, name): 254 Node.__init__(self, loc) 255 self.typespec = type 256 self.name = name 257 258class StructDecl(NamespacedNode): 259 def __init__(self, loc, name, fields): 260 NamespacedNode.__init__(self, loc, name) 261 self.fields = fields 262 263class UnionDecl(NamespacedNode): 264 def __init__(self, loc, name, components): 265 NamespacedNode.__init__(self, loc, name) 266 self.components = components 267 268class SpawnsStmt(Node): 269 def __init__(self, loc, side, proto, spawnedAs): 270 Node.__init__(self, loc) 271 self.side = side 272 self.proto = proto 273 self.spawnedAs = spawnedAs 274 275class BridgesStmt(Node): 276 def __init__(self, loc, parentSide, childSide): 277 Node.__init__(self, loc) 278 self.parentSide = parentSide 279 self.childSide = childSide 280 281class OpensStmt(Node): 282 def __init__(self, loc, side, proto): 283 Node.__init__(self, loc) 284 self.side = side 285 self.proto = proto 286 287class Manager(Node): 288 def __init__(self, loc, managerName): 289 Node.__init__(self, loc) 290 self.name = managerName 291 292class ManagesStmt(Node): 293 def __init__(self, loc, managedName): 294 Node.__init__(self, loc) 295 self.name = managedName 296 297class MessageDecl(Node): 298 def __init__(self, loc): 299 Node.__init__(self, loc) 300 self.name = None 301 self.sendSemantics = ASYNC 302 self.nested = NOT_NESTED 303 self.prio = NORMAL_PRIORITY 304 self.direction = None 305 self.inParams = [ ] 306 self.outParams = [ ] 307 self.compress = '' 308 self.verify = '' 309 310 def addInParams(self, inParamsList): 311 self.inParams += inParamsList 312 313 def addOutParams(self, outParamsList): 314 self.outParams += outParamsList 315 316 def addModifiers(self, modifiers): 317 for modifier in modifiers: 318 if modifier.startswith('compress'): 319 self.compress = modifier 320 elif modifier == 'verify': 321 self.verify = modifier 322 elif modifier != '': 323 raise Exception, "Unexpected message modifier `%s'"% modifier 324 325class Transition(Node): 326 def __init__(self, loc, trigger, msg, toStates): 327 Node.__init__(self, loc) 328 self.trigger = trigger 329 self.msg = msg 330 self.toStates = toStates 331 332 def __cmp__(self, o): 333 c = cmp(self.msg, o.msg) 334 if c: return c 335 c = cmp(self.trigger, o.trigger) 336 if c: return c 337 338 def __hash__(self): return hash(str(self)) 339 def __str__(self): return '%s %s'% (self.trigger, self.msg) 340 341 @staticmethod 342 def nameToTrigger(name): 343 return { 'send': SEND, 'recv': RECV, 'call': CALL, 'answer': ANSWER }[name] 344 345Transition.NULL = Transition(Loc.NONE, None, None, [ ]) 346 347class TransitionStmt(Node): 348 def __init__(self, loc, state, transitions): 349 Node.__init__(self, loc) 350 self.state = state 351 self.transitions = transitions 352 353 @staticmethod 354 def makeNullStmt(state): 355 return TransitionStmt(Loc.NONE, state, [ Transition.NULL ]) 356 357class SEND: 358 pretty = 'send' 359 @classmethod 360 def __hash__(cls): return hash(cls.pretty) 361 @classmethod 362 def direction(cls): return OUT 363class RECV: 364 pretty = 'recv' 365 @classmethod 366 def __hash__(cls): return hash(cls.pretty) 367 @classmethod 368 def direction(cls): return IN 369class CALL: 370 pretty = 'call' 371 @classmethod 372 def __hash__(cls): return hash(cls.pretty) 373 @classmethod 374 def direction(cls): return OUT 375class ANSWER: 376 pretty = 'answer' 377 @classmethod 378 def __hash__(cls): return hash(cls.pretty) 379 @classmethod 380 def direction(cls): return IN 381 382class State(Node): 383 def __init__(self, loc, name, start=False): 384 Node.__init__(self, loc) 385 self.name = name 386 self.start = start 387 def __eq__(self, o): 388 return (isinstance(o, State) 389 and o.name == self.name 390 and o.start == self.start) 391 def __hash__(self): 392 return hash(repr(self)) 393 def __ne__(self, o): 394 return not (self == o) 395 def __repr__(self): return '<State %r start=%r>'% (self.name, self.start) 396 def __str__(self): return '<State %s start=%s>'% (self.name, self.start) 397 398State.ANY = State(Loc.NONE, '[any]', start=True) 399State.DEAD = State(Loc.NONE, '[dead]', start=False) 400State.DYING = State(Loc.NONE, '[dying]', start=False) 401 402class Param(Node): 403 def __init__(self, loc, typespec, name): 404 Node.__init__(self, loc) 405 self.name = name 406 self.typespec = typespec 407 408class TypeSpec(Node): 409 def __init__(self, loc, spec, state=None, array=0, nullable=0, 410 myChmod=None, otherChmod=None): 411 Node.__init__(self, loc) 412 self.spec = spec # QualifiedId 413 self.state = state # None or State 414 self.array = array # bool 415 self.nullable = nullable # bool 416 self.myChmod = myChmod # None or string 417 self.otherChmod = otherChmod # None or string 418 419 def basename(self): 420 return self.spec.baseid 421 422 def isActor(self): 423 return self.state is not None 424 425 def __str__(self): return str(self.spec) 426 427class QualifiedId: # FIXME inherit from node? 428 def __init__(self, loc, baseid, quals=[ ]): 429 assert isinstance(baseid, str) 430 for qual in quals: assert isinstance(qual, str) 431 432 self.loc = loc 433 self.baseid = baseid 434 self.quals = quals 435 436 def qualify(self, id): 437 self.quals.append(self.baseid) 438 self.baseid = id 439 440 def __str__(self): 441 if 0 == len(self.quals): 442 return self.baseid 443 return '::'.join(self.quals) +'::'+ self.baseid 444 445# added by type checking passes 446class Decl(Node): 447 def __init__(self, loc): 448 Node.__init__(self, loc) 449 self.progname = None # what the programmer typed, if relevant 450 self.shortname = None # shortest way to refer to this decl 451 self.fullname = None # full way to refer to this decl 452 self.loc = loc 453 self.type = None 454 self.scope = None 455