0

Is there any way to traverse the AST made up from dart Analyser in PreOrder, postOrder or inOrder.i am using visit Node to traverse the AST tree using GeneralizingAstVisitor but it just traverse it recursively from top to bottom of code.

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);
}

Please help if u have any solution.

Shubham Kumar
  • 2,171
  • 1
  • 13
  • 22
  • Shouldn't you be able to control that yourself with `node.childEntities.forEach((n) => print(n)); return super.visitNode(node);`? – Günter Zöchbauer Jul 23 '18 at 15:46
  • no that recursively traverse from top to bottom of code visiting parent then its children then the next parent, what i want to traverse all the parent node first and if the desired node is meet then its child node. – Shubham Kumar Jul 24 '18 at 06:40

1 Answers1

2

The pattern that GeneralizingAstVisitor does is pre-order.

In-order traversal doesn't make sense in the context of an AST. In-order traversal is left, root, right. But an AST branch may have anywhere from 1 to infinity children. So the best you could do is define some in-order(n) traversal, where you visit the first child, second child, ... nth-child, root, nth+1 child, nth+2 child... I don't see a purpose of this.

For post-order its a bit more nuanced. If all you want to do is print the node and its child entities, then your solution is simple. You just have to call super before printing the node:

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;
  }
}

But if you wanted custom logic for a bunch of node types, you'd have to follow that pattern in each visit handler:

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
}

In this case, I would compose visitors to make this easier:

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
}

In this case, PostOrderVisitor handles the post-ordering, and Visitor4 handles the individual nodes according to that order but should not do any recursion itself.

These should get you by for most use cases, though it's hard to be certain without knowing what you're trying to do.

Mike Fairhurst
  • 626
  • 5
  • 15
  • yeah this work, can you just explain the role of `node.accept(postOrderedVisitor)` in the code – Shubham Kumar Jul 26 '18 at 13:49
  • @ShubhamKumar (I'd recommend reading more about the visitor pattern, there are lots of great resources that can help!) The visitor pattern is a means of double dispatch. It calls some code for some combination of types. In this case, the type of the Node, and the type of the Visitor. So x.accept(y) will end up calling Y.visitX(). Since PostOrderVisitor handles the order, and Visitor4.visitX() handles the algorithm, we call "node.accept(postOrderedVisitor)" so that Visitor4.visitX() is performed. You could write "postOrderedVisitor.visitNode(node)" if the type of "node" is irrelevant to you. – Mike Fairhurst Jul 26 '18 at 19:55
  • Thank you very much for you time and help.it really sort some of my problems. i am just started working in dart-Analysis, it will be be very helpful if you share some docs or resources on it – Shubham Kumar Jul 26 '18 at 20:24
  • 1
    This is the best guide I found on the visitor pattern with some googling: https://manski.net/2013/05/the-visitor-pattern-explained/ Though its written for C#, so if you aren't familiar with method overloading then you may need to look that up. Otherwise the differences between C# and Dart are hopefully not large enough to be an issue – Mike Fairhurst Jul 27 '18 at 00:03