blob: bc15d898382026b812ae8f81a56dd958424aba34 [file] [log] [blame] [edit]
// Copyright (c) 2025, 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.
import '../builder/compilation_unit.dart';
import '../builder/declaration_builders.dart';
import '../builder/prefix_builder.dart';
import 'name_space.dart';
/// Interface for accessing extensions available in the current scope.
///
/// This available extensions come from the current library or from extensions
/// imported into the current scope, possibly through prefixes, and through
/// the extension scope of parent parts.
abstract class ExtensionScope {
void forEachExtension(void Function(ExtensionBuilder) f);
}
/// Interface for accessing extensions directly declared or imported.
///
/// This is used as a base for computing the nested extension scope in
/// [ExtensionScope].
abstract class Extensions {
void forEachLocalExtension(void Function(ExtensionBuilder member) f);
}
class ExtensionsBuilder implements Extensions {
Set<ExtensionBuilder>? _extensions;
/// Adds [builder] to the extensions in this name space.
void addExtension(ExtensionBuilder builder) {
(_extensions ??= {}).add(builder);
}
@override
void forEachLocalExtension(void Function(ExtensionBuilder member) f) {
_extensions?.forEach(f);
}
}
final class LibraryExtensions implements Extensions {
final Set<ExtensionBuilder>? _extensions;
LibraryExtensions({required Set<ExtensionBuilder> extensions})
: _extensions = extensions;
@override
void forEachLocalExtension(void Function(ExtensionBuilder member) f) {
_extensions?.forEach(f);
}
}
abstract class BaseExtensionScope implements ExtensionScope {
Extensions get _localExtensions;
ExtensionScope? get _parent;
@override
void forEachExtension(void Function(ExtensionBuilder) f) {
_localExtensions.forEachLocalExtension(f);
_parent?.forEachExtension(f);
}
@override
String toString() => "$runtimeType()";
}
// Coverage-ignore(suite): Not run.
/// Implementation of [ExtensionScope] that includes extensions from a given
/// [Extensions] object.
///
/// This is used for expression compilation to give access to extensions
/// declared in the library that the expression should be resolved in.
class ParentLibraryExtensionScope extends BaseExtensionScope {
@override
final Extensions _localExtensions;
@override
final ExtensionScope? _parent;
ParentLibraryExtensionScope(this._localExtensions, {ExtensionScope? parent})
: _parent = parent;
}
class CompilationUnitImportExtensionScope extends BaseExtensionScope {
final SourceCompilationUnit _compilationUnit;
final Extensions _importNameSpace;
CompilationUnitImportExtensionScope(
this._compilationUnit,
this._importNameSpace,
);
@override
Extensions get _localExtensions => _importNameSpace;
@override
ExtensionScope? get _parent =>
_compilationUnit.parentCompilationUnit?.prefixExtensionScope ??
_compilationUnit.libraryBuilder.parentExtensionScope;
}
class CompilationUnitExtensionScope extends BaseExtensionScope {
final SourceCompilationUnit _compilationUnit;
@override
final ExtensionScope? _parent;
CompilationUnitExtensionScope(this._compilationUnit, {ExtensionScope? parent})
: _parent = parent;
@override
Extensions get _localExtensions =>
_compilationUnit.libraryBuilder.libraryExtensions;
/// Set of extension declarations in scope. This is computed lazily in
/// [forEachExtension].
Set<ExtensionBuilder>? _extensions;
@override
void forEachExtension(void Function(ExtensionBuilder) f) {
if (_extensions == null) {
Set<ExtensionBuilder> extensions = _extensions = <ExtensionBuilder>{};
_parent?.forEachExtension(extensions.add);
_localExtensions.forEachLocalExtension(extensions.add);
}
_extensions!.forEach(f);
}
}
class CompilationUnitPrefixExtensionScope implements ExtensionScope {
final ComputedNameSpace _prefixNameSpace;
final ExtensionScope _parent;
CompilationUnitPrefixExtensionScope(
this._prefixNameSpace, {
required ExtensionScope parent,
}) : _parent = parent;
/// Set of extension declarations in scope. This is computed lazily in
/// [forEachExtension].
Set<ExtensionBuilder>? _extensions;
@override
void forEachExtension(void Function(ExtensionBuilder) f) {
if (_extensions == null) {
Set<ExtensionBuilder> extensions = _extensions = {};
Iterator<PrefixBuilder> iterator = _prefixNameSpace.filteredIterator();
while (iterator.moveNext()) {
iterator.current.forEachExtension((e) {
extensions.add(e);
});
}
_parent.forEachExtension(extensions.add);
}
_extensions!.forEach(f);
}
@override
String toString() => "$runtimeType()";
}