OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2014, 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 /// Collects services that can be used to access objects dynamically, inspect |
| 6 /// type information, and convert between symbols and strings. |
| 7 library smoke; |
| 8 |
| 9 import 'src/implementation.dart' as implementation; |
| 10 |
| 11 export 'src/common.dart' show minArgs, maxArgs, SUPPORTED_ARGS; |
| 12 import 'src/common.dart' show compareLists; |
| 13 |
| 14 /// Configures this library to use [objectAccessor] for all read/write/invoke |
| 15 /// APIs, [typeInspector] for all type query APIs, and [symbolConverter] for all |
| 16 /// symbol convertion operations. |
| 17 /// |
| 18 /// This function doesn't need to be called during development, but frameworks |
| 19 /// should autogenerate a call to this function when running in deployment. |
| 20 void configure(ObjectAccessorService objectAccessor, |
| 21 TypeInspectorService typeInspector, |
| 22 SymbolConverterService symbolConverter) { |
| 23 implementation.objectAccessor = objectAccessor; |
| 24 implementation.typeInspector = typeInspector; |
| 25 implementation.symbolConverter = symbolConverter; |
| 26 } |
| 27 |
| 28 /// Return the value of [field] in [object]. |
| 29 read(Object object, Symbol field) => |
| 30 implementation.objectAccessor.read(object, field); |
| 31 |
| 32 /// Update the [value] of [field] in [object]. |
| 33 void write(Object object, Symbol field, value) => |
| 34 implementation.objectAccessor.write(object, field, value); |
| 35 |
| 36 /// Invoke [method] in [receiver] with [args]. The [receiver] can be either an |
| 37 /// object (to invoke instance methods) or a type (to invoke static methods). |
| 38 /// This function optionally [adjust]s the list of arguments to match the number |
| 39 /// of formal parameters by either adding nulls for missing arguments, or by |
| 40 /// truncating the list. |
| 41 invoke(receiver, Symbol method, List args, |
| 42 {Map namedArgs, bool adjust: false}) => |
| 43 implementation.objectAccessor.invoke( |
| 44 receiver, method, args, namedArgs: namedArgs, adjust: adjust); |
| 45 |
| 46 /// Tells whether [type] is transitively a subclass of [supertype]. |
| 47 bool isSubclassOf(Type type, Type supertype) => |
| 48 implementation.typeInspector.isSubclassOf(type, supertype); |
| 49 |
| 50 // TODO(sigmund): consider adding also: |
| 51 // * isImplementationOf(type, subtype) to tells whether [type] declares that it |
| 52 // implements the [supertype] interface. |
| 53 // * isSubtypeOf(type, subtype): Tells whether [type]'s interface is a sybtype |
| 54 // of [supertype]. That is, whether it is a subclass or if [type] implements |
| 55 // [supertype]. |
| 56 |
| 57 /// Tells whether [type] has a field or getter for [field]. |
| 58 bool hasGetter(Type type, Symbol field) => |
| 59 implementation.typeInspector.hasGetter(type, field); |
| 60 |
| 61 /// Tells whether [type] has a field or setter for [field]. |
| 62 bool hasSetter(Type type, Symbol field) => |
| 63 implementation.typeInspector.hasSetter(type, field); |
| 64 |
| 65 /// Tells whether [type] or a superclass (other than [Object]) defines |
| 66 /// `noSuchMethod`. |
| 67 bool hasNoSuchMethod(Type type) => hasInstanceMethod(type, #noSuchMethod); |
| 68 |
| 69 /// Tells whether [type] has or a superclass contains a specific instance |
| 70 /// [method] (excluding methods in [Object]). |
| 71 bool hasInstanceMethod(Type type, Symbol method) => |
| 72 implementation.typeInspector.hasInstanceMethod(type, method); |
| 73 |
| 74 /// Tells whether [type] has a specific static [method]. |
| 75 bool hasStaticMethod(Type type, Symbol method) => |
| 76 implementation.typeInspector.hasStaticMethod(type, method); |
| 77 |
| 78 /// Get the declaration associated with field [name] found in [type] or a |
| 79 /// superclass of [type]. |
| 80 Declaration getDeclaration(Type type, Symbol name) => |
| 81 implementation.typeInspector.getDeclaration(type, name); |
| 82 |
| 83 /// Retrieve all symbols of [type] that match [options]. |
| 84 List<Declaration> query(Type type, QueryOptions options) => |
| 85 implementation.typeInspector.query(type, options); |
| 86 |
| 87 /// Returns the name associated with a [symbol]. |
| 88 String symbolToName(Symbol symbol) => |
| 89 implementation.symbolConverter.symbolToName(symbol); |
| 90 |
| 91 /// Returns the symbol associated with a [name]. |
| 92 Symbol nameToSymbol(String name) => |
| 93 implementation.symbolConverter.nameToSymbol(name); |
| 94 |
| 95 /// Establishes the parameters for [query] to search for symbols in a type |
| 96 /// hierarchy. For now only public instance symbols can be queried (no private, |
| 97 /// no static). |
| 98 class QueryOptions { |
| 99 /// Whether to include fields (default is true). |
| 100 final bool includeFields; |
| 101 |
| 102 /// Whether to include getters and setters (default is true). Note that to |
| 103 /// include fields you also need to enable [includeFields]. |
| 104 final bool includeProperties; |
| 105 |
| 106 /// Whether to include symbols from the given type and its superclasses |
| 107 /// (except [Object]). |
| 108 final bool includeInherited; |
| 109 |
| 110 /// If [includeInherited], walk up the type hierarchy up to this type |
| 111 /// (defaults to [Object]). |
| 112 final Type includeUpTo; |
| 113 |
| 114 /// Whether to include final fields and getter-only properties. |
| 115 final bool excludeFinal; |
| 116 |
| 117 /// Whether to include methods (default is false). |
| 118 final bool includeMethods; |
| 119 |
| 120 /// If [withAnnotation] is not null, then it should be a list of types, so |
| 121 /// only symbols that are annotated with instances of those types are |
| 122 /// included. |
| 123 final List withAnnotations; |
| 124 |
| 125 /// If [matches] is not null, then include only those fields, properties, or |
| 126 /// methods that match the predicate. |
| 127 final NameMatcher matches; |
| 128 |
| 129 const QueryOptions({ |
| 130 this.includeFields: true, |
| 131 this.includeProperties: true, |
| 132 this.includeInherited: true, |
| 133 this.includeUpTo: Object, |
| 134 this.excludeFinal: false, |
| 135 this.includeMethods: false, |
| 136 this.withAnnotations: null, |
| 137 this.matches: null}); |
| 138 |
| 139 String toString() => (new StringBuffer() |
| 140 ..write('(options:') |
| 141 ..write(includeFields ? 'fields ' : '') |
| 142 ..write(includeProperties ? 'properties ' : '') |
| 143 ..write(includeMethods ? 'methods ' : '') |
| 144 ..write(includeInherited ? 'inherited ' : '_') |
| 145 ..write(excludeFinal ? 'no finals ' : '') |
| 146 ..write('annotations: $withAnnotations') |
| 147 ..write(matches != null ? 'with matcher' : '') |
| 148 ..write(')')).toString(); |
| 149 } |
| 150 |
| 151 /// Used to filter query results based on a predicate on [name]. Returns true if |
| 152 /// [name] should be included in the query results. |
| 153 typedef bool NameMatcher(Symbol name); |
| 154 |
| 155 /// Information associated with a symbol declaration (like a property or |
| 156 /// method). |
| 157 class Declaration { |
| 158 /// Name of the property or method |
| 159 final Symbol name; |
| 160 |
| 161 /// Kind of declaration (field, property, or method). |
| 162 final DeclarationKind kind; |
| 163 |
| 164 /// Whether the symbol is a field (and not a getter/setter property). |
| 165 bool get isField => kind == FIELD; |
| 166 |
| 167 /// Whether the symbol is a getter/setter and not a field. |
| 168 bool get isProperty => kind == PROPERTY; |
| 169 |
| 170 /// Whether the symbol is a method. |
| 171 bool get isMethod => kind == METHOD; |
| 172 |
| 173 /// For fields, whether they are final, for properties, whether they are |
| 174 /// read-only (they have no setter). |
| 175 final bool isFinal; |
| 176 |
| 177 /// If this is a field or property, it's declared type (including dynamic if |
| 178 /// it's not declared). For methods, the returned type. |
| 179 final Type type; |
| 180 |
| 181 /// Whether this symbol is static. |
| 182 final bool isStatic; |
| 183 |
| 184 /// List of annotations in this declaration. |
| 185 final List annotations; |
| 186 |
| 187 const Declaration(this.name, this.type, {this.kind: FIELD, |
| 188 this.isFinal: false, this.isStatic: false, this.annotations: const []}); |
| 189 |
| 190 int get hashCode => name.hashCode; |
| 191 operator ==(other) => other is Declaration && name == other.name && |
| 192 kind == other.kind && isFinal == other.isFinal && |
| 193 type == other.type && isStatic == other.isStatic && |
| 194 compareLists(annotations, other.annotations); |
| 195 |
| 196 String toString() { |
| 197 return (new StringBuffer() |
| 198 ..write('(declaration ') |
| 199 ..write(name) |
| 200 ..write(isProperty ? ' (property) ' : ' (method) ') |
| 201 ..write(isFinal ? 'final ' : '') |
| 202 ..write(isStatic ? 'static ' : '') |
| 203 ..write(annotations) |
| 204 ..write(')')).toString(); |
| 205 } |
| 206 } |
| 207 |
| 208 /// Enumeration for declaration kinds (field, property, or method) |
| 209 class DeclarationKind { |
| 210 final int kind; |
| 211 const DeclarationKind(this.kind); |
| 212 } |
| 213 |
| 214 /// Declaration kind used to denote a raw field. |
| 215 const FIELD = const DeclarationKind(0); |
| 216 |
| 217 /// Declaration kind used to denote a getter/setter. |
| 218 const PROPERTY = const DeclarationKind(1); |
| 219 |
| 220 /// Declaration kind used to denote a method. |
| 221 const METHOD = const DeclarationKind(2); |
| 222 |
| 223 |
| 224 /// A service that provides a way to implement simple operations on objects like |
| 225 /// read, write, and invoke. |
| 226 abstract class ObjectAccessorService { |
| 227 /// Return the value of [field] in [object]. |
| 228 read(Object object, Symbol field); |
| 229 |
| 230 /// Update the [value] of [field] in [object]. |
| 231 void write(Object object, Symbol field, value); |
| 232 |
| 233 /// Invoke [method] in [object] with [args]. It optionally [adjust]s the list |
| 234 /// of arguments to match the number of formal parameters by either adding |
| 235 /// nulls for missing arguments, or by truncating the list. |
| 236 invoke(Object object, Symbol method, List args, |
| 237 {Map namedArgs, bool adjust: false}); |
| 238 } |
| 239 |
| 240 |
| 241 /// A service that provides partial inspection into Dart types. |
| 242 abstract class TypeInspectorService { |
| 243 /// Tells whether [type] is transitively a subclass of [supertype]. |
| 244 bool isSubclassOf(Type type, Type supertype); |
| 245 |
| 246 /// Tells whether [type] has a field or getter for [name]. |
| 247 bool hasGetter(Type type, Symbol name); |
| 248 |
| 249 /// Tells whether [type] has a field or setter for [name]. |
| 250 bool hasSetter(Type type, Symbol name); |
| 251 |
| 252 /// Tells whether [type] has a specific instance [method]. |
| 253 bool hasInstanceMethod(Type type, Symbol method); |
| 254 |
| 255 /// Tells whether [type] has a specific static [method]. |
| 256 bool hasStaticMethod(Type type, Symbol method); |
| 257 |
| 258 /// Get the declaration associated with field [name] in [type]. |
| 259 Declaration getDeclaration(Type type, Symbol name); |
| 260 |
| 261 /// Retrieve all symbols of [type] that match [options]. |
| 262 List<Declaration> query(Type type, QueryOptions options); |
| 263 } |
| 264 |
| 265 |
| 266 /// A service that converts between [Symbol]s and [String]s. |
| 267 abstract class SymbolConverterService { |
| 268 /// Returns the name associated with a [symbol]. |
| 269 String symbolToName(Symbol symbol); |
| 270 |
| 271 /// Returns the symbol associated with a [name]. |
| 272 Symbol nameToSymbol(String name); |
| 273 } |
OLD | NEW |