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

Side by Side Diff: client/html/scripts/html-diff.dart

Issue 8548019: Add a script for determining which DOM methods correspond to which HTML methods. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: More code review changes Created 9 years, 1 month 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
OLDNEW
(Empty)
1 // Copyright (c) 2011, 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 /**
6 * A script to assist in documenting the difference between the dart:html API
7 * and the old DOM API.
8 */
9 #library('renames');
10
11 #import('../../../frog/lang.dart');
12 #import('../../../frog/file_system_node.dart');
13 #import('../../../frog/file_system.dart');
14 #import('../../../utils/dartdoc/dartdoc.dart');
15
16 void main() {
17 HtmlDiff.initWorld('../../frog', new NodeFileSystem());
18 initializeDartDoc();
19 var diff = new HtmlDiff();
20 diff.run();
21
22 diff.domToDart.forEach((domMember, htmlMember) {
23 if (domMember.name != htmlMember.name) {
24 var domTypeName = domMember.declaringType.name;
25 var htmlTypeName = htmlMember.declaringType.name.
26 replaceFirst('WrappingImplementation', '');
27 var htmlName = '$htmlTypeName.${htmlMember.name}';
28 if (htmlMember.isConstructor || htmlMember.isFactory) {
29 final separator = htmlMember.name == '' ? '' : '.';
30 htmlName = 'new $htmlTypeName$separator${htmlMember.name}';
31 }
32 print('$domTypeName.${domMember.name} -> ${htmlName}');
33 }
34 });
35
36 for (var type in world.dom.types.getValues()) {
37 if (type.name == null) continue;
38 if (type.definition is FunctionTypeDefinition) continue;
39 for (var member in type.members.getValues()) {
40 if (!member.isPrivate && member.name != 'typeName' &&
41 !diff.domToDart.containsKey(member) &&
42 (member is MethodMember || member is PropertyMember)) {
43 print('No dart:html wrapper for ${type.name}.${member.name}');
44 }
45 }
46 }
47 }
48
49 class HtmlDiff {
50 final Map<Member, Member> domToDart;
51
52 static void initWorld(String frogDir, FileSystem files) {
53 parseOptions(frogDir, [] /* args */, files);
54 initializeWorld(files);
55 world.processScript('dart:html');
56 world.resolveAll();
57 }
58
59 HtmlDiff() : domToDart = <Member, Member>{};
60
61 void run() {
62 final htmlLib = world.libraries['dart:html'];
63 for (var htmlType in htmlLib.types.getValues()) {
64 final domType = htmlToDomType(htmlType);
65 final members = new List.from(htmlType.members.getValues());
66 members.addAll(htmlType.constructors.getValues());
67 htmlType.factories.forEach((f) => members.add(f));
68 for (var member in members) {
69 htmlToDomMembers(member, domType).forEach((m) => domToDart[m] = member);
70 }
71 }
72 }
73
74 Type htmlToDomType(Type htmlType) {
75 if (htmlType.name == null) return;
76 final tags = _getTags(findComment(htmlType.span));
77
78 if (tags.containsKey('domName')) {
79 final domName = tags['domName'];
80 if (domName == 'none') return;
81 final domType = world.dom.types[domName];
82 if (domType == null) print('Warning: no dart:dom type named $domName');
83 return domType;
84 } else {
85 if (!htmlType.name.endsWith('WrappingImplementation')) return;
86 final domName = htmlType.name.replaceFirst('WrappingImplementation', '');
87 var domType = world.dom.types[domName];
88 if (domType == null && domName.endsWith('Element')) {
89 domType = world.dom.types['HTML$domName'];
90 }
91 if (domType == null) domType = world.dom.types['WebKit$domName'];
92 if (domType == null) {
93 print('Warning: no dart:dom type matches dart:html ${htmlType.name}');
94 }
95 return domType;
96 }
97 }
98
99 Set<Member> htmlToDomMembers(Member htmlMember, Type domType) {
100 if (htmlMember.isPrivate) return new Set();
101 if (htmlMember is MethodMember) {
102 final tags = _getTags(findComment(htmlMember.span));
103 if (tags.containsKey('domName')) {
104 final domName = tags['domName'];
105 if (domName == 'none') return new Set();
106 return _membersFromName(domName, domType, world.dom);
107 }
108 if (domType == null) return new Set();
109 if (htmlMember.definition == null) return new Set();
110 if (htmlMember.name == 'get\$on') {
111 final members = _members(domType.members['addEventListener']);
112 members.addAll(_members(domType.members['dispatchEvent']));
113 members.addAll(_members(domType.members['removeEventListener']));
114 return members;
115 }
116 if (htmlMember.isFactory && htmlMember.name == '' &&
117 domType.name.endsWith('Event')) {
118 return _members(domType.members['init${domType.name}']);
119 }
120 return _members(_getDomMember(htmlMember.definition.body, domType));
121 } else if (htmlMember is PropertyMember) {
122 final members = new Set();
123 if (htmlMember.getter != null) {
124 members.addAll(htmlToDomMembers(htmlMember.getter, domType));
125 }
126 if (htmlMember.setter != null) {
127 members.addAll(htmlToDomMembers(htmlMember.setter, domType));
128 }
129 return members;
130 } else {
131 return new Set();
132 }
133 }
134
135 Set<Member> _membersFromName(String name, Type defaultType, Library library) {
136 if (!name.contains('.', 0)) {
137 if (defaultType == null) {
138 print('Warning: no default type for ${name}');
139 return new Set();
140 }
141 final member = defaultType.members[name];
142 if (member == null) {
143 print('Warning: no member ${defaultType.name}.${name}');
144 }
145 return _members(member);
146 }
147
148 final splitName = name.split('.');
149 if (splitName.length != 2) {
150 print('Warning: invalid member name ${name}');
151 return new Set();
152 }
153 final type = library.types[splitName[0]];
154 if (type == null) {
155 print('Warning: no ${library.name} type named ${splitName[0]}');
156 return new Set();
157 }
158 final member = type.members[splitName[1]];
159 if (member == null) {
160 print('Warning: no member named $name');
161 }
162 return _members(member);
163 }
164
165 Set<Member> _members(Member m) => m == null ? new Set() : new Set.from([m]);
166
167 Member _getDomMember(Statement stmt, Type domType) {
168 if (stmt is BlockStatement) {
169 final body = stmt.body.filter((s) => !_ignorableStatement(s));
170 if (body.length != 1) return;
171 return _getDomMember(stmt.body[0], domType);
172 } else if (stmt is ReturnStatement) {
173 return _domMemberFromExpression(stmt.value, domType);
174 } else if (stmt is ExpressionStatement) {
175 return _domMemberFromExpression(stmt.body, domType);
176 } else if (stmt is TryStatement) {
177 return _getDomMember(stmt.body, domType);
178 } else if (stmt is IfStatement) {
179 final trueMember = _getDomMember(stmt.trueBranch, domType);
180 final falseMember = _getDomMember(stmt.falseBranch, domType);
181 if (stmt.falseBranch == null || trueMember == falseMember) {
182 return trueMember;
183 }
184 }
185 }
186
187 /**
188 * Whether a statement can be ignored for the purpose of determining the DOM
189 * name of the enclosing method. The Webkit-to-Dart conversion process leaves
190 * behind various throws and returns that we want to ignore.
191 */
192 bool _ignorableStatement(Statement stmt) {
193 if (stmt is BlockStatement) {
194 return Collections.every(stmt.body, (s) => _ignorableStatement(s));
195 } else if (stmt is TryStatement) {
196 return _ignorableStatement(stmt.body);
197 } else if (stmt is IfStatement) {
198 return _ignorableStatement(stmt.trueBranch) &&
199 _ignorableStatement(stmt.falseBranch);
200 } else if (stmt is ReturnStatement) {
201 return stmt.value == null || stmt.value is ThisExpression;
202 } else {
203 return stmt is ThrowStatement;
204 }
205 }
206
207 Member _domMemberFromExpression(Expression expr, Type domType) {
208 if (expr is BinaryExpression && expr.op.kind == TokenKind.ASSIGN) {
209 return _domMemberFromExpression(expr.x, domType);
210 } else if (expr is CallExpression) {
211 if (expr.target is DotExpression && expr.target.self is VarExpression &&
212 expr.target.self.name.name == 'LevelDom' &&
213 (expr.target.name.name.startsWith('wrap') ||
214 expr.target.name.name == 'unwrap')) {
215 return _domMemberFromExpression(expr.arguments[0].value, domType);
216 }
217 return _domMemberFromExpression(expr.target, domType);
218 } else if (expr is DotExpression) {
219 if (expr.self is NewExpression && expr.name.name == '_wrap' &&
220 expr.self.arguments.length == 1) {
221 return _domMemberFromExpression(expr.self.arguments[0].value, domType);
222 } else if (expr.self is VarExpression && expr.self.name.name == '_ptr') {
223 return domType.members[expr.name.name];
224 }
225 final base = _domMemberFromExpression(expr.self, domType);
226 if (base != null && base.returnType != null) {
227 return base.returnType.members[expr.name.name];
228 }
229 } else if (expr is NewExpression && expr.arguments.length == 1) {
230 return _domMemberFromExpression(expr.arguments[0].value, domType);
231 } else {
232 return null;
233 }
234 }
235
236 Map<String, String> _getTags(String comment) {
237 if (comment == null) return const <String, String>{};
238 final re = new RegExp("@([a-zA-Z]+) ([^;]+)(?:;|\$)");
239 final tags = <String, String>{};
240 for (var m in re.allMatches(comment.trim())) {
241 tags[m[1]] = m[2];
242 }
243 return tags;
244 }
245 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698