Skip to content

Commit

Permalink
[cfe] Support LabeledStatement and Break in text serialization
Browse files Browse the repository at this point in the history
In addition to supporting the nodes, the notion of Binder is
reworked.  It doesn't store the computed local distinct name on the
node itself now, as it's not always possible (which is the case of
LabeledStatement), but keep it in a map.

Change-Id: I04c08875cbcac3a547d62afbe5b17f023e6f1035
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/153342
Reviewed-by: Johnni Winther <johnniwinther@google.com>
  • Loading branch information
Dmitry Stefantsov authored and commit-bot@chromium.org committed Jul 7, 2020
1 parent 1ed7581 commit da87123
Show file tree
Hide file tree
Showing 5 changed files with 242 additions and 206 deletions.
128 changes: 79 additions & 49 deletions pkg/kernel/lib/text/serializer_combinators.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,30 @@ class DeserializationEnvironment<T extends Node> {

final Map<String, T> binders = <String, T>{};

final Set<String> usedNames;
final Map<T, String> distinctNames = new Map<T, String>.identity();

DeserializationEnvironment(this.parent)
: usedNames = parent?.usedNames?.toSet() ?? new Set<String>();
DeserializationEnvironment(this.parent);

T lookup(String name) => locals[name] ?? parent?.lookup(name);

T addBinder(String name, T node) {
if (usedNames.contains(name)) {
throw StateError("Name '${name}' is already declared in this scope.");
T addBinder(T node, String distinctName) {
if (lookupDistinctName(node) != null) {
throw StateError(
"Name '${distinctName}' is already declared in this scope.");
}
usedNames.add(name);
return binders[name] = node;
distinctNames[node] = distinctName;
return binders[distinctName] = node;
}

void close() {
// TODO(dmitryas): Consider combining with [addBinder] into a single method.
void extend() {
locals.addAll(binders);
binders.clear();
}

String lookupDistinctName(T object) {
return distinctNames[object] ?? parent?.lookupDistinctName(object);
}
}

class SerializationEnvironment<T extends Node> {
Expand All @@ -47,33 +52,55 @@ class SerializationEnvironment<T extends Node> {

int nameCount;

Map<T, String> distinctNames = new Map<T, String>.identity();

SerializationEnvironment(this.parent) : nameCount = parent?.nameCount ?? 0;

String lookup(T node) => locals[node] ?? parent?.lookup(node);

String addBinder(T node, String name) {
String addBinder(T node, {String nameClue}) {
final String separator = "^";
final int codeOfZero = "0".codeUnitAt(0);
final int codeOfNine = "9".codeUnitAt(0);

int prefixLength = name.length - 1;
bool isOnlyDigits = true;
while (prefixLength >= 0 && name[prefixLength] != separator) {
int code = name.codeUnitAt(prefixLength);
isOnlyDigits = isOnlyDigits && (codeOfZero <= code && code <= codeOfNine);
--prefixLength;
}
if (prefixLength < 0 || !isOnlyDigits) {
prefixLength = name.length;
String prefix;
if (nameClue != null) {
int prefixLength = nameClue.length - 1;
bool isOnlyDigits = true;
while (prefixLength >= 0 && nameClue[prefixLength] != separator) {
int code = nameClue.codeUnitAt(prefixLength);
isOnlyDigits =
isOnlyDigits && (codeOfZero <= code && code <= codeOfNine);
--prefixLength;
}
if (prefixLength < 0 || !isOnlyDigits) {
prefixLength = nameClue.length;
}
prefix = nameClue.substring(0, prefixLength);
} else {
prefix = "ID";
}
String prefix = name.substring(0, prefixLength);
return binders[node] = "$prefix$separator${nameCount++}";
}

void close() {
String distinctName = "$prefix$separator${nameCount++}";
// The following checks for an internal error, not an error caused by the user.
// So, an assert is used instead of an exception.
assert(
lookupDistinctName(node) == null,
"Can't assign distinct name '${distinctName}' "
"to an object of kind '${node.runtimeType}': "
"it's already known by name '${lookupDistinctName(node)}'.");
distinctNames[node] = distinctName;
return binders[node] = distinctName;
}

// TODO(dmitryas): Consider combining with [addBinder] into a single method.
void extend() {
locals.addAll(binders);
binders.clear();
}

String lookupDistinctName(T object) {
return distinctNames[object] ?? parent?.lookupDistinctName(object);
}
}

class DeserializationState {
Expand Down Expand Up @@ -312,7 +339,7 @@ class Tuple2Serializer<T1, T2> extends TextSerializer<Tuple2<T1, T2>> {
void writeTo(
StringBuffer buffer, Tuple2<T1, T2> object, SerializationState state) {
first.writeTo(buffer, object.first, state);
buffer.write(' ');
if (!second.isEmpty) buffer.write(' ');
second.writeTo(buffer, object.second, state);
}
}
Expand Down Expand Up @@ -340,9 +367,9 @@ class Tuple3Serializer<T1, T2, T3> extends TextSerializer<Tuple3<T1, T2, T3>> {
void writeTo(StringBuffer buffer, Tuple3<T1, T2, T3> object,
SerializationState state) {
first.writeTo(buffer, object.first, state);
buffer.write(' ');
if (!second.isEmpty) buffer.write(' ');
second.writeTo(buffer, object.second, state);
buffer.write(' ');
if (!third.isEmpty) buffer.write(' ');
third.writeTo(buffer, object.third, state);
}
}
Expand Down Expand Up @@ -376,11 +403,11 @@ class Tuple4Serializer<T1, T2, T3, T4>
void writeTo(StringBuffer buffer, Tuple4<T1, T2, T3, T4> object,
SerializationState state) {
first.writeTo(buffer, object.first, state);
buffer.write(' ');
if (!second.isEmpty) buffer.write(' ');
second.writeTo(buffer, object.second, state);
buffer.write(' ');
if (!third.isEmpty) buffer.write(' ');
third.writeTo(buffer, object.third, state);
buffer.write(' ');
if (!fourth.isEmpty) buffer.write(' ');
fourth.writeTo(buffer, object.fourth, state);
}
}
Expand Down Expand Up @@ -451,25 +478,28 @@ class Optional<T> extends TextSerializer<T> {
/// Serializes an object and uses it as a binder for the name that is retrieved
/// from the object using [nameGetter] and (temporarily) modified using
/// [nameSetter]. The binder is added to the enclosing environment.
class Binder<T extends Node> extends TextSerializer<T> {
final TextSerializer<T> contents;
final String Function(T) nameGetter;
final void Function(T, String) nameSetter;
class Binder<T extends Node> extends TextSerializer<Tuple2<String, T>> {
final Tuple2Serializer<String, T> namedContents;

const Binder(this.contents, this.nameGetter, this.nameSetter);
Binder(TextSerializer<T> contents)
: namedContents = new Tuple2Serializer(const DartString(), contents);

T readFrom(Iterator<Object> stream, DeserializationState state) {
T object = contents.readFrom(stream, state);
state.environment.addBinder(nameGetter(object), object);
return object;
Tuple2<String, T> readFrom(
Iterator<Object> stream, DeserializationState state) {
Tuple2<String, T> namedObject = namedContents.readFrom(stream, state);
String name = namedObject.first;
T object = namedObject.second;
state.environment.addBinder(object, name);
return new Tuple2(name, object);
}

void writeTo(StringBuffer buffer, T object, SerializationState state) {
String oldName = nameGetter(object);
String newName = state.environment.addBinder(object, oldName);
nameSetter(object, newName);
contents.writeTo(buffer, object, state);
nameSetter(object, oldName);
void writeTo(StringBuffer buffer, Tuple2<String, T> namedObject,
SerializationState state) {
String nameClue = namedObject.first;
T object = namedObject.second;
String distinctName =
state.environment.addBinder(object, nameClue: nameClue);
namedContents.writeTo(buffer, new Tuple2(distinctName, object), state);
}
}

Expand All @@ -488,7 +518,7 @@ class Bind<P, T> extends TextSerializer<Tuple2<P, T>> {
var bindingState = new DeserializationState(
new DeserializationEnvironment(state.environment), state.nameRoot);
P first = pattern.readFrom(stream, bindingState);
bindingState.environment.close();
bindingState.environment.extend();
T second = term.readFrom(stream, bindingState);
return new Tuple2(first, second);
}
Expand All @@ -498,7 +528,7 @@ class Bind<P, T> extends TextSerializer<Tuple2<P, T>> {
var bindingState =
new SerializationState(new SerializationEnvironment(state.environment));
pattern.writeTo(buffer, tuple.first, bindingState);
bindingState.environment.close();
bindingState.environment.extend();
buffer.write(' ');
term.writeTo(buffer, tuple.second, bindingState);
}
Expand All @@ -520,7 +550,7 @@ class Rebind<P, T> extends TextSerializer<Tuple2<P, T>> {
var closedState = new DeserializationState(
new DeserializationEnvironment(state.environment)
..binders.addAll(state.environment.binders)
..close(),
..extend(),
state.nameRoot);
T second = pattern2.readFrom(stream, closedState);
state.environment.binders.addAll(closedState.environment.binders);
Expand All @@ -533,7 +563,7 @@ class Rebind<P, T> extends TextSerializer<Tuple2<P, T>> {
var closedState =
new SerializationState(new SerializationEnvironment(state.environment)
..binders.addAll(state.environment.binders)
..close());
..extend());
buffer.write(' ');
pattern2.writeTo(buffer, tuple.second, closedState);
state.environment.binders.addAll(closedState.environment.binders);
Expand Down
2 changes: 0 additions & 2 deletions pkg/kernel/lib/text/text_serialization_verifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -344,12 +344,10 @@ class VerificationState {
!isStatementNotSupported(node);

static bool isStatementNotSupported(Statement node) =>
node is BreakStatement ||
node is VariableDeclaration &&
(node.parent is! Block || node.name == null) ||
node is SwitchStatement ||
node is TryFinally ||
node is LabeledStatement ||
node is TryCatch ||
node is FunctionDeclaration ||
node is ContinueSwitchStatement;
Expand Down
Loading

0 comments on commit da87123

Please sign in to comment.