@@ -28,6 +28,19 @@ var $kindString = 24;
28
28
var $kindStruct = 25;
29
29
var $kindUnsafePointer = 26;
30
30
31
+ var $methodSynthesizers = [];
32
+ var $addMethodSynthesizer = function(f) {
33
+ if ($methodSynthesizers === null) {
34
+ f();
35
+ return;
36
+ }
37
+ $methodSynthesizers.push(f);
38
+ };
39
+ var $synthesizeMethods = function() {
40
+ $methodSynthesizers.forEach(function(f) { f(); });
41
+ $methodSynthesizers = null;
42
+ };
43
+
31
44
var $newType = function(size, kind, string, name, pkg, constructor) {
32
45
var typ;
33
46
switch(kind) {
@@ -225,29 +238,31 @@ var $newType = function(size, kind, string, name, pkg, constructor) {
225
238
typ.ptr.nil = Object.create(constructor.prototype, properties);
226
239
typ.ptr.nil.$val = typ.ptr.nil;
227
240
/* methods for embedded fields */
228
- var forwardMethod = function(target, m, f) {
229
- if (target.prototype[m.prop] !== undefined) { return; }
230
- target.prototype[m.prop] = function() {
231
- var v = this.$val[f.prop];
232
- if (f.typ === $js.Object) {
233
- v = new $js.container.ptr(v);
234
- }
235
- if (v.$val === undefined) {
236
- v = new f.typ(v);
237
- }
238
- return v[m.prop].apply(v, arguments);
241
+ $addMethodSynthesizer(function() {
242
+ var synthesizeMethod = function(target, m, f) {
243
+ if (target.prototype[m.prop] !== undefined) { return; }
244
+ target.prototype[m.prop] = function() {
245
+ var v = this.$val[f.prop];
246
+ if (f.typ === $js.Object) {
247
+ v = new $js.container.ptr(v);
248
+ }
249
+ if (v.$val === undefined) {
250
+ v = new f.typ(v);
251
+ }
252
+ return v[m.prop].apply(v, arguments);
253
+ };
239
254
};
240
- };
241
- fields.forEach(function(f ) {
242
- if (f.name === "" ) {
243
- f.typ.methods.forEach(function(m) {
244
- forwardMethod (typ, m, f);
245
- forwardMethod(typ.ptr, m, f );
246
- });
247
- $ptrType(f. typ).methods.forEach(function(m) {
248
- forwardMethod(typ.ptr, m, f );
249
- });
250
- }
255
+ fields.forEach(function(f) {
256
+ if (f.name === "" ) {
257
+ $methodSet (f.typ).forEach(function(m ) {
258
+ synthesizeMethod(typ, m, f);
259
+ synthesizeMethod (typ.ptr , m, f);
260
+ } );
261
+ $methodSet($ptrType(f.typ)).forEach(function(m) {
262
+ synthesizeMethod( typ.ptr, m, f);
263
+ } );
264
+ }
265
+ });
251
266
});
252
267
};
253
268
break;
@@ -331,11 +346,77 @@ var $newType = function(size, kind, string, name, pkg, constructor) {
331
346
typ.typeName = name;
332
347
typ.pkg = pkg;
333
348
typ.methods = [];
349
+ typ.methodSetCache = null;
334
350
typ.comparable = true;
335
- var rt = null;
336
351
return typ;
337
352
};
338
353
354
+ var $methodSet = function(typ) {
355
+ if (typ.methodSetCache !== null) {
356
+ return typ.methodSetCache;
357
+ }
358
+ var base = {};
359
+
360
+ var isPtr = (typ.kind === $kindPtr);
361
+ if (isPtr && typ.elem.kind === $kindInterface) {
362
+ typ.methodSetCache = [];
363
+ return [];
364
+ }
365
+
366
+ var current = [{typ: isPtr ? typ.elem : typ, indirect: isPtr}];
367
+
368
+ var seen = {};
369
+
370
+ while (current.length > 0) {
371
+ var next = [];
372
+ var mset = [];
373
+
374
+ current.forEach(function(e) {
375
+ if (seen[e.typ.string]) {
376
+ return;
377
+ }
378
+ seen[e.typ.string] = true;
379
+
380
+ if(e.typ.typeName !== "") {
381
+ mset = mset.concat(e.typ.methods);
382
+ if (e.indirect) {
383
+ mset = mset.concat($ptrType(e.typ).methods);
384
+ }
385
+ }
386
+
387
+ switch (e.typ.kind) {
388
+ case $kindStruct:
389
+ e.typ.fields.forEach(function(f) {
390
+ if (f.name === "") {
391
+ var fTyp = f.typ;
392
+ var fIsPtr = (fTyp.kind === $kindPtr);
393
+ next.push({typ: fIsPtr ? fTyp.elem : fTyp, indirect: e.indirect || fIsPtr});
394
+ }
395
+ });
396
+ break;
397
+
398
+ case $kindInterface:
399
+ mset = mset.concat(e.typ.methods);
400
+ break;
401
+ }
402
+ });
403
+
404
+ mset.forEach(function(m) {
405
+ if (base[m.name] === undefined) {
406
+ base[m.name] = m;
407
+ }
408
+ });
409
+
410
+ current = next;
411
+ }
412
+
413
+ typ.methodSetCache = [];
414
+ Object.keys(base).sort().forEach(function(name) {
415
+ typ.methodSetCache.push(base[name]);
416
+ });
417
+ return typ.methodSetCache;
418
+ };
419
+
339
420
var $Bool = $newType( 1, $kindBool, "bool", "bool", "", null);
340
421
var $Int = $newType( 4, $kindInt, "int", "int", "", null);
341
422
var $Int8 = $newType( 1, $kindInt8, "int8", "int8", "", null);
@@ -355,19 +436,6 @@ var $Complex128 = $newType(16, $kindComplex128, "complex128", "complex
355
436
var $String = $newType( 8, $kindString, "string", "string", "", null);
356
437
var $UnsafePointer = $newType( 4, $kindUnsafePointer, "unsafe.Pointer", "Pointer", "", null);
357
438
358
- var $anonTypeInits = [];
359
- var $addAnonTypeInit = function(f) {
360
- if ($anonTypeInits === null) {
361
- f();
362
- return;
363
- }
364
- $anonTypeInits.push(f);
365
- };
366
- var $initAnonTypes = function() {
367
- $anonTypeInits.forEach(function(f) { f(); });
368
- $anonTypeInits = null;
369
- };
370
-
371
439
var $nativeArray = function(elemKind) {
372
440
switch (elemKind) {
373
441
case $kindInt:
@@ -410,7 +478,7 @@ var $arrayType = function(elem, len) {
410
478
if (typ === undefined) {
411
479
typ = $newType(12, $kindArray, string, "", "", null);
412
480
$arrayTypes[string] = typ;
413
- $addAnonTypeInit(function() { typ.init(elem, len); } );
481
+ typ.init(elem, len);
414
482
}
415
483
return typ;
416
484
};
@@ -422,7 +490,7 @@ var $chanType = function(elem, sendOnly, recvOnly) {
422
490
if (typ === undefined) {
423
491
typ = $newType(4, $kindChan, string, "", "", null);
424
492
elem[field] = typ;
425
- $addAnonTypeInit(function() { typ.init(elem, sendOnly, recvOnly); } );
493
+ typ.init(elem, sendOnly, recvOnly);
426
494
}
427
495
return typ;
428
496
};
@@ -443,7 +511,7 @@ var $funcType = function(params, results, variadic) {
443
511
if (typ === undefined) {
444
512
typ = $newType(4, $kindFunc, string, "", "", null);
445
513
$funcTypes[string] = typ;
446
- $addAnonTypeInit(function() { typ.init(params, results, variadic); } );
514
+ typ.init(params, results, variadic);
447
515
}
448
516
return typ;
449
517
};
@@ -460,7 +528,7 @@ var $interfaceType = function(methods) {
460
528
if (typ === undefined) {
461
529
typ = $newType(8, $kindInterface, string, "", "", null);
462
530
$interfaceTypes[string] = typ;
463
- $addAnonTypeInit(function() { typ.init(methods); } );
531
+ typ.init(methods);
464
532
}
465
533
return typ;
466
534
};
@@ -483,7 +551,7 @@ var $mapType = function(key, elem) {
483
551
if (typ === undefined) {
484
552
typ = $newType(4, $kindMap, string, "", "", null);
485
553
$mapTypes[string] = typ;
486
- $addAnonTypeInit(function() { typ.init(key, elem); } );
554
+ typ.init(key, elem);
487
555
}
488
556
return typ;
489
557
};
@@ -493,7 +561,7 @@ var $ptrType = function(elem) {
493
561
if (typ === undefined) {
494
562
typ = $newType(4, $kindPtr, "*" + elem.string, "", "", null);
495
563
elem.ptr = typ;
496
- $addAnonTypeInit(function() { typ.init(elem); } );
564
+ typ.init(elem);
497
565
}
498
566
return typ;
499
567
};
@@ -510,7 +578,7 @@ var $sliceType = function(elem) {
510
578
if (typ === undefined) {
511
579
typ = $newType(12, $kindSlice, "[]" + elem.string, "", "", null);
512
580
elem.Slice = typ;
513
- $addAnonTypeInit(function() { typ.init(elem); } );
581
+ typ.init(elem);
514
582
}
515
583
return typ;
516
584
};
@@ -546,22 +614,7 @@ var $structType = function(fields) {
546
614
}
547
615
});
548
616
$structTypes[string] = typ;
549
- $anonTypeInits.push(function() {
550
- /* collect methods for anonymous fields */
551
- for (var i = 0; i < fields.length; i++) {
552
- var f = fields[i];
553
- if (f.name === "") {
554
- f.typ.methods.forEach(function(m) {
555
- typ.methods.push(m);
556
- typ.ptr.methods.push(m);
557
- });
558
- $ptrType(f.typ).methods.forEach(function(m) {
559
- typ.ptr.methods.push(m);
560
- });
561
- }
562
- };
563
- typ.init(fields);
564
- });
617
+ typ.init(fields);
565
618
}
566
619
return typ;
567
620
};
@@ -577,13 +630,13 @@ var $assertType = function(value, type, returnTuple) {
577
630
ok = type.implementedBy[valueTypeString];
578
631
if (ok === undefined) {
579
632
ok = true;
580
- var valueMethods = value.constructor.methods ;
581
- var typeMethods = type.methods;
582
- for (var i = 0; i < typeMethods .length; i++) {
583
- var tm = typeMethods [i];
633
+ var valueMethodSet = $methodSet( value.constructor) ;
634
+ var interfaceMethods = type.methods;
635
+ for (var i = 0; i < interfaceMethods .length; i++) {
636
+ var tm = interfaceMethods [i];
584
637
var found = false;
585
- for (var j = 0; j < valueMethods .length; j++) {
586
- var vm = valueMethods [j];
638
+ for (var j = 0; j < valueMethodSet .length; j++) {
639
+ var vm = valueMethodSet [j];
587
640
if (vm.name === tm.name && vm.pkg === tm.pkg && vm.typ === tm.typ) {
588
641
found = true;
589
642
break;
0 commit comments