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

Side by Side Diff: frog/leg/lib/native_helper.dart

Issue 9873021: Move frog/leg to lib/compiler/implementation. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 9 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 | « frog/leg/lib/mockimpl.dart ('k') | frog/leg/lib/regexp_helper.dart » ('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) 2012, 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 String typeNameInChrome(obj) {
6 String name = JS('String', "#.constructor.name", obj);
7 if (name == 'Window') return 'DOMWindow';
8 return name;
9 }
10
11 String typeNameInFirefox(obj) {
12 String name = constructorNameFallback(obj);
13 if (name == 'Window') return 'DOMWindow';
14 if (name == 'Document') return 'HTMLDocument';
15 if (name == 'XMLDocument') return 'Document';
16 return name;
17 }
18
19 String typeNameInIE(obj) {
20 String name = constructorNameFallback(obj);
21 if (name == 'Window') return 'DOMWindow';
22 // IE calls both HTML and XML documents 'Document', so we check for the
23 // xmlVersion property, which is the empty string on HTML documents.
24 if (name == 'Document' && JS('bool', '!!#.xmlVersion', obj)) return 'Document' ;
25 if (name == 'Document') return 'HTMLDocument';
26 return name;
27 }
28
29 String constructorNameFallback(obj) {
30 var constructor = JS('var', "#.constructor", obj);
31 if (JS('String', "typeof(#)", constructor) === 'function') {
32 // The constructor isn't null or undefined at this point. Try
33 // to grab hold of its name.
34 var name = JS('var', '#.name', constructor);
35 // If the name is a non-empty string, we use that as the type
36 // name of this object. On Firefox, we often get 'Object' as
37 // the constructor name even for more specialized objects so
38 // we have to fall through to the toString() based implementation
39 // below in that case.
40 if (JS('String', "typeof(#)", name) === 'string'
41 && !name.isEmpty()
42 && name !== 'Object') {
43 return name;
44 }
45 }
46 String string = JS('String', 'Object.prototype.toString.call(#)', obj);
47 return string.substring(8, string.length - 1);
48 }
49
50
51 /**
52 * Returns the function to use to get the type name of an object.
53 */
54 Function getTypeNameOfFunction() {
55 // If we're not in the browser, we're almost certainly running on v8.
56 if (JS('String', 'typeof(navigator)') !== 'object') return typeNameInChrome;
57
58 String userAgent = JS('String', "navigator.userAgent");
59 if (userAgent.contains(const RegExp('Chrome|DumpRenderTree'))) {
60 return typeNameInChrome;
61 } else if (userAgent.contains('Firefox')) {
62 return typeNameInFirefox;
63 } else if (userAgent.contains('MSIE')) {
64 return typeNameInIE;
65 } else {
66 return constructorNameFallback;
67 }
68 }
69
70
71 /**
72 * Cached value for the function to use to get the type name of an
73 * object.
74 */
75 Function _getTypeNameOf;
76
77 /**
78 * Returns the type name of [obj].
79 */
80 String getTypeNameOf(var obj) {
81 if (_getTypeNameOf === null) _getTypeNameOf = getTypeNameOfFunction();
82 return _getTypeNameOf(obj);
83 }
84
85 String toStringForNativeObject(var obj) {
86 return 'Instance of ${getTypeNameOf(obj)}';
87 }
88
89 /**
90 * Sets a JavaScript property on an object.
91 */
92 void defineProperty(var obj, String property, var value) {
93 JS('void', """Object.defineProperty(#, #,
94 {value: #, enumerable: false, writable: false, configurable: true});""",
95 obj,
96 property,
97 value);
98 }
99
100 /**
101 * Helper method to throw a [NoSuchMethodException] for a invalid call
102 * on a native object.
103 */
104 void throwNoSuchMethod(obj, name, arguments) {
105 throw new NoSuchMethodException(obj, name, arguments);
106 }
107
108 /**
109 * This method looks up the type name of [obj] in [methods]. If it
110 * cannot find it, it looks into the [_dynamicMetadata] array. If the
111 * method can still not be found, it creates a method that will throw
112 * a [NoSuchMethodException].
113 *
114 * Once it has a method, the prototype of [obj] is patched with that
115 * method, on the property [name]. The method is then invoked.
116 *
117 * This method returns the result of invoking the found method.
118 */
119 dynamicBind(var obj,
120 String name,
121 var methods,
122 List arguments) {
123 String tag = getTypeNameOf(obj);
124 var method = JS('var', '#[#]', methods, tag);
125
126 if (method === null && _dynamicMetadata !== null) {
127 for (int i = 0; i < _dynamicMetadata.length; i++) {
128 MetaInfo entry = _dynamicMetadata[i];
129 if (entry.set.contains(tag)) {
130 method = JS('var', '#[#]', methods, entry.tag);
131 if (method !== null) break;
132 }
133 }
134 }
135
136 if (method === null) {
137 method = JS('var', "#['Object']", methods);
138 }
139
140 if (method === null) {
141 method = JS('var',
142 'function () {'
143 '#(#, #, Array.prototype.slice.call(arguments));'
144 '}',
145 DART_CLOSURE_TO_JS(throwNoSuchMethod), obj, name);
146 }
147
148 var nullCheckMethod = JS('var',
149 'function() {'
150 'var res = #.apply(this, Array.prototype.slice.call(arguments));'
151 'return res === null ? (void 0) : res;'
152 '}',
153 method);
154
155 var proto = JS('var', 'Object.getPrototypeOf(#)', obj);
156 if (JS('bool', '!#.hasOwnProperty(#)', proto, name)) {
157 defineProperty(proto, name, nullCheckMethod);
158 }
159
160 return JS('var', '#.apply(#, #)', nullCheckMethod, obj, arguments);
161 }
162
163 /**
164 * Code for doing the dynamic dispatch on JavaScript prototypes that are not
165 * available at compile-time. Each property of a native Dart class
166 * is registered through this function, which is called with the
167 * following pattern:
168 *
169 * dynamicFunction('propertyName').prototypeName = // JS code
170 *
171 * What this function does is:
172 * - Creates a map of { prototypeName: JS code }.
173 * - Attaches 'propertyName' to the JS Object prototype that will
174 * intercept at runtime all calls to propertyName.
175 * - Sets the value of 'propertyName' to the returned method from
176 * [dynamicBind].
177 *
178 */
179 dynamicFunction(name) {
180 var f = JS('var', 'Object.prototype[#]', name);
181 if (f !== null && JS('bool', '!!#.methods', f)) {
182 return JS('var', '#.methods', f);
183 }
184
185 // TODO(ngeoffray): We could make this a map if the code we
186 // generate plays well with a Dart map.
187 var methods = JS('var', '{}');
188 // If there is a method attached to the Dart Object class, use it as
189 // the method to call in case no method is registered for that type.
190 var dartMethod = JS('var', 'Object.getPrototypeOf(#)[#]', new Object(), name);
191 if (dartMethod !== null) JS('void', "#['Object'] = #", methods, dartMethod);
192
193 var bind = JS('var',
194 'function() {'
195 'return #(this, #, #, Array.prototype.slice.call(arguments));'
196 '}',
197 DART_CLOSURE_TO_JS(dynamicBind), name, methods);
198
199 JS('void', '#.methods = #', bind, methods);
200 defineProperty(JS('var', 'Object.prototype'), name, bind);
201 return methods;
202 }
203
204 /**
205 * This class encodes the class hierarchy when we need it for dynamic
206 * dispatch.
207 */
208 class MetaInfo {
209 /**
210 * The type name this [MetaInfo] relates to.
211 */
212 String tag;
213
214 /**
215 * A string containing the names of subtypes of [tag], separated by
216 * '|'.
217 */
218 String tags;
219
220 /**
221 * A list of names of subtypes of [tag].
222 */
223 Set<String> set;
224
225 MetaInfo(this.tag, this.tags, this.set);
226 }
227
228 List<MetaInfo> get _dynamicMetadata() {
229 if (JS('var', 'typeof(\$dynamicMetadata)') === 'undefined') {
230 _dynamicMetadata = <MetaInfo>[];
231 }
232 return JS('var', '\$dynamicMetadata');
233 }
234
235 void set _dynamicMetadata(List<String> table) {
236 JS('void', '\$dynamicMetadata = #', table);
237 }
238
239 /**
240 * Builds the metadata used for encoding the class hierarchy of native
241 * classes. The following example:
242 *
243 * class A native "*A" {}
244 * class B native "*B" {}
245 *
246 * Will generate:
247 * ['A', 'A|B']
248 *
249 * This method turns the array into a list of [MetaInfo] objects.
250 */
251 void dynamicSetMetadata(List<List<String>> inputTable) {
252 _dynamicMetadata = <MetaInfo>[];
253 for (int i = 0; i < inputTable.length; i++) {
254 String tag = inputTable[i][0];
255 String tags = inputTable[i][1];
256 Set<String> set = new Set<String>();
257 List<String> tagNames = tags.split('|');
258 for (int j = 0; j < tagNames.length; j++) {
259 set.add(tagNames[j]);
260 }
261 _dynamicMetadata.add(new MetaInfo(tag, tags, set));
262 }
263 }
OLDNEW
« no previous file with comments | « frog/leg/lib/mockimpl.dart ('k') | frog/leg/lib/regexp_helper.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698