text: # ----------------------------------------------------------------------
  # phpast.py
  #
  # PHP abstract syntax node definitions.
  # ----------------------------------------------------------------------
  
  class Node(object):
      fields = []
  
      def __init__(self, *args, **kwargs):
          assert len(self.fields) == len(args), \
              '%s takes %d arguments' % (self.__class__.__name__,
                                         len(self.fields))
          try:
              self.lineno = kwargs['lineno']
          except KeyError:
              self.lineno = None
          for i, field in enumerate(self.fields):
              setattr(self, field, args[i])
  
      def __repr__(self):
          return "%s(%s)" % (self.__class__.__name__,
                             ', '.join([repr(getattr(self, field))
                                        for field in self.fields]))
  
      def __eq__(self, other):
          if not isinstance(other, self.__class__):
              return False
          for field in self.fields:
              if not (getattr(self, field) == getattr(other, field)):
                  return False
          return True
  
      def accept(self, visitor):
          visitor(self)
          for field in self.fields:
              value = getattr(self, field)
              if isinstance(value, Node):
                  value.accept(visitor)
              elif isinstance(value, list):
                  for item in value:
                      if isinstance(item, Node):
                          item.accept(visitor)
  
      def generic(self, with_lineno=False):
          values = {}
          if with_lineno:
              values['lineno'] = self.lineno
          for field in self.fields:
              value = getattr(self, field)
              if hasattr(value, 'generic'):
                  value = value.generic(with_lineno)
              elif isinstance(value, list):
                  items = value
                  value = []
                  for item in items:
                      if hasattr(item, 'generic'):
                          item = item.generic(with_lineno)
                      value.append(item)
              values[field] = value
          return (self.__class__.__name__, values)
  
  def node(name, fields):
      attrs = {'fields': fields}
      return type(name, (Node,), attrs)
  
  InlineHTML = node('InlineHTML', ['data'])
  Block = node('Block', ['nodes'])
  Assignment = node('Assignment', ['node', 'expr', 'is_ref'])
  ListAssignment = node('ListAssignment', ['nodes', 'expr'])
  New = node('New', ['name', 'params'])
  Clone = node('Clone', ['node'])
  Break = node('Break', ['node'])
  Continue = node('Continue', ['node'])
  Return = node('Return', ['node'])
  Yield = node('Yield', ['node'])
  Global = node('Global', ['nodes'])
  Static = node('Static', ['nodes'])
  Echo = node('Echo', ['nodes'])
  Print = node('Print', ['node'])
  Unset = node('Unset', ['nodes'])
  Try = node('Try', ['nodes', 'catches', 'finally'])
  Catch = node('Catch', ['class_', 'var', 'nodes'])
  Finally = node('Finally', ['nodes'])
  Throw = node('Throw', ['node'])
  Declare = node('Declare', ['directives', 'node'])
  Directive = node('Directive', ['name', 'node'])
  Function = node('Function', ['name', 'params', 'nodes', 'is_ref'])
  Method = node('Method', ['name', 'modifiers', 'params', 'nodes', 'is_ref'])
  Closure = node('Closure', ['params', 'vars', 'nodes', 'is_ref'])
  Class = node('Class', ['name', 'type', 'extends', 'implements', 'traits', 'nodes'])
  Trait = node('Trait', ['name', 'traits', 'nodes'])
  ClassConstants = node('ClassConstants', ['nodes'])
  ClassConstant = node('ClassConstant', ['name', 'initial'])
  ClassVariables = node('ClassVariables', ['modifiers', 'nodes'])
  ClassVariable = node('ClassVariable', ['name', 'initial'])
  Interface = node('Interface', ['name', 'extends', 'nodes'])
  AssignOp = node('AssignOp', ['op', 'left', 'right'])
  BinaryOp = node('BinaryOp', ['op', 'left', 'right'])
  UnaryOp = node('UnaryOp', ['op', 'expr'])
  TernaryOp = node('TernaryOp', ['expr', 'iftrue', 'iffalse'])
  PreIncDecOp = node('PreIncDecOp', ['op', 'expr'])
  PostIncDecOp = node('PostIncDecOp', ['op', 'expr'])
  Cast = node('Cast', ['type', 'expr'])
  IsSet = node('IsSet', ['nodes'])
  Empty = node('Empty', ['expr'])
  Eval = node('Eval', ['expr'])
  Include = node('Include', ['expr', 'once'])
  Require = node('Require', ['expr', 'once'])
  Exit = node('Exit', ['expr', 'type'])
  Silence = node('Silence', ['expr'])
  MagicConstant = node('MagicConstant', ['name', 'value'])
  Constant = node('Constant', ['name'])
  Variable = node('Variable', ['name'])
  StaticVariable = node('StaticVariable', ['name', 'initial'])
  LexicalVariable = node('LexicalVariable', ['name', 'is_ref'])
  FormalParameter = node('FormalParameter', ['name', 'default', 'is_ref', 'type'])
  Parameter = node('Parameter', ['node', 'is_ref'])
  FunctionCall = node('FunctionCall', ['name', 'params'])
  Array = node('Array', ['nodes'])
  ArrayElement = node('ArrayElement', ['key', 'value', 'is_ref'])
  ArrayOffset = node('ArrayOffset', ['node', 'expr'])
  StringOffset = node('StringOffset', ['node', 'expr'])
  ObjectProperty = node('ObjectProperty', ['node', 'name'])
  StaticProperty = node('StaticProperty', ['node', 'name'])
  MethodCall = node('MethodCall', ['node', 'name', 'params'])
  StaticMethodCall = node('StaticMethodCall', ['class_', 'name', 'params'])
  If = node('If', ['expr', 'node', 'elseifs', 'else_'])
  ElseIf = node('ElseIf', ['expr', 'node'])
  Else = node('Else', ['node'])
  While = node('While', ['expr', 'node'])
  DoWhile = node('DoWhile', ['node', 'expr'])
  For = node('For', ['start', 'test', 'count', 'node'])
  Foreach = node('Foreach', ['expr', 'keyvar', 'valvar', 'node'])
  ForeachVariable = node('ForeachVariable', ['name', 'is_ref'])
  Switch = node('Switch', ['expr', 'nodes'])
  Case = node('Case', ['expr', 'nodes'])
  Default = node('Default', ['nodes'])
  Namespace = node('Namespace', ['name', 'nodes'])
  UseDeclarations = node('UseDeclarations', ['nodes'])
  UseDeclaration = node('UseDeclaration', ['name', 'alias'])
  ConstantDeclarations = node('ConstantDeclarations', ['nodes'])
  ConstantDeclaration = node('ConstantDeclaration', ['name', 'initial'])
  TraitUse = node('TraitUse', ['name', 'renames'])
  TraitModifier = node('TraitModifier', ['from', 'to', 'visibility'])
  
  def resolve_magic_constants(nodes):
      current = {}
      def visitor(node):
          if isinstance(node, Namespace):
              current['namespace'] = node.name
          elif isinstance(node, Class):
              current['class'] = node.name
          elif isinstance(node, Function):
              current['function'] = node.name
          elif isinstance(node, Method):
              current['method'] = node.name
          elif isinstance(node, MagicConstant):
              if node.name == '__NAMESPACE__':
                  node.value = current.get('namespace')
              elif node.name == '__CLASS__':
                  node.value = current.get('class')
                  if current.get('namespace'):
                      node.value = '%s\\%s' % (current.get('namespace'),
                                               node.value)
              elif node.name == '__FUNCTION__':
                  node.value = current.get('function')
                  if current.get('namespace'):
                      node.value = '%s\\%s' % (current.get('namespace'),
                                               node.value)
              elif node.name == '__METHOD__':
                  node.value = current.get('method')
                  if current.get('class'):
                      node.value = '%s::%s' % (current.get('class'),
                                               node.value)
                  if current.get('namespace'):
                      node.value = '%s\\%s' % (current.get('namespace'),
                                               node.value)
      for node in nodes:
          if isinstance(node, Node):
              node.accept(visitor)
  