| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 /** |
| 6 * Code for classifying the semantics of identifiers appearing in a Dart file. |
| 7 */ |
| 8 library sharedfrontend.access_semantics; |
| 9 |
| 10 import '../elements.dart'; |
| 11 |
| 12 /** |
| 13 * Enum representing the different kinds of destinations which a property |
| 14 * access or method or function invocation might refer to. |
| 15 */ |
| 16 class AccessKind { |
| 17 /** |
| 18 * The destination of the access is an instance method, property, or field |
| 19 * of a class, and thus must be determined dynamically. |
| 20 */ |
| 21 static const AccessKind DYNAMIC = const AccessKind._('DYNAMIC'); |
| 22 |
| 23 /** |
| 24 * The destination of the access is a function that is defined locally within |
| 25 * an enclosing function or method. |
| 26 */ |
| 27 static const AccessKind LOCAL_FUNCTION = const AccessKind._('LOCAL_FUNCTION'); |
| 28 |
| 29 /** |
| 30 * The destination of the access is a variable that is defined locally within |
| 31 * an enclosing function or method. |
| 32 */ |
| 33 static const AccessKind LOCAL_VARIABLE = const AccessKind._('LOCAL_VARIABLE'); |
| 34 |
| 35 /** |
| 36 * The destination of the access is a variable that is defined as a parameter |
| 37 * to an enclosing function or method. |
| 38 */ |
| 39 static const AccessKind PARAMETER = const AccessKind._('PARAMETER'); |
| 40 |
| 41 /** |
| 42 * The destination of the access is a field that is defined statically within |
| 43 * a class, or a top level variable within a library. |
| 44 */ |
| 45 static const AccessKind STATIC_FIELD = const AccessKind._('STATIC_FIELD'); |
| 46 |
| 47 /** |
| 48 * The destination of the access is a method that is defined statically |
| 49 * within a class, or at top level within a library. |
| 50 */ |
| 51 static const AccessKind STATIC_METHOD = const AccessKind._('STATIC_METHOD'); |
| 52 |
| 53 /** |
| 54 * The destination of the access is a property getter/setter that is defined |
| 55 * statically within a class, or at top level within a library. |
| 56 */ |
| 57 static const AccessKind STATIC_PROPERTY = |
| 58 const AccessKind._('STATIC_PROPERTY'); |
| 59 |
| 60 /** |
| 61 * The destination of the access is a toplevel class, function typedef, mixin |
| 62 * application, or the built-in type "dynamic". |
| 63 */ |
| 64 static const AccessKind TOPLEVEL_TYPE = const AccessKind._('TOPLEVEL_TYPE'); |
| 65 |
| 66 /** |
| 67 * The destination of the access is a type parameter of the enclosing class. |
| 68 */ |
| 69 static const AccessKind TYPE_PARAMETER = const AccessKind._('TYPE_PARAMETER'); |
| 70 |
| 71 final String name; |
| 72 |
| 73 const AccessKind._(this.name); |
| 74 |
| 75 String toString() => name; |
| 76 } |
| 77 |
| 78 /** |
| 79 * Data structure used to classify the semantics of a property access or method |
| 80 * or function invocation. |
| 81 */ |
| 82 // TODO(paulberry,johnniwinther): Support index operations in AccessSemantics. |
| 83 class AccessSemantics { |
| 84 /** |
| 85 * The kind of access. |
| 86 */ |
| 87 final AccessKind kind; |
| 88 |
| 89 /** |
| 90 * The name being used to access the property, method, or function. |
| 91 */ |
| 92 final String name; |
| 93 |
| 94 /** |
| 95 * The element being accessed, if statically known. This will be null if |
| 96 * [kind] is DYNAMIC or if the element is undefined (e.g. an attempt to |
| 97 * access a non-existent static method in a class). |
| 98 */ |
| 99 final Element element; |
| 100 |
| 101 /** |
| 102 * The class containing the element being accessed, if this is a static |
| 103 * reference to an element in a class. This will be null if [kind] is |
| 104 * DYNAMIC, LOCAL_FUNCTION, LOCAL_VARIABLE, PARAMETER, TOPLEVEL_CLASS, or |
| 105 * TYPE_PARAMETER, or if the element being accessed is defined at toplevel |
| 106 * within a library. |
| 107 * |
| 108 * Note: it is possible for [classElement] to be non-null and for [element] |
| 109 * to be null; for example this occurs if the element being accessed is a |
| 110 * non-existent static method or field inside an existing class. |
| 111 */ |
| 112 final ClassElement classElement; |
| 113 |
| 114 // TODO(paulberry): would it also be useful to store the libraryElement? |
| 115 |
| 116 /** |
| 117 * When [kind] is DYNAMIC, the expression whose runtime type determines the |
| 118 * class in which [identifier] should be looked up. Null if the expression |
| 119 * is implicit "this". |
| 120 * |
| 121 * When [kind] is not DYNAMIC, this field is always null. |
| 122 */ |
| 123 final /*Expression*/ target; |
| 124 |
| 125 /** |
| 126 * True if this is an invocation of a method, or a call on a property. |
| 127 */ |
| 128 final bool isInvoke; |
| 129 |
| 130 /** |
| 131 * True if this is a read access to a property, or a method tear-off. Note |
| 132 * that both [isRead] and [isWrite] will be true in the case of a |
| 133 * read-modify-write operation (e.g. "+="). |
| 134 */ |
| 135 final bool isRead;// => !isInvoke && identifier.inGetterContext(); |
| 136 |
| 137 /** |
| 138 * True if this is a write access to a property, or an (erroneous) attempt to |
| 139 * write to a method. Note that both [isRead] and [isWrite] will be true in |
| 140 * the case of a read-modify-write operation (e.g. "+="). |
| 141 */ |
| 142 final bool isWrite; // => identifier.inSetterContext(); |
| 143 |
| 144 AccessSemantics.dynamic( |
| 145 this.name, |
| 146 this.target, |
| 147 {this.isInvoke: false, |
| 148 this.isRead: false, |
| 149 this.isWrite: false}) |
| 150 : kind = AccessKind.DYNAMIC, |
| 151 element = null, |
| 152 classElement = null; |
| 153 |
| 154 AccessSemantics.localFunction( |
| 155 this.name, |
| 156 this.element, |
| 157 {this.isInvoke: false, |
| 158 this.isRead: false, |
| 159 this.isWrite: false}) |
| 160 : kind = AccessKind.LOCAL_FUNCTION, |
| 161 classElement = null, |
| 162 target = null; |
| 163 |
| 164 AccessSemantics.localVariable( |
| 165 this.name, |
| 166 this.element, |
| 167 {this.isInvoke: false, |
| 168 this.isRead: false, |
| 169 this.isWrite: false}) |
| 170 : kind = AccessKind.LOCAL_VARIABLE, |
| 171 classElement = null, |
| 172 target = null; |
| 173 |
| 174 AccessSemantics.parameter( |
| 175 this.name, |
| 176 this.element, |
| 177 {this.isInvoke: false, |
| 178 this.isRead: false, |
| 179 this.isWrite: false}) |
| 180 : kind = AccessKind.PARAMETER, |
| 181 classElement = null, |
| 182 target = null; |
| 183 |
| 184 AccessSemantics.staticField( |
| 185 this.name, |
| 186 this.element, |
| 187 this.classElement, |
| 188 {this.isInvoke: false, |
| 189 this.isRead: false, |
| 190 this.isWrite: false}) |
| 191 : kind = AccessKind.STATIC_FIELD, |
| 192 target = null; |
| 193 |
| 194 AccessSemantics.staticMethod( |
| 195 this.name, |
| 196 this.element, |
| 197 this.classElement, |
| 198 {this.isInvoke: false, |
| 199 this.isRead: false, |
| 200 this.isWrite: false}) |
| 201 : kind = AccessKind.STATIC_METHOD, |
| 202 target = null; |
| 203 |
| 204 AccessSemantics.staticProperty( |
| 205 this.name, |
| 206 this.element, |
| 207 this.classElement, |
| 208 {this.isInvoke: false, |
| 209 this.isRead: false, |
| 210 this.isWrite: false}) |
| 211 : kind = AccessKind.STATIC_PROPERTY, |
| 212 target = null; |
| 213 |
| 214 AccessSemantics.toplevelType( |
| 215 this.name, |
| 216 this.element, |
| 217 {this.isInvoke: false, |
| 218 this.isRead: false, |
| 219 this.isWrite: false}) |
| 220 : kind = AccessKind.TOPLEVEL_TYPE, |
| 221 classElement = null, |
| 222 target = null; |
| 223 |
| 224 AccessSemantics.typeParameter( |
| 225 this.name, |
| 226 this.element, |
| 227 {this.isInvoke: false, |
| 228 this.isRead: false, |
| 229 this.isWrite: false}) |
| 230 : kind = AccessKind.TYPE_PARAMETER, |
| 231 classElement = null, |
| 232 target = null; |
| 233 |
| 234 String toString() { |
| 235 StringBuffer sb = new StringBuffer(); |
| 236 sb.write('AccessSemantics['); |
| 237 sb.write('kind=$kind,'); |
| 238 if (isRead && isWrite) { |
| 239 assert(!isInvoke); |
| 240 sb.write('read/write,'); |
| 241 } else if (isRead) { |
| 242 sb.write('read,'); |
| 243 } else if (isWrite) { |
| 244 sb.write('write,'); |
| 245 } else if (isInvoke) { |
| 246 sb.write('call,'); |
| 247 } |
| 248 if (element != null) { |
| 249 sb.write('element='); |
| 250 if (classElement != null) { |
| 251 sb.write('${classElement.name}.'); |
| 252 } |
| 253 sb.write('${element}'); |
| 254 } else { |
| 255 if (target == null) { |
| 256 sb.write('target=this.$name'); |
| 257 } else { |
| 258 sb.write('target=$target.$name'); |
| 259 } |
| 260 } |
| 261 sb.write(']'); |
| 262 return sb.toString(); |
| 263 } |
| 264 } |
| OLD | NEW |