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

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

Issue 9750003: Write our JS blobs for handling native classes in Dart. (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/js_helper.dart ('k') | frog/leg/native_emitter.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 chromeTypeNameOf(obj) {
ahe 2012/03/26 14:01:23 Generally, I would prefer if these methods followe
ngeoffray 2012/03/26 14:13:44 Done.
6 String name = JS('String', "#.constructor.name", obj);
7 if (name == 'Window') return 'DOMWindow';
8 return name;
9 }
10
11 String firefoxTypeNameOf(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 ieTypeNameOf(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';
ahe 2012/03/26 14:01:23 I doubt that this is really a bool: JS('bool', '#.
ngeoffray 2012/03/26 14:13:44 Done.
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('bool', "typeof(#) == 'function'", constructor)) {
ahe 2012/03/26 14:01:23 I think we have generally used this pattern, but i
ngeoffray 2012/03/26 14:13:44 Yeah, that could be better.
ahe 2012/03/27 09:42:08 I don't know if it is a problem to use === on stri
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('bool', "typeof(#) == 'string'", name)
41 && JS('bool', '#', name)
ahe 2012/03/26 14:57:28 This is not a boolean and I think it is unnecessar
ngeoffray 2012/03/27 09:17:35 It's necessary because it's checking if the string
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);
ahe 2012/03/26 14:57:28 I'm concerned about this. We should share this wit
ngeoffray 2012/03/27 09:17:35 Probably, but I'd wait another CL to make sure it'
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("bool", "typeof(navigator) != 'object'")) return chromeTypeNameOf;
57
58 String userAgent = JS('String', "navigator.userAgent");
59 if (userAgent.contains(const RegExp('Chrome|DumpRenderTree'))) {
60 return chromeTypeNameOf;
61 } else if (userAgent.contains('Firefox')) {
62 return firefoxTypeNameOf;
63 } else if (userAgent.contains('MSIE')) {
64 return ieTypeNameOf;
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();
ahe 2012/03/26 14:57:28 ===
ngeoffray 2012/03/27 09:17:35 Done.
82 return _getTypeNameOf(obj);
83 }
84
85 /**
86 * Sets a JavaScript property on an object.
87 */
88 void defineProperty(var obj, String property, var value) {
89 JS('void', """Object.defineProperty(#, #,
90 {value: #, enumerable: false, writable: false, configurable: true});""",
91 obj,
92 property,
93 value);
94 }
95
96 /**
97 * Helper method to throw a [NoSuchMethodException] for a invalid call
98 * on a native object.
99 */
100 void throwNoSuchMethod(obj, name, arguments) {
101 throw new NoSuchMethodException(obj, name, arguments);
102 }
103
104 /**
105 * Returns a method that queries [methods] with the prototype of [obj],
106 * patches the prototype of [obj] with the found JS code,
107 * and invokes the JS code.
ahe 2012/03/26 14:57:28 This comment is convoluted and it doesn't match wh
ngeoffray 2012/03/27 09:17:35 Comment updated. Yes [methods] is a JS object, see
108 */
109 dynamicBind(var obj,
110 String name,
ahe 2012/03/26 14:57:28 What is the name for?
ngeoffray 2012/03/27 09:17:35 That's the name of the method. Used to patch the p
111 var methods,
112 List arguments) {
113 String tag = getTypeNameOf(obj);
114 var method = JS('var', '#[#]', methods, tag);
115
116 if (method === null && _dynamicMetadata !== null) {
ahe 2012/03/26 14:57:28 What is _dynamicMetadata and how does it relate to
ngeoffray 2012/03/27 09:17:35 I updated the comment.
117 for (int i = 0; i < _dynamicMetadata.length; i++) {
118 MetaInfo entry = _dynamicMetadata[i];
119 if (entry.set.contains(tag)) {
120 method = JS('var', '#[#]', methods, entry.tag);
121 if (method !== null) break;
122 }
123 }
124 }
125
126 if (method === null) {
127 method = JS('var', "#['Object']", methods);
128 }
129
130 if (method === null) {
131 method = JS('var',
132 'function () {'
133 '#(#, #, Array.prototype.slice.call(arguments));'
ahe 2012/03/26 14:57:28 Would this work: new List.from(arguments) We could
ngeoffray 2012/03/27 09:17:35 I'm not sure I want to mix regular code that calls
ahe 2012/03/27 09:42:08 I would find this code easier to understand if it
ngeoffray 2012/03/27 10:37:33 I could change it to: '#(#, #, #(arguments));', D
134 '}',
135 DART_CLOSURE_TO_JS(throwNoSuchMethod), obj, name);
136 }
137
138 var nullCheckMethod = JS('var',
139 'function() {'
140 'var res = #.apply(this, Array.prototype.slice.call(arguments));'
141 'return res === null ? (void 0) : res;'
142 '}',
143 method);
144
145 var proto = JS('var', 'Object.getPrototypeOf(#)', obj);
146 if (JS('bool', '!#.hasOwnProperty(#)', proto, name)) {
147 defineProperty(proto, name, nullCheckMethod);
148 }
149
150 return JS('var', '#.apply(#, #)', nullCheckMethod, obj, arguments);
151 }
152
153 /**
154 * Code for doing the dynamic dispatch on JavaScript prototypes that are not
155 * available at compile-time. Each property of a native Dart class
156 * is registered through this function, which is called with the
157 * following pattern:
158 *
159 * dynamicFunction('propertyName').prototypeName = // JS code
160 *
161 * What this function does is:
162 * - Creates a map of { prototypeName: JS code }.
163 * - Attaches 'propertyName' to the JS Object prototype that will
164 * intercept at runtime all calls to propertyName.
165 * - Sets the value of 'propertyName' to the returned method from
166 * [dynamicBind].
167 *
168 */
169 dynamicFunction(name) {
170 var f = JS('var', 'Object.prototype[#]', name);
171 if (f !== null && JS('bool', '#.methods', f)) {
ahe 2012/03/26 14:57:28 I doubt that #.methods is a boolean.
ngeoffray 2012/03/27 09:17:35 Done.
172 return JS('var', '#.methods', f);
173 }
174
175 // TODO(ngeoffray): We could make this a map if the code we
176 // generate plays well with a Dart map.
177 var methods = JS('var', '{}');
178 // If there is a method attached to the Dart Object class, use it as
179 // the method to call in case no method is registered for that type.
180 var dartMethod = JS('var', 'Object.getPrototypeOf(#)[#]', new Object(), name);
181 if (dartMethod !== null) JS('void', "#['Object'] = #", methods, dartMethod);
182
183 var bind = JS('var',
184 'function() {'
185 'return #(this, #, #, Array.prototype.slice.call(arguments));'
186 '}',
187 DART_CLOSURE_TO_JS(dynamicBind), name, methods);
188
189 JS('void', '#.methods = #', bind, methods);
190 defineProperty(JS('var', 'Object.prototype'), name, bind);
191 return methods;
192 }
193
194
195 class MetaInfo {
ahe 2012/03/26 14:57:28 Exactly what information is this information about
ngeoffray 2012/03/27 09:17:35 Added a comment.
196 String tag;
197 String tags;
198 Set<String> set;
199 MetaInfo(this.tag, this.tags, this.set);
200 }
201
202 List<MetaInfo> get _dynamicMetadata() {
203 return JS('var', '\$dynamicMetadata');
204 }
205
206 void set _dynamicMetadata(List<String> table) {
207 return JS('void', '\$dynamicMetadata = #', table);
ahe 2012/03/26 14:57:28 Do you really need to return from here?
ngeoffray 2012/03/27 09:17:35 No, return removed.
208 }
209
210 /**
211 * Builds the metadata used for encoding the class hierarchy of native
212 * classes.
ahe 2012/03/26 14:57:28 Add example?
ngeoffray 2012/03/27 09:17:35 Done.
213 */
214 void dynamicSetMetadata(List<List<String>> inputTable) {
215 _dynamicMetadata = <MetaInfo>[];
216 for (int i = 0; i < inputTable.length; i++) {
217 String tag = inputTable[i][0];
218 String tags = inputTable[i][1];
219 Set<String> set = new Set<String>();
220 List<String> tagNames = tags.split('|');
221 for (int j = 0; j < tagNames.length; j++) {
222 set.add(tagNames[j]);
223 }
224 _dynamicMetadata.add(new MetaInfo(tag, tags, set));
225 }
226 }
227
228 var isChecksHelper;
ahe 2012/03/26 14:57:28 What is this for and who initializes it?
ngeoffray 2012/03/27 09:17:35 It's a Js object initialized by the compiler. It w
ahe 2012/03/27 09:42:08 Add TODO?
229
230 // This method will be called for 'is' checks on native types.
231 // It takes the object on which the 'is' check is being done, and the
232 // property name for the type check. The method patches the real
233 // prototype of the object with the value from the Dart object
234 // (see [generateNativeClass]).
235 bool dynamicIsCheck(obj, String typeName) {
236 if (isJsArray(obj)) return false;
237 // Check if the Dart object corresponding to this class has the property.
238 var res = JS('bool', '!!#[#][#]', isChecksHelper, getTypeNameOf(obj),
239 typeName);
240 var proto = JS('var', 'Object.getPrototypeOf(#)', obj);
241 defineProperty(proto, typeName, res);
242 return res;
243 }
OLDNEW
« no previous file with comments | « frog/leg/lib/js_helper.dart ('k') | frog/leg/native_emitter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698