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