Есть ли способ пройти Аст в предзаказе, постзаказе или Inorder в дротике
Есть ли способ пройти AST, составленный из анализатора дротиков, в PreOrder, postOrder или inOrder.i я использую посещающий узел для обхода дерева AST, используя GeneralizingAstVisitor, но он просто рекурсивно перебирает его сверху вниз.
import'package:analyzer/src/generated/testing/element_factory.dart';
import 'package:analyzer/analyzer.dart';
import 'dart:io';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/src/context/builder.dart';
import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/source/source_resource.dart';
main() {
LibraryElement libElement;
Source source;
AnalysisContext context;
var ast = parseCompilationUnit(src,
parseFunctionBodies: true, suppressErrors: true);
print(ast.toSource());
PhysicalResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE;
DartSdk sdk = new FolderBasedDartSdk(resourceProvider,
resourceProvider.getFolder("/usr/local/opt/dart/libexec"));
var resolvers = [
new DartUriResolver(sdk),
];
context = AnalysisEngine.instance.createAnalysisContext()
..sourceFactory = new SourceFactory(resolvers);
source = new FileSource(resourceProvider.getFile(
"/Users/shubhamkumar/Sites/projects/flutterX/dart_analyser/demo.dart"));
ChangeSet changeSet = new ChangeSet()..addedSource(source);
context.applyChanges(changeSet);
libElement = context.computeLibraryElement(source);
callAST(context, source, libElement);
}
class Visitor1 extends GeneralizingAstVisitor {
@override
visitNode(AstNode node) {
print("node $node ${node.runtimeType} ");
node.childEntities.forEach((n) => print(n));
return super.visitNode(node);
}
}
callAST(context, source, libElement) {
CompilationUnit resolvedUnit =
context.resolveCompilationUnit(source, libElement);
var visitor = new Visitor1();
resolvedUnit.accept(visitor);
}
Пожалуйста, помогите, если у вас есть решение.
1 ответ
Шаблон, который делает GeneralizingAstVisitor, является предварительным заказом.
Обратный порядок не имеет смысла в контексте AST. Порядок обхода слева, корень, право. Но ветвь AST может иметь от 1 до бесконечности детей. Таким образом, лучшее, что вы могли бы сделать, это определить некоторый порядок (n) обхода, где вы посещаете первого ребенка, второго ребенка,... n-го ребенка, корня, nth+1 ребенка, nth+2 ребенка... Я надеваю не вижу цели этого.
Для пост-заказа это немного более нюанс. Если все, что вы хотите сделать, это напечатать узел и его дочерние объекты, то ваше решение простое. Вам просто нужно вызвать super перед печатью узла:
class Visitor2 extends GeneralizingAstVisitor {
@override
visitNode(AstNode node) {
final val = super.visitNode(node);
print("node $node ${node.runtimeType} ");
node.childEntities.forEach((n) => print(n));
return val;
}
}
Но если вы хотите использовать собственную логику для группы типов узлов, вам придется следовать этому шаблону в каждом обработчике посещений:
class Visitor3 extends GeneralizingAstVisitor {
@override
visitAssignmentExpression(AssignmentExpression node) {
final val = super.visitNode(node);
// use assignment expression here
return val;
}
@override
visitBinaryExpression(BinaryExpression node) {
final val = super.visitNode(node);
// use binary expression here
return val;
}
// ... more handlers
}
В этом случае я бы собрал посетителей, чтобы сделать это проще:
class PostOrderVisitor extends GeneralizingAstVisitor {
AstVisitor postOrderedVisitor = new Visitor4();
@override
visitNode(AstNode node) {
final val = super.visitNode(node);
return node.accept(postOrderedVisitor);
}
}
class Visitor4 extends AstVisitor {
@override
visitAssignmentExpression(AssignmentExpression node) {
// use assignment expression here
}
@override
visitBinaryExpression(BinaryExpression node) {
// use binary expression here
}
// ... more handlers
}
В этом случае, PostOrderVisitor
обрабатывает пост-заказ, и Visitor4
обрабатывает отдельные узлы в соответствии с этим порядком, но не должна выполнять никакой рекурсии.
Это поможет вам в большинстве случаев, хотя трудно быть уверенным, не зная, что вы пытаетесь сделать.