@@ -17,25 +17,30 @@ class DeserializationEnvironment<T extends Node> {
17
17
18
18
final Map <String , T > binders = < String , T > {};
19
19
20
- final Set < String > usedNames ;
20
+ final Map < T , String > distinctNames = new Map < T , String >. identity () ;
21
21
22
- DeserializationEnvironment (this .parent)
23
- : usedNames = parent? .usedNames? .toSet () ?? new Set <String >();
22
+ DeserializationEnvironment (this .parent);
24
23
25
24
T lookup (String name) => locals[name] ?? parent? .lookup (name);
26
25
27
- T addBinder (String name, T node) {
28
- if (usedNames.contains (name)) {
29
- throw StateError ("Name '${name }' is already declared in this scope." );
26
+ T addBinder (T node, String distinctName) {
27
+ if (lookupDistinctName (node) != null ) {
28
+ throw StateError (
29
+ "Name '${distinctName }' is already declared in this scope." );
30
30
}
31
- usedNames. add (name) ;
32
- return binders[name ] = node;
31
+ distinctNames[node] = distinctName ;
32
+ return binders[distinctName ] = node;
33
33
}
34
34
35
- void close () {
35
+ // TODO(dmitryas): Consider combining with [addBinder] into a single method.
36
+ void extend () {
36
37
locals.addAll (binders);
37
38
binders.clear ();
38
39
}
40
+
41
+ String lookupDistinctName (T object) {
42
+ return distinctNames[object] ?? parent? .lookupDistinctName (object);
43
+ }
39
44
}
40
45
41
46
class SerializationEnvironment <T extends Node > {
@@ -47,33 +52,55 @@ class SerializationEnvironment<T extends Node> {
47
52
48
53
int nameCount;
49
54
55
+ Map <T , String > distinctNames = new Map <T , String >.identity ();
56
+
50
57
SerializationEnvironment (this .parent) : nameCount = parent? .nameCount ?? 0 ;
51
58
52
59
String lookup (T node) => locals[node] ?? parent? .lookup (node);
53
60
54
- String addBinder (T node, String name ) {
61
+ String addBinder (T node, { String nameClue} ) {
55
62
final String separator = "^" ;
56
63
final int codeOfZero = "0" .codeUnitAt (0 );
57
64
final int codeOfNine = "9" .codeUnitAt (0 );
58
65
59
- int prefixLength = name.length - 1 ;
60
- bool isOnlyDigits = true ;
61
- while (prefixLength >= 0 && name[prefixLength] != separator) {
62
- int code = name.codeUnitAt (prefixLength);
63
- isOnlyDigits = isOnlyDigits && (codeOfZero <= code && code <= codeOfNine);
64
- -- prefixLength;
65
- }
66
- if (prefixLength < 0 || ! isOnlyDigits) {
67
- prefixLength = name.length;
66
+ String prefix;
67
+ if (nameClue != null ) {
68
+ int prefixLength = nameClue.length - 1 ;
69
+ bool isOnlyDigits = true ;
70
+ while (prefixLength >= 0 && nameClue[prefixLength] != separator) {
71
+ int code = nameClue.codeUnitAt (prefixLength);
72
+ isOnlyDigits =
73
+ isOnlyDigits && (codeOfZero <= code && code <= codeOfNine);
74
+ -- prefixLength;
75
+ }
76
+ if (prefixLength < 0 || ! isOnlyDigits) {
77
+ prefixLength = nameClue.length;
78
+ }
79
+ prefix = nameClue.substring (0 , prefixLength);
80
+ } else {
81
+ prefix = "ID" ;
68
82
}
69
- String prefix = name.substring (0 , prefixLength);
70
- return binders[node] = "$prefix $separator ${nameCount ++}" ;
71
- }
72
-
73
- void close () {
83
+ String distinctName = "$prefix $separator ${nameCount ++}" ;
84
+ // The following checks for an internal error, not an error caused by the user.
85
+ // So, an assert is used instead of an exception.
86
+ assert (
87
+ lookupDistinctName (node) == null ,
88
+ "Can't assign distinct name '${distinctName }' "
89
+ "to an object of kind '${node .runtimeType }': "
90
+ "it's already known by name '${lookupDistinctName (node )}'." );
91
+ distinctNames[node] = distinctName;
92
+ return binders[node] = distinctName;
93
+ }
94
+
95
+ // TODO(dmitryas): Consider combining with [addBinder] into a single method.
96
+ void extend () {
74
97
locals.addAll (binders);
75
98
binders.clear ();
76
99
}
100
+
101
+ String lookupDistinctName (T object) {
102
+ return distinctNames[object] ?? parent? .lookupDistinctName (object);
103
+ }
77
104
}
78
105
79
106
class DeserializationState {
@@ -312,7 +339,7 @@ class Tuple2Serializer<T1, T2> extends TextSerializer<Tuple2<T1, T2>> {
312
339
void writeTo (
313
340
StringBuffer buffer, Tuple2 <T1 , T2 > object, SerializationState state) {
314
341
first.writeTo (buffer, object.first, state);
315
- buffer.write (' ' );
342
+ if ( ! second.isEmpty) buffer.write (' ' );
316
343
second.writeTo (buffer, object.second, state);
317
344
}
318
345
}
@@ -340,9 +367,9 @@ class Tuple3Serializer<T1, T2, T3> extends TextSerializer<Tuple3<T1, T2, T3>> {
340
367
void writeTo (StringBuffer buffer, Tuple3 <T1 , T2 , T3 > object,
341
368
SerializationState state) {
342
369
first.writeTo (buffer, object.first, state);
343
- buffer.write (' ' );
370
+ if ( ! second.isEmpty) buffer.write (' ' );
344
371
second.writeTo (buffer, object.second, state);
345
- buffer.write (' ' );
372
+ if ( ! third.isEmpty) buffer.write (' ' );
346
373
third.writeTo (buffer, object.third, state);
347
374
}
348
375
}
@@ -376,11 +403,11 @@ class Tuple4Serializer<T1, T2, T3, T4>
376
403
void writeTo (StringBuffer buffer, Tuple4 <T1 , T2 , T3 , T4 > object,
377
404
SerializationState state) {
378
405
first.writeTo (buffer, object.first, state);
379
- buffer.write (' ' );
406
+ if ( ! second.isEmpty) buffer.write (' ' );
380
407
second.writeTo (buffer, object.second, state);
381
- buffer.write (' ' );
408
+ if ( ! third.isEmpty) buffer.write (' ' );
382
409
third.writeTo (buffer, object.third, state);
383
- buffer.write (' ' );
410
+ if ( ! fourth.isEmpty) buffer.write (' ' );
384
411
fourth.writeTo (buffer, object.fourth, state);
385
412
}
386
413
}
@@ -451,25 +478,28 @@ class Optional<T> extends TextSerializer<T> {
451
478
/// Serializes an object and uses it as a binder for the name that is retrieved
452
479
/// from the object using [nameGetter] and (temporarily) modified using
453
480
/// [nameSetter] . The binder is added to the enclosing environment.
454
- class Binder <T extends Node > extends TextSerializer <T > {
455
- final TextSerializer <T > contents;
456
- final String Function (T ) nameGetter;
457
- final void Function (T , String ) nameSetter;
481
+ class Binder <T extends Node > extends TextSerializer <Tuple2 <String , T >> {
482
+ final Tuple2Serializer <String , T > namedContents;
458
483
459
- const Binder (this .contents, this .nameGetter, this .nameSetter);
484
+ Binder (TextSerializer <T > contents)
485
+ : namedContents = new Tuple2Serializer (const DartString (), contents);
460
486
461
- T readFrom (Iterator <Object > stream, DeserializationState state) {
462
- T object = contents.readFrom (stream, state);
463
- state.environment.addBinder (nameGetter (object), object);
464
- return object;
487
+ Tuple2 <String , T > readFrom (
488
+ Iterator <Object > stream, DeserializationState state) {
489
+ Tuple2 <String , T > namedObject = namedContents.readFrom (stream, state);
490
+ String name = namedObject.first;
491
+ T object = namedObject.second;
492
+ state.environment.addBinder (object, name);
493
+ return new Tuple2 (name, object);
465
494
}
466
495
467
- void writeTo (StringBuffer buffer, T object, SerializationState state) {
468
- String oldName = nameGetter (object);
469
- String newName = state.environment.addBinder (object, oldName);
470
- nameSetter (object, newName);
471
- contents.writeTo (buffer, object, state);
472
- nameSetter (object, oldName);
496
+ void writeTo (StringBuffer buffer, Tuple2 <String , T > namedObject,
497
+ SerializationState state) {
498
+ String nameClue = namedObject.first;
499
+ T object = namedObject.second;
500
+ String distinctName =
501
+ state.environment.addBinder (object, nameClue: nameClue);
502
+ namedContents.writeTo (buffer, new Tuple2 (distinctName, object), state);
473
503
}
474
504
}
475
505
@@ -488,7 +518,7 @@ class Bind<P, T> extends TextSerializer<Tuple2<P, T>> {
488
518
var bindingState = new DeserializationState (
489
519
new DeserializationEnvironment (state.environment), state.nameRoot);
490
520
P first = pattern.readFrom (stream, bindingState);
491
- bindingState.environment.close ();
521
+ bindingState.environment.extend ();
492
522
T second = term.readFrom (stream, bindingState);
493
523
return new Tuple2 (first, second);
494
524
}
@@ -498,7 +528,7 @@ class Bind<P, T> extends TextSerializer<Tuple2<P, T>> {
498
528
var bindingState =
499
529
new SerializationState (new SerializationEnvironment (state.environment));
500
530
pattern.writeTo (buffer, tuple.first, bindingState);
501
- bindingState.environment.close ();
531
+ bindingState.environment.extend ();
502
532
buffer.write (' ' );
503
533
term.writeTo (buffer, tuple.second, bindingState);
504
534
}
@@ -520,7 +550,7 @@ class Rebind<P, T> extends TextSerializer<Tuple2<P, T>> {
520
550
var closedState = new DeserializationState (
521
551
new DeserializationEnvironment (state.environment)
522
552
..binders.addAll (state.environment.binders)
523
- ..close (),
553
+ ..extend (),
524
554
state.nameRoot);
525
555
T second = pattern2.readFrom (stream, closedState);
526
556
state.environment.binders.addAll (closedState.environment.binders);
@@ -533,7 +563,7 @@ class Rebind<P, T> extends TextSerializer<Tuple2<P, T>> {
533
563
var closedState =
534
564
new SerializationState (new SerializationEnvironment (state.environment)
535
565
..binders.addAll (state.environment.binders)
536
- ..close ());
566
+ ..extend ());
537
567
buffer.write (' ' );
538
568
pattern2.writeTo (buffer, tuple.second, closedState);
539
569
state.environment.binders.addAll (closedState.environment.binders);
0 commit comments