aboutsummaryrefslogtreecommitdiff
path: root/catapult/common/py_utils/py_utils/refactor/annotated_symbol/reference.py
blob: 9a273d875ef7a55cfc9bc3755cfd0a931f79aead (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import symbol
import token

from py_utils.refactor import snippet
from py_utils.refactor.annotated_symbol import base_symbol
from six.moves import range # pylint: disable=redefined-builtin
from six.moves import zip_longest # pylint: disable=redefined-builtin


__all__ = [
    'Reference',
]


class Reference(base_symbol.AnnotatedSymbol):
  @classmethod
  def Annotate(cls, nodes):
    if not nodes:
      return None
    if nodes[0].type != symbol.atom:
      return None
    if not nodes[0].children or nodes[0].children[0].type != token.NAME:
      return None

    for i in range(1, len(nodes)):
      if not nodes:
        break
      if nodes[i].type != symbol.trailer:
        break
      if len(nodes[i].children) != 2:
        break
      if (nodes[i].children[0].type != token.DOT or
          nodes[i].children[1].type != token.NAME):
        break
    else:
      i = len(nodes)

    return [cls(nodes[:i])] + nodes[i:]

  def __init__(self, children):
    super(Reference, self).__init__(-1, children)

  @property
  def type_name(self):
    return 'attribute_reference'

  @property
  def value(self):
    return ''.join(token_snippet.value
                   for child in self.children
                   for token_snippet in child.children)

  @value.setter
  def value(self, value):
    value_parts = value.split('.')

    # If we have too many children, cut the list down to size.
    # pylint: disable=attribute-defined-outside-init
    self._children = self._children[:len(value_parts)]

    # Update child nodes.
    for child, value_part in zip_longest(self._children, value_parts):
      if child:
        # Modify existing children. This helps preserve comments and spaces.
        child.children[-1].value = value_part
      else:
        # Add children as needed.
        token_snippets = [
            snippet.TokenSnippet.Create(token.DOT, '.'),
            snippet.TokenSnippet.Create(token.NAME, value_part),
        ]
        self._children.append(snippet.Symbol(symbol.trailer, token_snippets))