blob: 53256370f5af6b3b5ae364c262d8e2189a0b2848 [file] [log] [blame]
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of '../../ast.dart';
// ------------------------------------------------------------------------
// NAMES
// ------------------------------------------------------------------------
/// A public name, or a private name qualified by a library.
///
/// Names are only used for expressions with dynamic dispatch, as all
/// statically resolved references are represented in nameless form.
///
/// [Name]s are immutable and compare based on structural equality, and they
/// are not AST nodes.
///
/// The [toString] method returns a human-readable string that includes the
/// library name for private names; uniqueness is not guaranteed.
abstract class Name extends Node {
@override
final int hashCode;
final String text;
Reference? get libraryReference;
Library? get library;
bool get isPrivate;
Name._internal(this.hashCode, this.text);
factory Name(String text, [Library? library]) =>
new Name.byReference(text, library?.reference);
factory Name.byReference(String text, Reference? libraryName) {
/// Use separate subclasses for the public and private case to save memory
/// for public names.
if (text.startsWith('_')) {
assert(libraryName != null);
return new _PrivateName(text, libraryName!);
} else {
return new _PublicName(text);
}
}
@override
bool operator ==(other) {
return other is Name && text == other.text && library == other.library;
}
@override
R accept<R>(Visitor<R> v) => v.visitName(this);
@override
R accept1<R, A>(Visitor1<R, A> v, A arg) => v.visitName(this, arg);
@override
void visitChildren(Visitor v) {
// DESIGN TODO: Should we visit the library as a library reference?
}
/// Returns the textual representation of this node for use in debugging.
///
/// Note that this adds some nodes to a static map to ensure consistent
/// naming, but that it thus also leaks memory.
@override
String leakingDebugToString() => astToText.debugNodeToString(this);
@override
void toTextInternal(AstPrinter printer) {
printer.writeName(this);
}
/// The name of the `call` method on a function.
static final Name callName = new _PublicName('call');
/// The name of the `==` operator.
static final Name equalsName = new _PublicName('==');
}
class _PrivateName extends Name {
@override
final Reference libraryReference;
@override
bool get isPrivate => true;
_PrivateName(String text, Reference libraryReference)
: this.libraryReference = libraryReference,
super._internal(_computeHashCode(text, libraryReference), text);
@override
String toString() => toStringInternal();
@override
String toStringInternal() => '$library::$text';
@override
Library get library => libraryReference.asLibrary;
static int _computeHashCode(String name, Reference libraryReference) {
// TODO(cstefantsova): Factor in [libraryReference] in a non-deterministic
// way into the result. Note, the previous code here was the following:
// return 131 * name.hashCode + 17 *
// libraryReference.asLibrary._libraryId;
return name.hashCode;
}
}
class _PublicName extends Name {
@override
Reference? get libraryReference => null;
@override
Library? get library => null;
@override
bool get isPrivate => false;
_PublicName(String text) : super._internal(text.hashCode, text);
@override
String toString() => toStringInternal();
}