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

Side by Side Diff: lib/declaration.ts

Issue 2394683003: JS Interop Facade generation polish.
Patch Set: more cleanup Created 4 years, 2 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
« no previous file with comments | « lib/base.ts ('k') | lib/facade_converter.ts » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 import * as ts from 'typescript'; 1 import * as ts from 'typescript';
2 2
3 import * as base from './base'; 3 import * as base from './base';
4 import {FacadeConverter} from './facade_converter'; 4 import {FacadeConverter} from './facade_converter';
5 import {Transpiler} from './main'; 5 import {Transpiler} from './main';
6 import {MergedParameter, MergedType} from './merge'; 6 import {MergedParameter, MergedType, MergedTypeParameters} from './merge';
7 7
8 export function isFunctionLikeProperty( 8 export function isFunctionLikeProperty(
9 decl: ts.PropertyDeclaration|ts.ParameterDeclaration, tc: ts.TypeChecker): b oolean { 9 decl: ts.PropertyDeclaration|ts.ParameterDeclaration, tc: ts.TypeChecker): b oolean {
10 if (!decl.type) return false; 10 if (!decl.type) return false;
11 if (decl.name.kind !== ts.SyntaxKind.Identifier) {
12 // No need to promote properties
13 return false;
14 }
11 let name = base.ident(decl.name); 15 let name = base.ident(decl.name);
12 if (name.match(/^on[A-Z]/)) return false; 16 if (name.match(/^on[A-Z]/)) return false;
13 return base.isFunctionType(decl.type, tc); 17 return base.isFunctionType(decl.type, tc);
14 } 18 }
15 19
16 export default class DeclarationTranspiler extends base.TranspilerBase { 20 export default class DeclarationTranspiler extends base.TranspilerBase {
17 private tc: ts.TypeChecker; 21 private tc: ts.TypeChecker;
18 22
19 private moduleStack: string[] = [];
20 private extendsClass: boolean = false; 23 private extendsClass: boolean = false;
21 24
22 static NUM_FAKE_REST_PARAMETERS = 5; 25 static NUM_FAKE_REST_PARAMETERS = 5;
23 26
24 setTypeChecker(tc: ts.TypeChecker) { this.tc = tc; } 27 setTypeChecker(tc: ts.TypeChecker) { this.tc = tc; }
25 setFacadeConverter(fc: FacadeConverter) { this.fc = fc; } 28 setFacadeConverter(fc: FacadeConverter) { this.fc = fc; }
26 29
27 getJsPath(node: ts.Node): string { 30 getJsPath(node: ts.Node, suppressUnneededPaths = true): string {
28 let path = [].concat(this.moduleStack); 31 let path: Array<String> = [];
32 let moduleDecl =
33 base.getAncestor(node, ts.SyntaxKind.ModuleDeclaration) as ts.ModuleDecl aration;
34 while (moduleDecl != null) {
35 path.unshift(moduleDecl.name.text);
36 moduleDecl =
37 base.getAncestor(
38 moduleDecl.parent, ts.SyntaxKind.ModuleDeclaration) as ts.Modu leDeclaration;
39 }
40
29 let classDecl = base.getEnclosingClass(node); 41 let classDecl = base.getEnclosingClass(node);
30 if (classDecl) { 42 if (classDecl) {
31 path.push(classDecl.name.text); 43 if (classDecl.kind === ts.SyntaxKind.InterfaceDeclaration) {
44 let interfaceDecl = classDecl as base.ExtendedInterfaceDeclaration;
45 if (interfaceDecl.classLikeVariableDeclaration) {
46 // We upgrade these variable interface declarations to behave more
47 // like class declarations as we have a valid concrete JS class to
48 // an appropriate class object.
49 return this.getJsPath(interfaceDecl.classLikeVariableDeclaration, fals e);
50 }
51 return '';
52 } else {
53 path.push(classDecl.name.text);
54 }
32 } 55 }
33 56
34 switch (node.kind) { 57 switch (node.kind) {
35 case ts.SyntaxKind.ModuleDeclaration: 58 case ts.SyntaxKind.ModuleDeclaration:
59 path.push((<ts.ModuleDeclaration>node).name.text);
36 break; 60 break;
37 case ts.SyntaxKind.ClassDeclaration: 61 case ts.SyntaxKind.ClassDeclaration:
38 case ts.SyntaxKind.InterfaceDeclaration: 62 case ts.SyntaxKind.InterfaceDeclaration:
39 path.push((<base.ClassLike>node).name.text); 63 // Already handled by call to getEnclosingClass.
40 break; 64 break;
41 case ts.SyntaxKind.EnumDeclaration: 65 case ts.SyntaxKind.EnumDeclaration:
42 path.push((<ts.EnumDeclaration>node).name.text); 66 path.push((<ts.EnumDeclaration>node).name.text);
43 break; 67 break;
44 case ts.SyntaxKind.PropertyDeclaration: 68 case ts.SyntaxKind.PropertyDeclaration:
45 case ts.SyntaxKind.VariableDeclaration: 69 case ts.SyntaxKind.VariableDeclaration:
46 case ts.SyntaxKind.MethodDeclaration: 70 case ts.SyntaxKind.MethodDeclaration:
71 case ts.SyntaxKind.MethodSignature:
47 case ts.SyntaxKind.FunctionDeclaration: 72 case ts.SyntaxKind.FunctionDeclaration:
48 case ts.SyntaxKind.GetAccessor: 73 case ts.SyntaxKind.GetAccessor:
49 case ts.SyntaxKind.SetAccessor: 74 case ts.SyntaxKind.SetAccessor:
50 case ts.SyntaxKind.PropertySignature: 75 case ts.SyntaxKind.PropertySignature:
51 let memberName = base.ident((<base.NamedDeclaration>node).name); 76 let memberName = base.ident((<base.NamedDeclaration>node).name);
52 if (!base.isStatic(node) && classDecl != null) return memberName; 77 if (!base.isStatic(node) && classDecl != null) return memberName;
53 path.push(memberName); 78 path.push(memberName);
54 break; 79 break;
55 default: 80 default:
56 throw 'Internal error. Unexpected node kind:' + node.kind; 81 throw 'Internal error. Unexpected node kind:' + node.kind;
57 } 82 }
58 if (path.length === 1) { 83 if (suppressUnneededPaths && path.length === 1) {
59 // No need to specify the path if is simply the node name. 84 // No need to specify the path if is simply the node name or the escaped v ersion of the node
85 // name.
60 return ''; 86 return '';
61 } 87 }
62 return path.join('.'); 88 return path.join('.');
63 } 89 }
64 90
65 private isAnonymousInterface(node: ts.Node): boolean { 91 private isAnonymousInterface(node: ts.Node): boolean {
66 if (node.kind !== ts.SyntaxKind.InterfaceDeclaration) return false; 92 if (node.kind !== ts.SyntaxKind.InterfaceDeclaration) return false;
67 // This is a bit of a hack but for the purposes of Dart codegen, 93 let interfaceDecl = node as base.ExtendedInterfaceDeclaration;
68 // interfaces with static members or constructors have a known class name 94 // If we were able to associate a variable declaration with the interface de finition then
69 // at least for the purposes of resolving static members. 95 // the interface isn't actually anonymous.
70 // Example case that triggers this case: 96 return !interfaceDecl.classLikeVariableDeclaration;
71 // interface Foo {
72 // bar();
73 // }
74 // declare let Foo: {
75 // new(): Foo,
76 // SOME_STATIC : number;
77 // }
78 return (<ts.InterfaceDeclaration>node).members.every((m: ts.Declaration) => {
79 return m.kind !== ts.SyntaxKind.Constructor && !base.isStatic(m);
80 });
81 } 97 }
82 98
83 maybeEmitJsAnnotation(node: ts.Node) { 99 maybeEmitJsAnnotation(node: ts.Node) {
84 // No need to emit the annotations as an entity outside the code comment 100 // No need to emit the annotations as an entity outside the code comment
85 // will already have the same annotation. 101 // will already have the same annotation.
86 if (this.insideCodeComment) return; 102 if (this.insideCodeComment) return;
87 103
88 if (this.isAnonymousInterface(node)) { 104 if (this.isAnonymousInterface(node)) {
89 this.emit('@anonymous'); 105 this.emit('@anonymous');
90 this.emit('@JS()'); 106 this.emit('@JS()');
91 return; 107 return;
92 } 108 }
93 let name: String = this.getJsPath(node); 109 let name: String = this.getJsPath(node);
94 this.emit('@JS('); 110 this.emit('@JS(');
95 if (name.length > 0) { 111 if (name.length > 0) {
96 this.emit('"' + name + '"'); 112 this.emit('"' + name + '"');
97 } 113 }
98 this.emit(')'); 114 this.emit(')');
99 } 115 }
100 116
101 /** 117 /**
102 * Emit fake constructors to placate the Dart Analyzer for JS Interop classes. 118 * Emit fake constructors to placate the Dart Analyzer for JS Interop classes.
103 */ 119 */
104 maybeEmitFakeConstructors(decl: base.ClassLike) { 120 maybeEmitFakeConstructors(decl: ts.Node) {
105 if (decl.kind === ts.SyntaxKind.ClassDeclaration) { 121 if (decl.kind === ts.SyntaxKind.ClassDeclaration) {
106 // Required to avoid spurious dart errors involving base classes without 122 // Required to avoid spurious dart errors involving base classes without
107 // default constructors. 123 // default constructors.
108 this.emit('// @Ignore\n'); 124 this.emit('// @Ignore\n');
109 this.fc.visitTypeName(decl.name); 125 this.fc.visitTypeName((<ts.ClassDeclaration>decl).name);
110 this.emit('.fakeConstructor$()'); 126 this.emit('.fakeConstructor$()');
111 if (this.extendsClass) { 127 if (this.extendsClass) {
112 // Required to keep the Dart Analyzer happy when a class has subclasses. 128 // Required to keep the Dart Analyzer happy when a class has subclasses.
113 this.emit(': super.fakeConstructor$()'); 129 this.emit(': super.fakeConstructor$()');
114 } 130 }
115 this.emit(';\n'); 131 this.emit(';\n');
116 } 132 }
117 } 133 }
118 134
119 private visitName(name: ts.Node) { 135 private visitName(name: ts.Node) {
120 if (base.getEnclosingClass(name) != null) { 136 if (base.getEnclosingClass(name) != null) {
121 this.visit(name); 137 this.visit(name);
122 return; 138 return;
123 } 139 }
124 // Have to rewrite names in this case as we could have conflicts 140 // Have to rewrite names in this case as we could have conflicts
125 // due to needing to support multiple JS modules in a single JS module 141 // due to needing to support multiple JS modules in a single JS module
126 if (name.kind !== ts.SyntaxKind.Identifier) { 142 if (name.kind !== ts.SyntaxKind.Identifier) {
127 throw 'Internal error: unexpected function name kind:' + name.kind; 143 throw 'Internal error: unexpected function name kind:' + name.kind;
128 } 144 }
129 let entry = this.fc.lookupCustomDartTypeName(<ts.Identifier>name, this.insid eCodeComment); 145 let entry = this.fc.lookupCustomDartTypeName(<ts.Identifier>name);
130 if (entry) { 146 if (entry) {
131 this.emit(entry.name); 147 this.emit(entry.name);
132 return; 148 return;
133 } 149 }
134 150
135 this.visit(name); 151 this.visit(name);
136 } 152 }
137 153
138 private notSimpleBagOfProperties(type: ts.Type): boolean { 154 private notSimpleBagOfProperties(type: ts.Type): boolean {
139 if (this.tc.getSignaturesOfType(type, ts.SignatureKind.Call).length > 0) ret urn true; 155 if (this.tc.getSignaturesOfType(type, ts.SignatureKind.Call).length > 0) ret urn true;
(...skipping 20 matching lines...) Expand all
160 return false; 176 return false;
161 } 177 }
162 178
163 /** 179 /**
164 * Returns whether all members of the class and all base classes 180 * Returns whether all members of the class and all base classes
165 */ 181 */
166 hasOnlyProperties(decl: ts.InterfaceDeclaration, outProperties: ts.PropertyDec laration[]): 182 hasOnlyProperties(decl: ts.InterfaceDeclaration, outProperties: ts.PropertyDec laration[]):
167 boolean { 183 boolean {
168 let type = <ts.InterfaceType>this.tc.getTypeAtLocation(decl); 184 let type = <ts.InterfaceType>this.tc.getTypeAtLocation(decl);
169 185
170 let properties = this.tc.getPropertiesOfType(type); 186 let symbols = this.tc.getPropertiesOfType(type);
171 let baseTypes = this.tc.getBaseTypes(type); 187 let baseTypes = this.tc.getBaseTypes(type);
172 if (this.notSimpleBagOfProperties(type)) return false; 188 if (this.notSimpleBagOfProperties(type)) return false;
173 for (let i = 0; i < baseTypes.length; ++i) { 189 for (let i = 0; i < baseTypes.length; ++i) {
174 let baseType = baseTypes[i]; 190 let baseType = baseTypes[i];
175 if (this.notSimpleBagOfProperties(baseType)) return false; 191 if (this.notSimpleBagOfProperties(baseType)) return false;
176 } 192 }
177 193
194 let properties: ts.Declaration[] = [];
195
196 for (let i = 0; i < symbols.length; ++i) {
197 let symbol = symbols[i];
198 let property = symbol.valueDeclaration;
199 properties.push(property);
200 }
201 return this.hasOnlyPropertiesHelper(properties, outProperties);
202 }
203
204 hasOnlyPropertiesHelper(properties: ts.Declaration[], outProperties: ts.Declar ation[]): boolean {
178 for (let i = 0; i < properties.length; ++i) { 205 for (let i = 0; i < properties.length; ++i) {
179 let symbol = properties[i]; 206 let node = properties[i];
180 let node = symbol.valueDeclaration;
181 switch (node.kind) { 207 switch (node.kind) {
182 case ts.SyntaxKind.PropertyDeclaration: 208 case ts.SyntaxKind.PropertyDeclaration:
183 case ts.SyntaxKind.PropertySignature: 209 case ts.SyntaxKind.PropertySignature:
184 case ts.SyntaxKind.VariableDeclaration: 210 case ts.SyntaxKind.VariableDeclaration:
185 let prop = <ts.PropertyDeclaration>node; 211 let prop = <ts.PropertyDeclaration>node;
186 if (this.promoteFunctionLikeMembers && isFunctionLikeProperty(prop, th is.tc)) { 212 if (this.promoteFunctionLikeMembers && isFunctionLikeProperty(prop, th is.tc)) {
187 return false; 213 return false;
188 } 214 }
189 outProperties.push(prop); 215 outProperties.push(prop);
190 break; 216 break;
191 default: 217 default:
192 return false; 218 return false;
193 } 219 }
194 } 220 }
195 return outProperties.length > 0; 221 return outProperties.length > 0;
196 } 222 }
197 223
198 visitClassBody(decl: base.ClassLike) { 224 visitClassBody(decl: base.ClassLike|ts.TypeLiteralNode, name: ts.Identifier) {
199 let properties: ts.PropertyDeclaration[] = []; 225 let properties: ts.PropertyDeclaration[] = [];
200 let isPropertyBag = decl.kind === ts.SyntaxKind.InterfaceDeclaration && 226 let isPropertyBag = false;
201 this.hasOnlyProperties(<ts.InterfaceDeclaration>decl, properties); 227 if (decl.kind === ts.SyntaxKind.InterfaceDeclaration) {
228 isPropertyBag = this.hasOnlyProperties(<ts.InterfaceDeclaration>decl, prop erties);
229 } else if (decl.kind === ts.SyntaxKind.TypeLiteral) {
230 isPropertyBag = this.hasOnlyPropertiesHelper(decl.members, properties);
231 }
202 this.visitMergingOverloads(decl.members); 232 this.visitMergingOverloads(decl.members);
203 233
204 if (isPropertyBag) { 234 if (isPropertyBag) {
205 this.emit('external factory'); 235 this.emit('external factory');
206 this.fc.visitTypeName(decl.name); 236 this.fc.visitTypeName(name);
207 this.emitNoSpace('({'); 237 this.emitNoSpace('({');
208 for (let i = 0; i < properties.length; i++) { 238 for (let i = 0; i < properties.length; i++) {
209 if (i > 0) this.emitNoSpace(','); 239 if (i > 0) this.emitNoSpace(',');
210 let p = properties[i]; 240 let p = properties[i];
211 this.visit(p.type); 241 this.visit(p.type);
212 this.visit(p.name); 242 this.visit(p.name);
213 } 243 }
214 this.emitNoSpace('});'); 244 this.emitNoSpace('});');
215 } 245 }
216 } 246 }
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 case ts.SyntaxKind.Constructor: 297 case ts.SyntaxKind.Constructor:
268 break; 298 break;
269 case ts.SyntaxKind.ConstructSignature: 299 case ts.SyntaxKind.ConstructSignature:
270 break; 300 break;
271 case ts.SyntaxKind.IndexSignature: 301 case ts.SyntaxKind.IndexSignature:
272 name = '[]'; 302 name = '[]';
273 break; 303 break;
274 case ts.SyntaxKind.ClassDeclaration: 304 case ts.SyntaxKind.ClassDeclaration:
275 case ts.SyntaxKind.InterfaceDeclaration: 305 case ts.SyntaxKind.InterfaceDeclaration:
276 case ts.SyntaxKind.VariableStatement: 306 case ts.SyntaxKind.VariableStatement:
277 orderedGroups.push([node]);
278 return;
279 case ts.SyntaxKind.GetAccessor: 307 case ts.SyntaxKind.GetAccessor:
280 case ts.SyntaxKind.SetAccessor: 308 case ts.SyntaxKind.SetAccessor:
281 case ts.SyntaxKind.SemicolonClassElement: 309 case ts.SyntaxKind.SemicolonClassElement:
282 case ts.SyntaxKind.ModuleDeclaration: 310 case ts.SyntaxKind.ModuleDeclaration:
283 case ts.SyntaxKind.TypeAliasDeclaration: 311 case ts.SyntaxKind.TypeAliasDeclaration:
284 case ts.SyntaxKind.ExportAssignment: 312 case ts.SyntaxKind.ExportAssignment:
313 case ts.SyntaxKind.EnumDeclaration:
314 case ts.SyntaxKind.ImportDeclaration:
315 case ts.SyntaxKind.ExportDeclaration:
316 case ts.SyntaxKind.GlobalModuleExportDeclaration:
317 case ts.SyntaxKind.ImportEqualsDeclaration:
318 case ts.SyntaxKind.EmptyStatement:
319 case ts.SyntaxKind.ExpressionStatement:
320 // Types where we don't need to perform any merging overloads work.
285 orderedGroups.push([node]); 321 orderedGroups.push([node]);
286 return; 322 return;
287 default: 323 default:
288 console.log('Warning: unexpected type... overloads: ' + node.kind + ' ' + node.getText()); 324 // This warning is to make sure we aren't quietly missing a type we ne ed to perform
325 // overload chunking and merging on.
326 console.log(
327 'Warning: unexpected type found looking for overloads: ' + node.ki nd + ' ' +
328 node.getText());
289 orderedGroups.push([node]); 329 orderedGroups.push([node]);
290 return; 330 return;
291 } 331 }
292 let group: Array<ts.Node>; 332 let group: Array<ts.Node>;
293 if (Object.prototype.hasOwnProperty.call(groups, name)) { 333 if (Object.prototype.hasOwnProperty.call(groups, name)) {
294 group = groups[name]; 334 group = groups[name];
295 } else { 335 } else {
296 group = []; 336 group = [];
297 groups[name] = group; 337 groups[name] = group;
298 orderedGroups.push(group); 338 orderedGroups.push(group);
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
337 case ts.SyntaxKind.IndexSignature: 377 case ts.SyntaxKind.IndexSignature:
338 break; 378 break;
339 default: 379 default:
340 throw 'Unexpected kind:' + kind; 380 throw 'Unexpected kind:' + kind;
341 } 381 }
342 let mergedParams = first.parameters.map( 382 let mergedParams = first.parameters.map(
343 (param: ts.ParameterDeclaration) => new MergedParameter(param, this.fc )); 383 (param: ts.ParameterDeclaration) => new MergedParameter(param, this.fc ));
344 let mergedType = new MergedType(this.fc); 384 let mergedType = new MergedType(this.fc);
345 mergedType.merge(first.type); 385 mergedType.merge(first.type);
346 386
387 let mergedTypeParams = new MergedTypeParameters(this.fc);
388 mergedTypeParams.merge(first.typeParameters);
389
347 for (let i = 1; i < group.length; ++i) { 390 for (let i = 1; i < group.length; ++i) {
348 let signature = <ts.SignatureDeclaration>group[i]; 391 let signature = <ts.SignatureDeclaration>group[i];
349 mergedType.merge(signature.type); 392 mergedType.merge(signature.type);
393 mergedTypeParams.merge(signature.typeParameters);
350 let overlap = Math.min(signature.parameters.length, mergedParams.length) ; 394 let overlap = Math.min(signature.parameters.length, mergedParams.length) ;
351 for (let j = 0; j < overlap; ++j) { 395 for (let j = 0; j < overlap; ++j) {
352 mergedParams[j].merge(signature.parameters[j]); 396 mergedParams[j].merge(signature.parameters[j]);
353 } 397 }
354 for (let j = overlap; j < mergedParams.length; ++j) { 398 for (let j = overlap; j < mergedParams.length; ++j) {
355 mergedParams[j].setOptional(); 399 mergedParams[j].setOptional();
356 } 400 }
357 for (let j = mergedParams.length; j < signature.parameters.length; ++j) { 401 for (let j = mergedParams.length; j < signature.parameters.length; ++j) {
358 let param = new MergedParameter(signature.parameters[j], this.fc); 402 let param = new MergedParameter(signature.parameters[j], this.fc);
359 param.setOptional(); 403 param.setOptional();
360 mergedParams.push(param); 404 mergedParams.push(param);
361 } 405 }
362 } 406 }
363 merged.parameters = <ts.NodeArray<ts.ParameterDeclaration>>mergedParams.ma p( 407 merged.parameters = <ts.NodeArray<ts.ParameterDeclaration>>mergedParams.ma p(
364 (p) => p.toParameterDeclaration()); 408 (p) => p.toParameterDeclaration());
365 merged.type = mergedType.toTypeNode(); 409 merged.type = mergedType.toTypeNode();
410 merged.typeParameters = mergedTypeParams.toTypeParameters();
366 411
367 this.fc.visit(merged); 412 this.fc.visit(merged);
368 }); 413 });
369 } 414 }
370 415
371 416
372 constructor( 417 constructor(
373 tr: Transpiler, private fc: FacadeConverter, private enforceUnderscoreConv entions: boolean, 418 tr: Transpiler, private fc: FacadeConverter, private enforceUnderscoreConv entions: boolean,
374 private promoteFunctionLikeMembers: boolean) { 419 private promoteFunctionLikeMembers: boolean) {
375 super(tr); 420 super(tr);
376 } 421 }
377 422
378 visitNode(node: ts.Node): boolean { 423 visitNode(node: ts.Node): boolean {
379 switch (node.kind) { 424 switch (node.kind) {
380 case ts.SyntaxKind.ModuleDeclaration: 425 case ts.SyntaxKind.ModuleDeclaration:
381 let moduleDecl = <ts.ModuleDeclaration>node; 426 let moduleDecl = <ts.ModuleDeclaration>node;
427 if (moduleDecl.name.text.slice(0, 2) === '..') {
428 this.emit(
429 '\n// Library augmentation not allowed by Dart. Ignoring augmentat ion of ' +
430 moduleDecl.name.text + '\n');
431 break;
432 }
382 this.emit('\n// Module ' + moduleDecl.name.text + '\n'); 433 this.emit('\n// Module ' + moduleDecl.name.text + '\n');
383 this.moduleStack.push(moduleDecl.name.text);
384
385 this.visit(moduleDecl.body); 434 this.visit(moduleDecl.body);
386 this.emit('\n// End module ' + moduleDecl.name.text + '\n'); 435 this.emit('\n// End module ' + moduleDecl.name.text + '\n');
387 this.moduleStack.pop();
388 break; 436 break;
389 case ts.SyntaxKind.ExportKeyword: 437 case ts.SyntaxKind.ExportKeyword:
390 // TODO(jacobr): perhaps add a specific Dart annotation to indicate 438 // TODO(jacobr): perhaps add a specific Dart annotation to indicate
391 // exported members or provide a flag to only generate code for exported 439 // exported members or provide a flag to only generate code for exported
392 // members. 440 // members.
393 break; 441 break;
394 case ts.SyntaxKind.EnumDeclaration: { 442 case ts.SyntaxKind.EnumDeclaration: {
395 let decl = <ts.EnumDeclaration>node; 443 let decl = <ts.EnumDeclaration>node;
396 // The only legal modifier for an enum decl is const. 444 // The only legal modifier for an enum decl is const.
397 let isConst = decl.modifiers && (decl.modifiers.flags & ts.NodeFlags.Con st); 445 let isConst = decl.modifiers && (decl.modifiers.flags & ts.NodeFlags.Con st);
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
432 480
433 if (paramDecl.dotDotDotToken) { 481 if (paramDecl.dotDotDotToken) {
434 // Weak support of varargs that works ok if you have 5 of fewer args. 482 // Weak support of varargs that works ok if you have 5 of fewer args.
435 let paramType: ts.TypeNode; 483 let paramType: ts.TypeNode;
436 let type = paramDecl.type; 484 let type = paramDecl.type;
437 if (type) { 485 if (type) {
438 if (type.kind === ts.SyntaxKind.ArrayType) { 486 if (type.kind === ts.SyntaxKind.ArrayType) {
439 let arrayType = <ts.ArrayTypeNode>type; 487 let arrayType = <ts.ArrayTypeNode>type;
440 paramType = arrayType.elementType; 488 paramType = arrayType.elementType;
441 } else if (type.kind !== ts.SyntaxKind.AnyKeyword) { 489 } else if (type.kind !== ts.SyntaxKind.AnyKeyword) {
442 throw 'Unexpected type for varargs: ' + type.kind; 490 console.log('Warning: falling back to dynamic for varArgs type: ' + type.getText());
443 } 491 }
444 } 492 }
445 493
446 for (let i = 1; i <= DeclarationTranspiler.NUM_FAKE_REST_PARAMETERS; + +i) { 494 for (let i = 1; i <= DeclarationTranspiler.NUM_FAKE_REST_PARAMETERS; + +i) {
447 if (i > 1) { 495 if (i > 1) {
448 this.emitNoSpace(','); 496 this.emitNoSpace(',');
449 } 497 }
450 this.visit(paramType); 498 this.visit(paramType);
451 this.emit(base.ident(paramDecl.name) + i); 499 this.emit(base.ident(paramDecl.name) + i);
452 } 500 }
(...skipping 17 matching lines...) Expand all
470 if (paramDecl.name.kind !== ts.SyntaxKind.Identifier) { 518 if (paramDecl.name.kind !== ts.SyntaxKind.Identifier) {
471 throw 'Unsupported parameter name kind: ' + paramDecl.name.kind; 519 throw 'Unsupported parameter name kind: ' + paramDecl.name.kind;
472 } 520 }
473 this.visit(paramDecl.type); 521 this.visit(paramDecl.type);
474 this.visit(paramDecl.name); 522 this.visit(paramDecl.name);
475 } break; 523 } break;
476 case ts.SyntaxKind.EnumMember: { 524 case ts.SyntaxKind.EnumMember: {
477 let member = <ts.EnumMember>node; 525 let member = <ts.EnumMember>node;
478 this.visit(member.name); 526 this.visit(member.name);
479 } break; 527 } break;
528 case ts.SyntaxKind.SourceFile:
529 let sourceFile = node as ts.SourceFile;
530 this.visitMergingOverloads(sourceFile.statements);
531 break;
480 case ts.SyntaxKind.ModuleBlock: { 532 case ts.SyntaxKind.ModuleBlock: {
481 let block = <ts.ModuleBlock>node; 533 let block = <ts.ModuleBlock>node;
482 this.visitMergingOverloads(block.statements); 534 this.visitMergingOverloads(block.statements);
483 } break; 535 } break;
484 case ts.SyntaxKind.VariableDeclarationList: { 536 case ts.SyntaxKind.VariableDeclarationList: {
485 // We have to handle variable declaration lists differently in the case 537 // We have to handle variable declaration lists differently in the case
486 // of JS interop because Dart does not support external variables. 538 // of JS interop because Dart does not support external variables.
487 let varDeclList = <ts.VariableDeclarationList>node; 539 let varDeclList = <ts.VariableDeclarationList>node;
488 this.visitList(varDeclList.declarations, ';'); 540 this.visitList(varDeclList.declarations, ';');
489 } break; 541 } break;
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
523 this.visitParameters(fn.parameters); 575 this.visitParameters(fn.parameters);
524 this.emitNoSpace(';'); 576 this.emitNoSpace(';');
525 } break; 577 } break;
526 case ts.SyntaxKind.IndexSignature: 578 case ts.SyntaxKind.IndexSignature:
527 this.emit('/* Index signature is not yet supported by JavaScript interop . */\n'); 579 this.emit('/* Index signature is not yet supported by JavaScript interop . */\n');
528 break; 580 break;
529 case ts.SyntaxKind.ExportAssignment: 581 case ts.SyntaxKind.ExportAssignment:
530 // let exportAssignment = <ts.ExportAssignment>node; 582 // let exportAssignment = <ts.ExportAssignment>node;
531 this.emit('/* WARNING: export assignment not yet supported. */\n'); 583 this.emit('/* WARNING: export assignment not yet supported. */\n');
532 break; 584 break;
533 case ts.SyntaxKind.TypeAliasDeclaration: 585 case ts.SyntaxKind.TypeAliasDeclaration: {
534 // Dart does not provide special syntax for definning type alais 586 // Object literal type alias declarations are equivalent to interface de clarations.
535 // declarations so we do not emit anything here and resolve alaises 587 let alias = <ts.TypeAliasDeclaration>node;
536 // to their original types at each usage site. 588 let type = alias.type;
537 break; 589 if (type.kind === ts.SyntaxKind.TypeLiteral) {
590 let literal = <ts.TypeLiteralNode>type;
591 this.emit('@anonymous\n@JS()\n');
592 this.visitClassLikeHelper(
593 'abstract class', literal, alias.name, alias.typeParameters, null) ;
594 } else if (type.kind === ts.SyntaxKind.FunctionType) {
595 // Function type alias definitions are equivalent to dart typedefs.
596 this.visitFunctionTypedefInterface(
597 base.ident(alias.name), type as ts.FunctionTypeNode, alias.typePar ameters);
598 } else {
599 this.enterCodeComment();
600 this.emit(alias.getText());
601 this.exitCodeComment();
602 this.emit('\n');
603 }
604 // We ignore other type alias declarations as Dart doesn't have a corres ponding feature yet.
605 } break;
538 case ts.SyntaxKind.ClassDeclaration: 606 case ts.SyntaxKind.ClassDeclaration:
539 case ts.SyntaxKind.InterfaceDeclaration: { 607 case ts.SyntaxKind.InterfaceDeclaration: {
540 this.extendsClass = false; 608 this.extendsClass = false;
541 let classDecl = <ts.ClassDeclaration|ts.InterfaceDeclaration>node; 609 let classDecl = <ts.ClassDeclaration|ts.InterfaceDeclaration>node;
542 let isInterface = node.kind === ts.SyntaxKind.InterfaceDeclaration; 610 let isInterface = node.kind === ts.SyntaxKind.InterfaceDeclaration;
543 if (isInterface && 611 if (isInterface &&
544 base.isFunctionTypedefLikeInterface(classDecl as ts.InterfaceDeclara tion)) { 612 base.isFunctionTypedefLikeInterface(classDecl as ts.InterfaceDeclara tion)) {
545 let member = <ts.CallSignatureDeclaration>classDecl.members[0]; 613 let member = <ts.CallSignatureDeclaration>classDecl.members[0];
546 this.visitFunctionTypedefInterface(classDecl.name.text, member, classD ecl.typeParameters); 614 this.visitFunctionTypedefInterface(classDecl.name.text, member, classD ecl.typeParameters);
547 break; 615 break;
548 } 616 }
549 617
550 let customName = this.fc.lookupCustomDartTypeName(classDecl.name, this.i nsideCodeComment); 618 let customName = this.fc.lookupCustomDartTypeName(classDecl.name);
551 if (customName && !customName.keep) { 619 if (customName && !customName.keep) {
552 this.emit('\n/* Skipping class ' + base.ident(classDecl.name) + '*/\n' ); 620 this.emit('\n/* Skipping class ' + base.ident(classDecl.name) + '*/\n' );
553 break; 621 break;
554 } 622 }
555 this.maybeEmitJsAnnotation(node); 623 this.maybeEmitJsAnnotation(node);
556 624
557 if (isInterface || 625 if (isInterface ||
558 (classDecl.modifiers && (classDecl.modifiers.flags & ts.NodeFlags.Ab stract))) { 626 (classDecl.modifiers && (classDecl.modifiers.flags & ts.NodeFlags.Ab stract))) {
559 this.visitClassLike('abstract class', classDecl); 627 this.visitClassLike('abstract class', classDecl);
560 } else { 628 } else {
(...skipping 18 matching lines...) Expand all
579 let exprWithTypeArgs = <ts.ExpressionWithTypeArguments>node; 647 let exprWithTypeArgs = <ts.ExpressionWithTypeArguments>node;
580 this.visit(exprWithTypeArgs.expression); 648 this.visit(exprWithTypeArgs.expression);
581 this.maybeVisitTypeArguments(exprWithTypeArgs); 649 this.maybeVisitTypeArguments(exprWithTypeArgs);
582 } break; 650 } break;
583 case ts.SyntaxKind.Constructor: 651 case ts.SyntaxKind.Constructor:
584 case ts.SyntaxKind.ConstructSignature: { 652 case ts.SyntaxKind.ConstructSignature: {
585 let ctorDecl = <ts.ConstructorDeclaration>node; 653 let ctorDecl = <ts.ConstructorDeclaration>node;
586 // Find containing class name. 654 // Find containing class name.
587 let classDecl = base.getEnclosingClass(ctorDecl); 655 let classDecl = base.getEnclosingClass(ctorDecl);
588 if (!classDecl) this.reportError(ctorDecl, 'cannot find outer class node '); 656 if (!classDecl) this.reportError(ctorDecl, 'cannot find outer class node ');
657 let isAnonymous = this.isAnonymousInterface(classDecl);
658 if (isAnonymous) {
659 this.emit('// Constructors on anonymous interfaces are not yet support ed.\n');
660 this.enterCodeComment();
661 }
589 this.visitDeclarationMetadata(ctorDecl); 662 this.visitDeclarationMetadata(ctorDecl);
590 this.fc.visitTypeName(classDecl.name); 663 this.fc.visitTypeName(classDecl.name);
591 this.visitParameters(ctorDecl.parameters); 664 this.visitParameters(ctorDecl.parameters);
592 this.emitNoSpace(';'); 665 this.emitNoSpace(';');
666 if (isAnonymous) {
667 this.exitCodeComment();
668 this.emit('\n');
669 }
593 } break; 670 } break;
594 case ts.SyntaxKind.PropertyDeclaration: 671 case ts.SyntaxKind.PropertyDeclaration:
595 this.visitProperty(<ts.PropertyDeclaration>node); 672 this.visitProperty(<ts.PropertyDeclaration>node);
596 break; 673 break;
597 case ts.SyntaxKind.SemicolonClassElement: 674 case ts.SyntaxKind.SemicolonClassElement:
598 // No-op, don't emit useless declarations. 675 // No-op, don't emit useless declarations.
599 break; 676 break;
600 case ts.SyntaxKind.MethodDeclaration: 677 case ts.SyntaxKind.MethodDeclaration:
601 this.visitDeclarationMetadata(<ts.MethodDeclaration>node); 678 this.visitDeclarationMetadata(<ts.MethodDeclaration>node);
602 this.visitFunctionLike(<ts.MethodDeclaration>node); 679 this.visitFunctionLike(<ts.MethodDeclaration>node);
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
677 } 754 }
678 this.fc.visitTypeName(<ts.Identifier>name); 755 this.fc.visitTypeName(<ts.Identifier>name);
679 } 756 }
680 757
681 if (fn.typeParameters) { 758 if (fn.typeParameters) {
682 let insideComment = this.insideCodeComment; 759 let insideComment = this.insideCodeComment;
683 if (!insideComment) { 760 if (!insideComment) {
684 this.enterCodeComment(); 761 this.enterCodeComment();
685 } 762 }
686 this.emitNoSpace('<'); 763 this.emitNoSpace('<');
687 // Emit the names literally instead of visiting, otherwise they will be replaced with the 764 this.enterTypeArguments();
688 // comment hack themselves. 765 this.visitList(fn.typeParameters);
689 // TODO(jacobr): we can use the regular type parameter visiting pattern 766 this.exitTypeArguments();
690 // now that we properly track whether we are inside a comment.
691 this.emitNoSpace(fn.typeParameters.map(p => base.ident(p.name)).join(', '));
692 this.emitNoSpace('>'); 767 this.emitNoSpace('>');
693 if (!insideComment) { 768 if (!insideComment) {
694 this.exitCodeComment(); 769 this.exitCodeComment();
695 } 770 }
696 } 771 }
697 // Dart does not even allow the parens of an empty param list on getter 772 // Dart does not even allow the parens of an empty param list on getter
698 if (accessor !== 'get') { 773 if (accessor !== 'get') {
699 this.visitParameters(fn.parameters); 774 this.visitParameters(fn.parameters);
700 } else { 775 } else {
701 if (fn.parameters && fn.parameters.length > 0) { 776 if (fn.parameters && fn.parameters.length > 0) {
(...skipping 29 matching lines...) Expand all
731 this.emit('set'); 806 this.emit('set');
732 this.visitName(decl.name); 807 this.visitName(decl.name);
733 this.emitNoSpace('('); 808 this.emitNoSpace('(');
734 this.visit(decl.type); 809 this.visit(decl.type);
735 this.emit('v'); 810 this.emit('v');
736 this.emitNoSpace(')'); 811 this.emitNoSpace(')');
737 this.emitNoSpace(';'); 812 this.emitNoSpace(';');
738 } 813 }
739 814
740 private visitClassLike(keyword: string, decl: base.ClassLike) { 815 private visitClassLike(keyword: string, decl: base.ClassLike) {
816 return this.visitClassLikeHelper(
817 keyword, decl, decl.name, decl.typeParameters, decl.heritageClauses);
818 }
819
820 private visitClassLikeHelper(
821 keyword: string, decl: base.ClassLike|ts.TypeLiteralNode, name: ts.Identif ier,
822 typeParameters: ts.NodeArray<ts.TypeParameterDeclaration>,
823 heritageClauses: ts.NodeArray<ts.HeritageClause>) {
741 this.emit(keyword); 824 this.emit(keyword);
742 this.fc.visitTypeName(decl.name); 825 this.fc.visitTypeName(name);
743 if (decl.typeParameters) { 826 if (typeParameters) {
744 this.emit('<'); 827 this.emit('<');
745 this.visitList(decl.typeParameters); 828 this.enterTypeArguments();
829 this.visitList(typeParameters);
830 this.exitTypeArguments();
746 this.emit('>'); 831 this.emit('>');
747 } 832 }
748 833
749 this.visitEachIfPresent(decl.heritageClauses); 834 this.visitEachIfPresent(heritageClauses);
750 this.emit('{'); 835 this.emit('{');
751 836
752 this.maybeEmitFakeConstructors(decl); 837 this.maybeEmitFakeConstructors(decl);
753 838
754 // Synthesize explicit properties for ctor with 'property parameters' 839 // Synthesize explicit properties for ctor with 'property parameters'
755 let synthesizePropertyParam = (param: ts.ParameterDeclaration) => { 840 let synthesizePropertyParam = (param: ts.ParameterDeclaration) => {
756 if (this.hasFlag(param.modifiers, ts.NodeFlags.Public) || 841 if (this.hasFlag(param.modifiers, ts.NodeFlags.Public) ||
757 this.hasFlag(param.modifiers, ts.NodeFlags.Private) || 842 this.hasFlag(param.modifiers, ts.NodeFlags.Private) ||
758 this.hasFlag(param.modifiers, ts.NodeFlags.Protected)) { 843 this.hasFlag(param.modifiers, ts.NodeFlags.Protected)) {
759 // TODO: we should enforce the underscore prefix on privates 844 // TODO: we should enforce the underscore prefix on privates
760 this.visitProperty(param, true); 845 this.visitProperty(param, true);
761 } 846 }
762 }; 847 };
763 (decl.members as ts.NodeArray<ts.Declaration>) 848 (decl.members as ts.NodeArray<ts.Declaration>)
764 .filter(base.isConstructor) 849 .filter(base.isConstructor)
765 .forEach( 850 .forEach(
766 (ctor) => 851 (ctor) =>
767 (<ts.ConstructorDeclaration>ctor).parameters.forEach(synthesizeP ropertyParam)); 852 (<ts.ConstructorDeclaration>ctor).parameters.forEach(synthesizeP ropertyParam));
768 853
769 this.visitClassBody(decl); 854 this.visitClassBody(decl, name);
770 this.emit('}'); 855 this.emit('}');
771 } 856 }
772 857
773 private visitDeclarationMetadata(decl: ts.Declaration) { 858 private visitDeclarationMetadata(decl: ts.Declaration) {
774 this.visitEachIfPresent(decl.modifiers); 859 this.visitEachIfPresent(decl.modifiers);
775 860
776 switch (decl.kind) { 861 switch (decl.kind) {
777 case ts.SyntaxKind.Constructor: 862 case ts.SyntaxKind.Constructor:
778 case ts.SyntaxKind.ConstructSignature: 863 case ts.SyntaxKind.ConstructSignature:
779 this.emit('external factory'); 864 this.emit('external factory');
(...skipping 14 matching lines...) Expand all
794 default: 879 default:
795 throw 'Unexpected declaration kind:' + decl.kind; 880 throw 'Unexpected declaration kind:' + decl.kind;
796 } 881 }
797 } 882 }
798 883
799 /** 884 /**
800 * Handles a function typedef-like interface, i.e. an interface that only decl ares a single 885 * Handles a function typedef-like interface, i.e. an interface that only decl ares a single
801 * call signature, by translating to a Dart `typedef`. 886 * call signature, by translating to a Dart `typedef`.
802 */ 887 */
803 private visitFunctionTypedefInterface( 888 private visitFunctionTypedefInterface(
804 name: string, signature: ts.CallSignatureDeclaration, 889 name: string, signature: ts.SignatureDeclaration,
805 typeParameters: ts.NodeArray<ts.TypeParameterDeclaration>) { 890 typeParameters: ts.NodeArray<ts.TypeParameterDeclaration>) {
806 this.emit('typedef'); 891 this.emit('typedef');
807 if (signature.type) { 892 if (signature.type) {
808 this.visit(signature.type); 893 this.visit(signature.type);
809 } 894 }
810 this.emit(name); 895 this.emit(name);
811 if (typeParameters) { 896 if (typeParameters) {
812 this.emitNoSpace('<'); 897 this.emitNoSpace('<');
898 this.enterTypeArguments();
813 this.visitList(typeParameters); 899 this.visitList(typeParameters);
900 this.exitTypeArguments();
814 this.emitNoSpace('>'); 901 this.emitNoSpace('>');
815 } 902 }
816 this.visitParameters(signature.parameters); 903 this.visitParameters(signature.parameters);
817 this.emitNoSpace(';'); 904 this.emitNoSpace(';');
818 } 905 }
819 } 906 }
OLDNEW
« no previous file with comments | « lib/base.ts ('k') | lib/facade_converter.ts » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698