代码之家  ›  专栏  ›  技术社区  ›  Shubham Kumar

在DART中有没有任何方法可以在预订单、后订单或无序中遍历AST?

  •  0
  • Shubham Kumar  · 技术社区  · 7 年前

    是否有任何方法来遍历由DART分析器按预序、后序或无序组成的AST。我正在使用访问节点使用generalingastvisitor来遍历AST树,但它只是从代码的顶部到底部递归地遍历它。

    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 回复  |  直到 7 年前
        1
  •  2
  •   Mike Fairhurst    7 年前

    generalingastvisitor所做的模式是预排序。

    顺序遍历在AST上下文中没有意义。按顺序,遍历是左、根、右。但是一个AST分支可以有1到无穷大的子级。因此,最好是按顺序(n)定义一些遍历,在这里您访问第一个孩子、第二个孩子……第n个子级,根级,第n+1子级,第n+2子级…我看不出这样做的目的。

    对于后期订单来说,它有点微妙。如果您只想打印节点及其子实体,那么您的解决方案很简单。你只要打电话给超级 之前 打印节点:

    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 按照该顺序处理单个节点,但不应执行任何递归本身。

    对于大多数用例来说,这些应该能够帮助您度过难关,尽管在不知道您要做什么的情况下很难确定。