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