Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(482)

Side by Side Diff: pkg/smoke/lib/static.dart

Issue 169913004: Adding package:smoke. This CL includes the intial APIs, a mirror-based (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/smoke/lib/src/implementation.dart ('k') | pkg/smoke/pubspec.yaml » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 /// Static implementation of smoke services using code-generated data.
6 library smoke.static;
7
8 import 'dart:math' as math;
9
10 import 'package:logging/logging.dart';
11 import 'package:smoke/smoke.dart';
12
13 import 'src/common.dart';
14
15 typedef T Getter<T>(object);
16 typedef void Setter<T>(object, value);
17
18 StaticConfiguration _configuration;
19
20 class StaticConfiguration {
21 /// Maps symbol to a function that reads that symbol of an object. For
22 /// instance, `#i: (o) => o.i`.
23 final Map<Symbol, Getter> getters;
24
25 /// Maps symbol to a function that updates that symbol of an object. For
26 /// instance, `#i: (o, v) { o.i = v; }`.
27 final Map<Symbol, Setter> setters;
28
29 /// Maps a type to it's super class. For example, String: Object.
30 final Map<Type, Type> parents;
31
32 /// For each type, a map of declarations per symbol (property or method).
33 final Map<Type, Map<Symbol, Declaration>> declarations;
34
35 /// A map from symbol to strings.
36 final Map<Symbol, String> names;
37
38 /// A map from strings to symbols (the reverse of [names]).
39 final Map<String, Symbol> symbols;
40 StaticConfiguration({
41 this.getters: const {}, this.setters: const {}, this.parents: const {},
42 this.declarations: const {}, this.names: const {}})
43 : this.symbols = {} {
44 names.forEach((k, v) { symbols[v] = k; });
45 }
46 }
47
48 /// Set up the smoke package to use a static implementation based on the given
49 /// [configuration].
50 useGeneratedCode(StaticConfiguration configuration) {
51 _configuration = configuration;
52 configure(new _GeneratedObjectAccessorService(),
53 new _GeneratedTypeInspectorService(),
54 new _GeneratedSymbolConverterService());
55 }
56
57 /// Implements [ObjectAccessorService] using a static configuration.
58 class _GeneratedObjectAccessorService implements ObjectAccessorService {
59 read(Object object, Symbol name) {
60 var getter = _configuration.getters[name];
61 if (getter == null) {
62 throw new MissingCodeException('getter "$name" in $object');
63 }
64 return getter(object);
65 }
66 void write(Object object, Symbol name, value) {
67 var setter = _configuration.setters[name];
68 if (setter == null) {
69 throw new MissingCodeException('setter "$name" in $object');
70 }
71 setter(object, value);
72 }
73
74 invoke(object, Symbol name, List args, {Map namedArgs, bool adjust: false}) {
75 var method;
76 if (object is Type) {
77 } else {
78 var getter = _configuration.getters[name];
79 method = getter == null ? null : getter(object);
80 }
81 if (method == null) {
82 throw new MissingCodeException('method "$name" in $object');
83 }
84 var tentativeError;
85 if (adjust) {
86 var min = minArgs(method);
87 if (min > SUPPORTED_ARGS) {
88 tentativeError = 'we tried to adjust the arguments for calling "$name"'
89 ', but we couldn\'t determine the exact number of arguments it '
90 'expects (it is more than $SUPPORTED_ARGS).';
91 // The argument list might be correct, so we still invoke the function
92 // and let the user see the error.
93 args = adjustList(args, min, math.max(min, args.length));
94 } else {
95 var max = maxArgs(method);
96 args = adjustList(args, min, max >= 0 ? max : args.length);
97 }
98 }
99 if (namedArgs != null) {
100 throw new UnsupportedError(
101 'smoke.static doesn\'t support namedArguments in invoke');
102 }
103 try {
104 return Function.apply(method, args);
105 } on NoSuchMethodError catch (e) {
106 // TODO(sigmund): consider whether this should just be in a logger or if
107 // we should wrap `e` as a new exception (what's the best way to let users
108 // know about this tentativeError?)
109 if (tentativeError != null) print(tentativeError);
110 rethrow;
111 }
112 }
113 }
114
115 /// Implements [TypeInspectorService] using a static configuration.
116 class _GeneratedTypeInspectorService implements TypeInspectorService {
117 bool hasGetter(Type type, Symbol name) {
118 var decl = _findDeclaration(type, name);
119 // No need to check decl.isProperty because methods are also automatically
120 // considered getters (auto-closures).
121 return decl != null && !decl.isStatic;
122 }
123
124 bool hasSetter(Type type, Symbol name) {
125 var decl = _findDeclaration(type, name);
126 return decl != null && !decl.isMethod && !decl.isFinal && !decl.isStatic;
127 }
128
129 bool hasInstanceMethod(Type type, Symbol name) {
130 var decl = _findDeclaration(type, name);
131 return decl != null && decl.isMethod && !decl.isStatic;
132 }
133
134 bool hasStaticMethod(Type type, Symbol name) {
135 final map = _configuration.declarations[type];
136 if (map == null) {
137 throw new MissingCodeException('declarations for $type');
138 }
139 final decl = map[name];
140 return decl != null && decl.isMethod && decl.isStatic;
141 }
142
143 Declaration getDeclaration(Type type, Symbol name) {
144 var decl = _findDeclaration(type, name);
145 if (decl == null) {
146 throw new MissingCodeException('declaration for $type.$name');
147 }
148 return decl;
149 }
150
151 List<Declaration> query(Type type, QueryOptions options) {
152 var result;
153 if (options.includeInherited) {
154 var superclass = _configuration.parents[type];
155 if (superclass == null) {
156 throw new MissingCodeException('superclass of "$type"');
157 }
158 result = (superclass == Object) ? [] : query(superclass, options);
159 } else {
160 result = [];
161 }
162 var map = _configuration.declarations[type];
163 if (map == null) {
164 throw new MissingCodeException('declarations for $type');
165 }
166 for (var decl in map.values) {
167 if (!options.includeProperties && decl.isProperty) continue;
168 if (options.excludeFinal && decl.isFinal) continue;
169 if (!options.includeMethods && decl.isMethod) continue;
170 if (options.withAnnotations != null &&
171 !matchesAnnotation(decl.annotations, options.withAnnotations)) {
172 continue;
173 }
174 result.add(decl);
175 }
176 return result;
177 }
178 }
179
180 /// Implements [SymbolConverterService] using a static configuration.
181 class _GeneratedSymbolConverterService implements SymbolConverterService {
182 String symbolToName(Symbol symbol) => _configuration.names[symbol];
183 Symbol nameToSymbol(String name) => _configuration.symbols[name];
184 }
185
186
187 /// Exception thrown when trynig to access something that should be there, but
188 /// the code generator didn't include it.
189 class MissingCodeException implements Exception {
190 final String description;
191 MissingCodeException(this.description);
192
193 String toString() => 'Missing $description. '
194 'Code generation for the smoke package seems incomplete.';
195 }
196
197 Declaration _findDeclaration(Type type, Symbol name) {
198 while (type != Object) {
199 final declarations = _configuration.declarations[type];
200 if (declarations != null) {
201 final declaration = declarations[name];
202 if (declaration != null) return declaration;
203 }
204 var parentType = _configuration.parents[type];
205 if (parentType == null) {
206 throw new MissingCodeException('superclass of "$type"');
207 }
208 type = parentType;
209 }
210 return null;
211 }
OLDNEW
« no previous file with comments | « pkg/smoke/lib/src/implementation.dart ('k') | pkg/smoke/pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698