• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2022 Huawei Technologies Co., Ltd
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ============================================================================
15"""Rewrite module api: ValueType and ScopedValue."""
16from enum import Enum
17from typing import Optional, Union, List, Tuple
18from mindspore import _checkparam as Validator
19
20
21class ValueType(Enum):
22    """
23    ValueType represents type of `ScopedValue`.
24
25    - A `NamingValue` represents a reference to another variable.
26    - A `CustomObjValue` represents an instance of custom class or an object whose type is out of range of base-type
27      and container-type of ValueType.
28    """
29
30    # constant type
31    ConstantValue = 0
32    # container type
33    TupleValue = 20
34    ListValue = 21
35    DictValue = 22
36    # variable type
37    NamingValue = 40
38    CustomObjValue = 41
39    # unsupported type
40    UnsupportedValue = 50
41
42
43class ScopedValue:
44    """
45    `ScopedValue` represents a value with its full-scope.
46
47    `ScopedValue` is used to express: a left-value such as target of an assign statement, or a callable object such as
48    func of a call statement, or a right-value such as args and kwargs of an assign statement.
49
50    Args:
51        arg_type (ValueType): A `ValueType` represents type of current value.
52        scope (str, optional): A string represents scope of current value. Take "self.var1" as an example,
53            `scope` of this var1 is "self". Default: ``""`` .
54        value: A handler represents value of current value. The type of value is corresponding to `arg_type`.
55            Default: ``None`` .
56    """
57
58    def __init__(self, arg_type: ValueType, scope: str = "", value=None):
59        Validator.check_value_type("arg_type", arg_type, [ValueType], "ScopedValue")
60        Validator.check_value_type("scope", scope, [str], "ScopedValue")
61        self.type = arg_type
62        self.scope = scope
63        self.value = value
64
65    @classmethod
66    def create_variable_value(cls, value) -> Optional['ScopedValue']:
67        """
68        Create `ScopedValue` from a variable.
69
70        `ScopedValue`'s type is determined by type of value. `ScopedValue`'s scope is empty.
71
72        Args:
73            value: The value to be converted to `ScopedValue`.
74
75        Returns:
76            An instance of `ScopedValue`.
77
78        Examples:
79            >>> from mindspore.rewrite import ScopedValue
80            >>> variable = ScopedValue.create_variable_value(2)
81            >>> print(variable)
82            2
83        """
84        if isinstance(value, (type(None), int, float, str, bool)):
85            return cls(ValueType.ConstantValue, "", value)
86        if isinstance(value, tuple):
87            return cls(ValueType.TupleValue, "",
88                       tuple(cls.create_variable_value(single_value) for single_value in value))
89        if isinstance(value, list):
90            return cls(ValueType.ListValue, "",
91                       list(cls.create_variable_value(single_value) for single_value in value))
92        if isinstance(value, dict):
93            return cls(ValueType.DictValue, "",
94                       dict((cls.create_variable_value(key),
95                             cls.create_variable_value(single_value)) for key, single_value in value.items()))
96        return cls(ValueType.CustomObjValue, "", value)
97
98    @classmethod
99    def create_naming_value(cls, name: str, scope: str = "") -> 'ScopedValue':
100        """
101        Create a naming `ScopedValue`. A `NamingValue` represents a reference to another variable.
102
103        Args:
104            name (str): A string represents the identifier of another variable.
105            scope (str, optional): A string represents the scope of another variable. Default: ``""`` .
106
107        Returns:
108            An instance of `ScopedValue`.
109
110        Raises:
111            TypeError: If `name` is not `str`.
112            TypeError: If `scope` is not `str`.
113
114        Examples:
115            >>> from mindspore.rewrite import ScopedValue
116            >>> variable = ScopedValue.create_naming_value("conv", "self")
117            >>> print(variable)
118            self.conv
119        """
120        Validator.check_value_type("name", name, [str], "ScopedValue")
121        Validator.check_value_type("scope", scope, [str], "ScopedValue")
122        return cls(ValueType.NamingValue, scope, name)
123
124    @staticmethod
125    def create_name_values(names: Union[List[str], Tuple[str]],
126                           scopes: Union[List[str], Tuple[str]] = None) -> List['ScopedValue']:
127        """
128        Create a list of naming `ScopedValue`.
129
130        Args:
131            names (List[str] or Tuple[str]): List or tuple of `str` represents names of referenced variables.
132            scopes (List[str] or Tuple[str], optional): List or tuple of `str` represents scopes of
133                referenced variables. Default: ``None`` .
134
135        Returns:
136            An list of instance of `ScopedValue`.
137
138        Raises:
139            TypeError: If `names` is not `list` or `tuple` and name in `names` is not `str`.
140            TypeError: If `scopes` is not `list` or `tuple` and scope in `scopes` is not `str`.
141            ValueError: If the length of names is not equal to the length of scopes when scopes are not None.
142
143        Examples:
144            >>> from mindspore.rewrite import ScopedValue
145            >>> variables = ScopedValue.create_name_values(names=["z", "z_1"], scopes=["self", "self"])
146            >>> print(variables)
147            [self.z, self.z_1]
148        """
149        Validator.check_element_type_of_iterable("names", names, [str], "ScopedValue")
150        if scopes is not None:
151            Validator.check_element_type_of_iterable("scopes", scopes, [str], "ScopedValue")
152            if len(names) != len(scopes):
153                raise ValueError("Length of names should be equal to length of scopes")
154        result = []
155        for index, name in enumerate(names):
156            if scopes is not None:
157                scope = scopes[index]
158            else:
159                scope = ""
160            result.append(ScopedValue.create_naming_value(name, scope))
161        return result
162
163    def __str__(self):
164        if self.type == ValueType.ConstantValue:
165            return str(self.value)
166        if self.type == ValueType.NamingValue:
167            return f"{self.scope}.{self.value}" if self.scope else str(self.value)
168        if self.type == ValueType.CustomObjValue:
169            return f"CustomObj: {str(self.value)}"
170        return f"Illegal ValueType: {str(self.type)}"
171
172    def __eq__(self, other):
173        if id(self) == id(other):
174            return True
175        return self.type == other.type and self.scope == other.scope and self.value == other.value
176
177    def __repr__(self):
178        return str(self)
179
180    def __hash__(self):
181        return hash((self.type, self.scope, self.value))
182