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, canAcceptNArgs, 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}) => implementation.objectAccessor | |
43 .invoke(receiver, method, args, namedArgs: namedArgs, adjust: adjust); | |
44 | |
45 /// Tells whether [type] is transitively a subclass of [supertype]. | |
46 bool isSubclassOf(Type type, Type supertype) => | |
47 implementation.typeInspector.isSubclassOf(type, supertype); | |
48 | |
49 // TODO(sigmund): consider adding also: | |
50 // * isImplementationOf(type, subtype) to tells whether [type] declares that it | |
51 // implements the [supertype] interface. | |
52 // * isSubtypeOf(type, subtype): Tells whether [type]'s interface is a sybtype | |
53 // of [supertype]. That is, whether it is a subclass or if [type] implements | |
54 // [supertype]. | |
55 | |
56 /// Tells whether [type] has a field or getter for [field]. | |
57 bool hasGetter(Type type, Symbol field) => | |
58 implementation.typeInspector.hasGetter(type, field); | |
59 | |
60 /// Tells whether [type] has a field or setter for [field]. | |
61 bool hasSetter(Type type, Symbol field) => | |
62 implementation.typeInspector.hasSetter(type, field); | |
63 | |
64 /// Tells whether [type] or a superclass (other than [Object]) defines | |
65 /// `noSuchMethod`. | |
66 bool hasNoSuchMethod(Type type) => hasInstanceMethod(type, #noSuchMethod); | |
67 | |
68 /// Tells whether [type] has or a superclass contains a specific instance | |
69 /// [method] (excluding methods in [Object]). | |
70 bool hasInstanceMethod(Type type, Symbol method) => | |
71 implementation.typeInspector.hasInstanceMethod(type, method); | |
72 | |
73 /// Tells whether [type] has a specific static [method]. | |
74 bool hasStaticMethod(Type type, Symbol method) => | |
75 implementation.typeInspector.hasStaticMethod(type, method); | |
76 | |
77 /// Get the declaration associated with field [name] found in [type] or a | |
78 /// superclass of [type]. | |
79 Declaration getDeclaration(Type type, Symbol name) => | |
80 implementation.typeInspector.getDeclaration(type, name); | |
81 | |
82 /// Retrieve all symbols of [type] that match [options]. | |
83 List<Declaration> query(Type type, QueryOptions options) => | |
84 implementation.typeInspector.query(type, options); | |
85 | |
86 /// Returns the name associated with a [symbol]. | |
87 String symbolToName(Symbol symbol) => | |
88 implementation.symbolConverter.symbolToName(symbol); | |
89 | |
90 /// Returns the symbol associated with a [name]. | |
91 Symbol nameToSymbol(String name) => | |
92 implementation.symbolConverter.nameToSymbol(name); | |
93 | |
94 /// Establishes the parameters for [query] to search for symbols in a type | |
95 /// hierarchy. For now only public instance symbols can be queried (no private, | |
96 /// no static). | |
97 class QueryOptions { | |
98 /// Whether to include fields (default is true). | |
99 final bool includeFields; | |
100 | |
101 /// Whether to include getters and setters (default is true). Note that to | |
102 /// include fields you also need to enable [includeFields]. | |
103 final bool includeProperties; | |
104 | |
105 /// Whether to include symbols from the given type and its superclasses | |
106 /// (except [Object]). | |
107 final bool includeInherited; | |
108 | |
109 /// If [includeInherited], walk up the type hierarchy up to this type | |
110 /// (defaults to [Object]). | |
111 final Type includeUpTo; | |
112 | |
113 /// Whether to include final fields and getter-only properties. | |
114 final bool excludeFinal; | |
115 | |
116 /// Whether to include symbols that are overriden within the subclass | |
117 /// (default is false). | |
118 final bool excludeOverriden; | |
119 | |
120 /// Whether to include methods (default is false). | |
121 final bool includeMethods; | |
122 | |
123 /// If [withAnnotation] is not null, then it should be a list of types, so | |
124 /// only symbols that are annotated with instances of those types are | |
125 /// included. | |
126 final List withAnnotations; | |
127 | |
128 /// If [matches] is not null, then include only those fields, properties, or | |
129 /// methods that match the predicate. | |
130 final NameMatcher matches; | |
131 | |
132 const QueryOptions({this.includeFields: true, this.includeProperties: true, | |
133 this.includeInherited: true, this.includeUpTo: Object, | |
134 this.excludeFinal: false, this.excludeOverriden: false, | |
135 this.includeMethods: false, this.withAnnotations: null, | |
136 this.matches: null}); | |
137 | |
138 String toString() => (new StringBuffer() | |
139 ..write('(options:') | |
140 ..write(includeFields ? 'fields ' : '') | |
141 ..write(includeProperties ? 'properties ' : '') | |
142 ..write(includeMethods ? 'methods ' : '') | |
143 ..write(includeInherited ? 'inherited ' : '_') | |
144 ..write(excludeFinal ? 'no finals ' : '') | |
145 ..write(excludeOverriden ? 'no overriden ': '') | |
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 && | |
192 name == other.name && | |
193 kind == other.kind && | |
194 isFinal == other.isFinal && | |
195 type == other.type && | |
196 isStatic == other.isStatic && | |
197 compareLists(annotations, other.annotations); | |
198 | |
199 String toString() { | |
200 return (new StringBuffer() | |
201 ..write('(declaration ') | |
202 ..write(name) | |
203 ..write(isProperty ? ' (property) ' : ' (method) ') | |
204 ..write(isFinal ? 'final ' : '') | |
205 ..write(isStatic ? 'static ' : '') | |
206 ..write(annotations) | |
207 ..write(')')).toString(); | |
208 } | |
209 } | |
210 | |
211 /// Enumeration for declaration kinds (field, property, or method) | |
212 class DeclarationKind { | |
213 final int kind; | |
214 const DeclarationKind(this.kind); | |
215 } | |
216 | |
217 /// Declaration kind used to denote a raw field. | |
218 const FIELD = const DeclarationKind(0); | |
219 | |
220 /// Declaration kind used to denote a getter/setter. | |
221 const PROPERTY = const DeclarationKind(1); | |
222 | |
223 /// Declaration kind used to denote a method. | |
224 const METHOD = const DeclarationKind(2); | |
225 | |
226 /// A service that provides a way to implement simple operations on objects like | |
227 /// read, write, and invoke. | |
228 abstract class ObjectAccessorService { | |
229 /// Return the value of [field] in [object]. | |
230 read(Object object, Symbol field); | |
231 | |
232 /// Update the [value] of [field] in [object]. | |
233 void write(Object object, Symbol field, value); | |
234 | |
235 /// Invoke [method] in [object] with [args]. It optionally [adjust]s the list | |
236 /// of arguments to match the number of formal parameters by either adding | |
237 /// nulls for missing arguments, or by truncating the list. | |
238 invoke(Object object, Symbol method, List args, | |
239 {Map namedArgs, bool adjust: false}); | |
240 } | |
241 | |
242 /// A service that provides partial inspection into Dart types. | |
243 abstract class TypeInspectorService { | |
244 /// Tells whether [type] is transitively a subclass of [supertype]. | |
245 bool isSubclassOf(Type type, Type supertype); | |
246 | |
247 /// Tells whether [type] has a field or getter for [name]. | |
248 bool hasGetter(Type type, Symbol name); | |
249 | |
250 /// Tells whether [type] has a field or setter for [name]. | |
251 bool hasSetter(Type type, Symbol name); | |
252 | |
253 /// Tells whether [type] has a specific instance [method]. | |
254 bool hasInstanceMethod(Type type, Symbol method); | |
255 | |
256 /// Tells whether [type] has a specific static [method]. | |
257 bool hasStaticMethod(Type type, Symbol method); | |
258 | |
259 /// Get the declaration associated with field [name] in [type]. | |
260 Declaration getDeclaration(Type type, Symbol name); | |
261 | |
262 /// Retrieve all symbols of [type] that match [options]. | |
263 List<Declaration> query(Type type, QueryOptions options); | |
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 |