@@ -17,25 +17,30 @@ class DeserializationEnvironment<T extends Node> {
1717
1818 final Map <String , T > binders = < String , T > {};
1919
20- final Set < String > usedNames ;
20+ final Map < T , String > distinctNames = new Map < T , String >. identity () ;
2121
22- DeserializationEnvironment (this .parent)
23- : usedNames = parent? .usedNames? .toSet () ?? new Set <String >();
22+ DeserializationEnvironment (this .parent);
2423
2524 T lookup (String name) => locals[name] ?? parent? .lookup (name);
2625
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." );
3030 }
31- usedNames. add (name) ;
32- return binders[name ] = node;
31+ distinctNames[node] = distinctName ;
32+ return binders[distinctName ] = node;
3333 }
3434
35- void close () {
35+ // TODO(dmitryas): Consider combining with [addBinder] into a single method.
36+ void extend () {
3637 locals.addAll (binders);
3738 binders.clear ();
3839 }
40+
41+ String lookupDistinctName (T object) {
42+ return distinctNames[object] ?? parent? .lookupDistinctName (object);
43+ }
3944}
4045
4146class SerializationEnvironment <T extends Node > {
@@ -47,33 +52,55 @@ class SerializationEnvironment<T extends Node> {
4752
4853 int nameCount;
4954
55+ Map <T , String > distinctNames = new Map <T , String >.identity ();
56+
5057 SerializationEnvironment (this .parent) : nameCount = parent? .nameCount ?? 0 ;
5158
5259 String lookup (T node) => locals[node] ?? parent? .lookup (node);
5360
54- String addBinder (T node, String name ) {
61+ String addBinder (T node, { String nameClue} ) {
5562 final String separator = "^" ;
5663 final int codeOfZero = "0" .codeUnitAt (0 );
5764 final int codeOfNine = "9" .codeUnitAt (0 );
5865
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" ;
6882 }
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 () {
7497 locals.addAll (binders);
7598 binders.clear ();
7699 }
100+
101+ String lookupDistinctName (T object) {
102+ return distinctNames[object] ?? parent? .lookupDistinctName (object);
103+ }
77104}
78105
79106class DeserializationState {
@@ -312,7 +339,7 @@ class Tuple2Serializer<T1, T2> extends TextSerializer<Tuple2<T1, T2>> {
312339 void writeTo (
313340 StringBuffer buffer, Tuple2 <T1 , T2 > object, SerializationState state) {
314341 first.writeTo (buffer, object.first, state);
315- buffer.write (' ' );
342+ if ( ! second.isEmpty) buffer.write (' ' );
316343 second.writeTo (buffer, object.second, state);
317344 }
318345}
@@ -340,9 +367,9 @@ class Tuple3Serializer<T1, T2, T3> extends TextSerializer<Tuple3<T1, T2, T3>> {
340367 void writeTo (StringBuffer buffer, Tuple3 <T1 , T2 , T3 > object,
341368 SerializationState state) {
342369 first.writeTo (buffer, object.first, state);
343- buffer.write (' ' );
370+ if ( ! second.isEmpty) buffer.write (' ' );
344371 second.writeTo (buffer, object.second, state);
345- buffer.write (' ' );
372+ if ( ! third.isEmpty) buffer.write (' ' );
346373 third.writeTo (buffer, object.third, state);
347374 }
348375}
@@ -376,11 +403,11 @@ class Tuple4Serializer<T1, T2, T3, T4>
376403 void writeTo (StringBuffer buffer, Tuple4 <T1 , T2 , T3 , T4 > object,
377404 SerializationState state) {
378405 first.writeTo (buffer, object.first, state);
379- buffer.write (' ' );
406+ if ( ! second.isEmpty) buffer.write (' ' );
380407 second.writeTo (buffer, object.second, state);
381- buffer.write (' ' );
408+ if ( ! third.isEmpty) buffer.write (' ' );
382409 third.writeTo (buffer, object.third, state);
383- buffer.write (' ' );
410+ if ( ! fourth.isEmpty) buffer.write (' ' );
384411 fourth.writeTo (buffer, object.fourth, state);
385412 }
386413}
@@ -451,25 +478,28 @@ class Optional<T> extends TextSerializer<T> {
451478/// Serializes an object and uses it as a binder for the name that is retrieved
452479/// from the object using [nameGetter] and (temporarily) modified using
453480/// [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;
458483
459- const Binder (this .contents, this .nameGetter, this .nameSetter);
484+ Binder (TextSerializer <T > contents)
485+ : namedContents = new Tuple2Serializer (const DartString (), contents);
460486
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);
465494 }
466495
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);
473503 }
474504}
475505
@@ -488,7 +518,7 @@ class Bind<P, T> extends TextSerializer<Tuple2<P, T>> {
488518 var bindingState = new DeserializationState (
489519 new DeserializationEnvironment (state.environment), state.nameRoot);
490520 P first = pattern.readFrom (stream, bindingState);
491- bindingState.environment.close ();
521+ bindingState.environment.extend ();
492522 T second = term.readFrom (stream, bindingState);
493523 return new Tuple2 (first, second);
494524 }
@@ -498,7 +528,7 @@ class Bind<P, T> extends TextSerializer<Tuple2<P, T>> {
498528 var bindingState =
499529 new SerializationState (new SerializationEnvironment (state.environment));
500530 pattern.writeTo (buffer, tuple.first, bindingState);
501- bindingState.environment.close ();
531+ bindingState.environment.extend ();
502532 buffer.write (' ' );
503533 term.writeTo (buffer, tuple.second, bindingState);
504534 }
@@ -520,7 +550,7 @@ class Rebind<P, T> extends TextSerializer<Tuple2<P, T>> {
520550 var closedState = new DeserializationState (
521551 new DeserializationEnvironment (state.environment)
522552 ..binders.addAll (state.environment.binders)
523- ..close (),
553+ ..extend (),
524554 state.nameRoot);
525555 T second = pattern2.readFrom (stream, closedState);
526556 state.environment.binders.addAll (closedState.environment.binders);
@@ -533,7 +563,7 @@ class Rebind<P, T> extends TextSerializer<Tuple2<P, T>> {
533563 var closedState =
534564 new SerializationState (new SerializationEnvironment (state.environment)
535565 ..binders.addAll (state.environment.binders)
536- ..close ());
566+ ..extend ());
537567 buffer.write (' ' );
538568 pattern2.writeTo (buffer, tuple.second, closedState);
539569 state.environment.binders.addAll (closedState.environment.binders);
0 commit comments