比如有个需求:
通过分析注解,来生成一段dart代码。
dart上如果要自动生成代码,那么就需要用到代码生成器,code generator,这和Android里面apt类似。一般我们会引用source_gen声明一些generator,然后放在build.yaml里面,调用build_runner来生成代码。
如果不想使用框架,而是自己手写这个过程呢?
1.从dart文件读入代码
2.分析代码,读出里面的annotation对应的value值。
3.根据value值,自己再生成代码字符串content
4.把代码字符串写到一个dart文件中
如果是简单的第二个过程,可以想到一种,通过正则匹配来读出对应的annotation里面的值。然后用来生成代码字符串content。如果类很复杂,那么自己来手动分析就会比较繁琐。
dart中有一个工具analyzer,来分析代码。它会把一段代码内容导入进来,进行分析,然后生成一个ast抽象语法树。
我们现在利用它写一个demo读取出dart里面的注解内容。
我们先定义好一些注解类:
class SFLegoClass{
final String host;
final String source;
const SFLegoClass(this.host,this.source);
}
class SFLegoField{
final String fieldAlias;
const SFLegoField(this.fieldAlias);
}
class SFLegoMethod{
final String method;
const SFLegoMethod(this.method);
}
@SFLegoClass("www.baidu.com", "dart")
class ExampleClass{
@SFLegoField("mason")
String name;
@SFLegoMethod("method1")
void myMethod(){
}
我们的目标是,读出注解类上的值。
import 'dart:io';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/analysis/utilities.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
main(List<String> args) {
read(File("annotation_example.dart"));
}
read(File file){
// print(file.readAsStringSync());
String content = file.readAsStringSync();
// RegExp regExp = RegExp("");
ParseStringResult result = parseString(content: content);
CompilationUnit unit = result.unit;
unit.visitChildren(MyVisitor());
}
class MyVisitor extends RecursiveAstVisitor{
@override
visitAnnotation(Annotation node) {
print("annotation node:"+node.toString()+",${node.name},${node.arguments}");
return super.visitAnnotation(node);
}
}
我们来分析一下上面的代码。
1.读出上面的类中的文件到一个字符串中
2.通过analyzer的静态方法parseString()来分析代码
3.取出其中的代码解析产物CompilationUnit
4.对其进行遍历
AstVistor里面定义了很多的方法,我们在遍历的过程中,就可以分别读到不通的内容。
abstract class AstVisitor<R> {
R visitAdjacentStrings(AdjacentStrings node);
R visitAnnotation(Annotation node);
R visitArgumentList(ArgumentList node);
R visitAsExpression(AsExpression node);
R visitAssertInitializer(AssertInitializer node);
R visitAssertStatement(AssertStatement assertStatement);
...
}
analyzer定义了一些基本的vistor实现类。
这里主要说一下RecursiveAstVisitor。
看名字就知道它会递归遍历整棵抽象语法树。我们可以用它来查找我们要的变量。运行一下上面的代码,得到如下结果。
我们就可以取出annotation里面的值了。本文仅借此例子来了解dart analyzer的用法。
此外,dart sdk还自带了dartAnalyzer工具,帮我们做静态代码分析。
比如在某个dart类中加入错误的一段代码。"A {"
它就能帮我们分析出其中错误的地方。