1# ----------------------------------------------------------------------
2# phpast.py
3#
4# PHP abstract syntax node definitions.
5# ----------------------------------------------------------------------
6
7class Node(object):
8    fields = []
9
10    def __init__(self, *args, **kwargs):
11        assert len(self.fields) == len(args), \
12            '%s takes %d arguments' % (self.__class__.__name__,
13                                       len(self.fields))
14        try:
15            self.lineno = kwargs['lineno']
16        except KeyError:
17            self.lineno = None
18        for i, field in enumerate(self.fields):
19            setattr(self, field, args[i])
20
21    def __repr__(self):
22        return "%s(%s)" % (self.__class__.__name__,
23                           ', '.join([repr(getattr(self, field))
24                                      for field in self.fields]))
25
26    def __eq__(self, other):
27        if not isinstance(other, self.__class__):
28            return False
29        for field in self.fields:
30            if not (getattr(self, field) == getattr(other, field)):
31                return False
32        return True
33
34    def accept(self, visitor):
35        visitor(self)
36        for field in self.fields:
37            value = getattr(self, field)
38            if isinstance(value, Node):
39                value.accept(visitor)
40            elif isinstance(value, list):
41                for item in value:
42                    if isinstance(item, Node):
43                        item.accept(visitor)
44
45    def generic(self, with_lineno=False):
46        values = {}
47        if with_lineno:
48            values['lineno'] = self.lineno
49        for field in self.fields:
50            value = getattr(self, field)
51            if hasattr(value, 'generic'):
52                value = value.generic(with_lineno)
53            elif isinstance(value, list):
54                items = value
55                value = []
56                for item in items:
57                    if hasattr(item, 'generic'):
58                        item = item.generic(with_lineno)
59                    value.append(item)
60            values[field] = value
61        return (self.__class__.__name__, values)
62
63def node(name, fields):
64    attrs = {'fields': fields}
65    return type(name, (Node,), attrs)
66
67InlineHTML = node('InlineHTML', ['data'])
68Block = node('Block', ['nodes'])
69Assignment = node('Assignment', ['node', 'expr', 'is_ref'])
70ListAssignment = node('ListAssignment', ['nodes', 'expr'])
71New = node('New', ['name', 'params'])
72Clone = node('Clone', ['node'])
73Break = node('Break', ['node'])
74Continue = node('Continue', ['node'])
75Return = node('Return', ['node'])
76Yield = node('Yield', ['node'])
77Global = node('Global', ['nodes'])
78Static = node('Static', ['nodes'])
79Echo = node('Echo', ['nodes'])
80Print = node('Print', ['node'])
81Unset = node('Unset', ['nodes'])
82Try = node('Try', ['nodes', 'catches', 'finally'])
83Catch = node('Catch', ['class_', 'var', 'nodes'])
84Finally = node('Finally', ['nodes'])
85Throw = node('Throw', ['node'])
86Declare = node('Declare', ['directives', 'node'])
87Directive = node('Directive', ['name', 'node'])
88Function = node('Function', ['name', 'params', 'nodes', 'is_ref'])
89Method = node('Method', ['name', 'modifiers', 'params', 'nodes', 'is_ref'])
90Closure = node('Closure', ['params', 'vars', 'nodes', 'is_ref'])
91Class = node('Class', ['name', 'type', 'extends', 'implements', 'traits', 'nodes'])
92Trait = node('Trait', ['name', 'traits', 'nodes'])
93ClassConstants = node('ClassConstants', ['nodes'])
94ClassConstant = node('ClassConstant', ['name', 'initial'])
95ClassVariables = node('ClassVariables', ['modifiers', 'nodes'])
96ClassVariable = node('ClassVariable', ['name', 'initial'])
97Interface = node('Interface', ['name', 'extends', 'nodes'])
98AssignOp = node('AssignOp', ['op', 'left', 'right'])
99BinaryOp = node('BinaryOp', ['op', 'left', 'right'])
100UnaryOp = node('UnaryOp', ['op', 'expr'])
101TernaryOp = node('TernaryOp', ['expr', 'iftrue', 'iffalse'])
102PreIncDecOp = node('PreIncDecOp', ['op', 'expr'])
103PostIncDecOp = node('PostIncDecOp', ['op', 'expr'])
104Cast = node('Cast', ['type', 'expr'])
105IsSet = node('IsSet', ['nodes'])
106Empty = node('Empty', ['expr'])
107Eval = node('Eval', ['expr'])
108Include = node('Include', ['expr', 'once'])
109Require = node('Require', ['expr', 'once'])
110Exit = node('Exit', ['expr', 'type'])
111Silence = node('Silence', ['expr'])
112MagicConstant = node('MagicConstant', ['name', 'value'])
113Constant = node('Constant', ['name'])
114Variable = node('Variable', ['name'])
115StaticVariable = node('StaticVariable', ['name', 'initial'])
116LexicalVariable = node('LexicalVariable', ['name', 'is_ref'])
117FormalParameter = node('FormalParameter', ['name', 'default', 'is_ref', 'type'])
118Parameter = node('Parameter', ['node', 'is_ref'])
119FunctionCall = node('FunctionCall', ['name', 'params'])
120Array = node('Array', ['nodes'])
121ArrayElement = node('ArrayElement', ['key', 'value', 'is_ref'])
122ArrayOffset = node('ArrayOffset', ['node', 'expr'])
123StringOffset = node('StringOffset', ['node', 'expr'])
124ObjectProperty = node('ObjectProperty', ['node', 'name'])
125StaticProperty = node('StaticProperty', ['node', 'name'])
126MethodCall = node('MethodCall', ['node', 'name', 'params'])
127StaticMethodCall = node('StaticMethodCall', ['class_', 'name', 'params'])
128If = node('If', ['expr', 'node', 'elseifs', 'else_'])
129ElseIf = node('ElseIf', ['expr', 'node'])
130Else = node('Else', ['node'])
131While = node('While', ['expr', 'node'])
132DoWhile = node('DoWhile', ['node', 'expr'])
133For = node('For', ['start', 'test', 'count', 'node'])
134Foreach = node('Foreach', ['expr', 'keyvar', 'valvar', 'node'])
135ForeachVariable = node('ForeachVariable', ['name', 'is_ref'])
136Switch = node('Switch', ['expr', 'nodes'])
137Case = node('Case', ['expr', 'nodes'])
138Default = node('Default', ['nodes'])
139Namespace = node('Namespace', ['name', 'nodes'])
140UseDeclarations = node('UseDeclarations', ['nodes'])
141UseDeclaration = node('UseDeclaration', ['name', 'alias'])
142ConstantDeclarations = node('ConstantDeclarations', ['nodes'])
143ConstantDeclaration = node('ConstantDeclaration', ['name', 'initial'])
144TraitUse = node('TraitUse', ['name', 'renames'])
145TraitModifier = node('TraitModifier', ['from', 'to', 'visibility'])
146
147def resolve_magic_constants(nodes):
148    current = {}
149    def visitor(node):
150        if isinstance(node, Namespace):
151            current['namespace'] = node.name
152        elif isinstance(node, Class):
153            current['class'] = node.name
154        elif isinstance(node, Function):
155            current['function'] = node.name
156        elif isinstance(node, Method):
157            current['method'] = node.name
158        elif isinstance(node, MagicConstant):
159            if node.name == '__NAMESPACE__':
160                node.value = current.get('namespace')
161            elif node.name == '__CLASS__':
162                node.value = current.get('class')
163                if current.get('namespace'):
164                    node.value = '%s\\%s' % (current.get('namespace'),
165                                             node.value)
166            elif node.name == '__FUNCTION__':
167                node.value = current.get('function')
168                if current.get('namespace'):
169                    node.value = '%s\\%s' % (current.get('namespace'),
170                                             node.value)
171            elif node.name == '__METHOD__':
172                node.value = current.get('method')
173                if current.get('class'):
174                    node.value = '%s::%s' % (current.get('class'),
175                                             node.value)
176                if current.get('namespace'):
177                    node.value = '%s\\%s' % (current.get('namespace'),
178                                             node.value)
179    for node in nodes:
180        if isinstance(node, Node):
181            node.accept(visitor)
182