ee0c0bcd57
This is in preparation to migrate package:kernel to null safety. For the visitor interfaces to support non-nullable return types, the implementations must avoid using `null` as return value in its base case. TEST=Refactoring Change-Id: Ie8fa5d41b99850d9e4abb59634c72920c64128d9 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/183691 Reviewed-by: Jens Johansen <jensj@google.com> Commit-Queue: Johnni Winther <johnniwinther@google.com>
267 lines
6.8 KiB
Dart
267 lines
6.8 KiB
Dart
// Copyright (c) 2020, 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.
|
|
|
|
// @dart = 2.9
|
|
|
|
library kernel.transformations.scanner;
|
|
|
|
import '../ast.dart';
|
|
import '../kernel.dart';
|
|
|
|
abstract class Scanner<X extends TreeNode, Y extends TreeNode> {
|
|
final Scanner<Y, TreeNode> next;
|
|
Scanner(this.next);
|
|
bool predicate(X x);
|
|
ScanResult<X, Y> scan(TreeNode node);
|
|
}
|
|
|
|
class ScanResult<X extends TreeNode, Y extends TreeNode> {
|
|
Map<X, ScanResult<Y, TreeNode>> targets = new Map();
|
|
Map<X, ScanError> errors;
|
|
}
|
|
|
|
class ScanError {}
|
|
|
|
abstract class ClassScanner<Y extends TreeNode> implements Scanner<Class, Y> {
|
|
final Scanner<Y, TreeNode> next;
|
|
|
|
ClassScanner(this.next);
|
|
|
|
bool predicate(Class node);
|
|
|
|
ScanResult<Class, Y> scan(TreeNode node) {
|
|
ScanResult<Class, Y> result = new ScanResult();
|
|
|
|
if (node is Class) {
|
|
if (predicate(node)) {
|
|
result.targets[node] = next?.scan(node);
|
|
// TODO(dmitryas): set result.errors when specification is landed,
|
|
// same with all other places where targets is set
|
|
}
|
|
} else if (node is Library) {
|
|
_scanLibrary(node, result);
|
|
} else if (node is Component) {
|
|
_scanComponent(node, result);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void _scanLibrary(Library library, ScanResult<Class, Y> result) {
|
|
for (Class cls in library.classes) {
|
|
if (predicate(cls)) {
|
|
result.targets[cls] = next?.scan(cls);
|
|
}
|
|
}
|
|
}
|
|
|
|
void _scanComponent(Component component, ScanResult<Class, Y> result) {
|
|
for (Library library in component.libraries) {
|
|
_scanLibrary(library, result);
|
|
}
|
|
}
|
|
}
|
|
|
|
abstract class FieldScanner<Y extends TreeNode> implements Scanner<Field, Y> {
|
|
final Scanner<Y, TreeNode> next;
|
|
|
|
FieldScanner(this.next);
|
|
|
|
bool predicate(Field node);
|
|
|
|
ScanResult<Field, Y> scan(TreeNode node) {
|
|
ScanResult<Field, Y> result = new ScanResult();
|
|
|
|
if (node is Field) {
|
|
_scanField(node, result);
|
|
} else if (node is Class) {
|
|
_scanClass(node, result);
|
|
} else if (node is Library) {
|
|
_scanLibrary(node, result);
|
|
} else if (node is Component) {
|
|
_scanComponent(node, result);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void _scanField(Field field, ScanResult<Field, Y> result) {
|
|
if (predicate(field)) {
|
|
result.targets[field] = next?.scan(field);
|
|
}
|
|
}
|
|
|
|
void _scanClass(Class cls, ScanResult<Field, Y> result) {
|
|
for (Field field in cls.fields) {
|
|
_scanField(field, result);
|
|
}
|
|
}
|
|
|
|
void _scanLibrary(Library library, ScanResult<Field, Y> result) {
|
|
for (Class cls in library.classes) {
|
|
_scanClass(cls, result);
|
|
}
|
|
for (Field field in library.fields) {
|
|
_scanField(field, result);
|
|
}
|
|
}
|
|
|
|
void _scanComponent(Component component, ScanResult<Field, Y> result) {
|
|
for (Library library in component.libraries) {
|
|
_scanLibrary(library, result);
|
|
}
|
|
}
|
|
}
|
|
|
|
abstract class MemberScanner<Y extends TreeNode> implements Scanner<Member, Y> {
|
|
final Scanner<Y, TreeNode> next;
|
|
|
|
MemberScanner(this.next);
|
|
|
|
bool predicate(Member node);
|
|
|
|
ScanResult<Member, Y> scan(TreeNode node) {
|
|
ScanResult<Member, Y> result = new ScanResult();
|
|
|
|
if (node is Member) {
|
|
_scanMember(node, result);
|
|
} else if (node is Class) {
|
|
_scanClass(node, result);
|
|
} else if (node is Library) {
|
|
_scanLibrary(node, result);
|
|
} else if (node is Component) {
|
|
_scanComponent(node, result);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void _scanMember(Member member, ScanResult<Member, Y> result) {
|
|
if (predicate(member)) {
|
|
result.targets[member] = next?.scan(member);
|
|
}
|
|
}
|
|
|
|
void _scanClass(Class cls, ScanResult<Member, Y> result) {
|
|
for (Member member in cls.members) {
|
|
_scanMember(member, result);
|
|
}
|
|
}
|
|
|
|
void _scanLibrary(Library library, ScanResult<Member, Y> result) {
|
|
for (Class cls in library.classes) {
|
|
_scanClass(cls, result);
|
|
}
|
|
for (Member member in library.members) {
|
|
_scanMember(member, result);
|
|
}
|
|
}
|
|
|
|
void _scanComponent(Component component, ScanResult<Member, Y> result) {
|
|
for (Library library in component.libraries) {
|
|
_scanLibrary(library, result);
|
|
}
|
|
}
|
|
}
|
|
|
|
abstract class ProcedureScanner<Y extends TreeNode>
|
|
implements Scanner<Procedure, Y> {
|
|
final Scanner<Y, TreeNode> next;
|
|
|
|
ProcedureScanner(this.next);
|
|
|
|
bool predicate(Procedure node);
|
|
|
|
ScanResult<Procedure, Y> scan(TreeNode node) {
|
|
ScanResult<Procedure, Y> result = new ScanResult();
|
|
|
|
if (node is Procedure) {
|
|
_scanProcedure(node, result);
|
|
} else if (node is Class) {
|
|
_scanClass(node, result);
|
|
} else if (node is Library) {
|
|
_scanLibrary(node, result);
|
|
} else if (node is Component) {
|
|
_scanComponent(node, result);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void _scanProcedure(Procedure procedure, ScanResult<Procedure, Y> result) {
|
|
if (predicate(procedure)) {
|
|
result.targets[procedure] = next?.scan(procedure);
|
|
}
|
|
}
|
|
|
|
void _scanClass(Class cls, ScanResult<Procedure, Y> result) {
|
|
for (Procedure procedure in cls.procedures) {
|
|
_scanProcedure(procedure, result);
|
|
}
|
|
}
|
|
|
|
void _scanLibrary(Library library, ScanResult<Procedure, Y> result) {
|
|
for (Class cls in library.classes) {
|
|
_scanClass(cls, result);
|
|
}
|
|
for (Procedure procedure in library.procedures) {
|
|
_scanProcedure(procedure, result);
|
|
}
|
|
}
|
|
|
|
void _scanComponent(Component component, ScanResult<Procedure, Y> result) {
|
|
for (Library library in component.libraries) {
|
|
_scanLibrary(library, result);
|
|
}
|
|
}
|
|
}
|
|
|
|
abstract class ExpressionScanner<Y extends TreeNode>
|
|
extends RecursiveResultVisitor<void> implements Scanner<Expression, Y> {
|
|
final Scanner<Y, TreeNode> next;
|
|
ScanResult<Expression, Y> _result;
|
|
|
|
ExpressionScanner(this.next);
|
|
|
|
bool predicate(Expression node);
|
|
|
|
ScanResult<Expression, Y> scan(TreeNode node) {
|
|
ScanResult<Expression, Y> result = _result = new ScanResult();
|
|
node.accept(this);
|
|
_result = null;
|
|
return result;
|
|
}
|
|
|
|
void visitExpression(Expression node) {
|
|
if (predicate(node)) {
|
|
_result.targets[node] = next?.scan(node);
|
|
// TODO: Update result.errors.
|
|
}
|
|
}
|
|
}
|
|
|
|
abstract class MethodInvocationScanner<Y extends TreeNode>
|
|
extends RecursiveVisitor implements Scanner<MethodInvocation, Y> {
|
|
final Scanner<Y, TreeNode> next;
|
|
ScanResult<MethodInvocation, Y> _result;
|
|
|
|
MethodInvocationScanner(this.next);
|
|
|
|
bool predicate(MethodInvocation node);
|
|
|
|
ScanResult<MethodInvocation, Y> scan(TreeNode node) {
|
|
ScanResult<MethodInvocation, Y> result = _result = new ScanResult();
|
|
node.accept(this);
|
|
_result = null;
|
|
return result;
|
|
}
|
|
|
|
void visitMethodInvocation(MethodInvocation node) {
|
|
if (predicate(node)) {
|
|
_result.targets[node] = next?.scan(node);
|
|
// TODO: Update result.errors.
|
|
}
|
|
}
|
|
}
|