java 抽象语法树(AST)系列一:概述
java 抽象语法树解析
一、AST
AST abstract syntax tree (抽象语法结构树),是对java语言的一种抽象,每个节点都能对应到一种java语法,最终一个java文件就是由棵节点树构成
二、Tree
Tree是一个接口,是AST节点的抽象,内部有一个最重要的枚举Kind,定义了java中的每条语句的格式,也是对应着AST的一个节点
以下均为子接口,每个结构都定义了语法节点类型
Tree
- WildcardTree
- TypeParameterType
- StatementTree (一个完整的语句,比如简单的"int a = 1;",注意最后的“;”)
- ThrowTree
- ReturnTree
- TryTree
- ContinueTree
- BreakTree
- BlockTree
- DoWhileLoopTree
- ClassTree
- VariableTree
- WhileLoopTree
- ForLoopTree
- SwitchTree
- SynchronizedTree
- EnhancedForLoopTree
- LabeedStatementTree
- AssertTree
- EmptyStatementTree
- IfTree
- ExpressionStatementTree
- CatchTree
- MethodTree
- ArrayTypeTree
- UnionTypeTree
- ModifiersTree
- ParameterizedTypeTree
- CaseTree
- ExpressionTree (一个非完整的语句,比如简单的"a = 1",注意最后没有“;”)
- MemberReferenceTree
- LambdaExpressionTree
- UnaryTree
- MethodInvocationTree
- AnnotatedTypeTree
- CompoundAssignmentTree
- BinaryTree
- ErroneousTree
- MemberSelectTree
- ArrayAccessTree
- TypeCastTree
- NewClassTree
- ConditionalExpressionTree
- ParenthesizedTree
- AnnotationTree
- NewArrayType
- InstanceOfTree
- IdentifierTree
- AssignmentTree
- LiteralTree
- CompilationUnitTree
- IntersectionTypeTree
- PrimitiveTypeTree
- Import
三、Kind
AST 节点类型,对应着java的语法
枚举类型 | Tree节点(就是上面列出的接口) | 定义 | 示例 |
ANNOTATED_TYPE | AnnotatedTypeTree | 注解类型,可以用在任何类型上 注解的Target为:TYPE_PARAMETER TYPE_USE | @NotNull String |
ANNOTATION | AnnotationTree | 普通的注解 | @Data @JsonProperties(value="sdf") |
TYPE_ANNOTATION | AnnotationTree | 跟ANNOTATION,待验证有什么区别 | |
ARRAY_ACCESS | ArrayAccessTree | 数组访问 | array[3] |
ARRAY_TYPE | ArrayTypeTree | 数组类型 | int[] |
ASSIGNMENT | AssignmentTree | 赋值 | a = 1 |
BLOCK | BlockTree | 语句块 | {} { statements } static { statements } |
BREAK | BreakTree | break | break; break label; |
CASE | CaseTree | case 语句 | case expression:statements default: statements |
CATCH | CatchTree | catch 语句 | catch(parameter) block 注:这些语句会有嵌套问题 |
CLASS INTERFACE ENUM ANNOTATION_TYPE | ClassTree | class 定义 | modifiers class simpleName typeParameters extends extendsClause implements implementsClause { <em>members</em> } |
COMPILATION_UNIT | CompilationUnitTree | 一个编译单元 包括源文件和package-info.java | |
CONDITIONAL_EXPRESSION | ConditionalExpressionTree | 三元运算符 | a == 1 ? 1 : 0 |
CONTINUE | ContinueTree | continue 语句 | continue; continue label; |
DO_WHILE_LOOP | DoWhileLoopTree | do...while | |
ENHANCED_FOR_LOOP | EnhancedForLoopTree | 增强for | for(int i: intlist) { statement } |
EXPRESSION_STATEMENT | ExpressionStatementTree | 语句 | |
MEMBER_SELECT | MemberSelectTree | 对象.操作 | aClass.aparams |
MEMBER_REFERENCE | MemberReferenceTree | 成员引用表达式 | |
FOR_LOOP | ForLoopTree | for循环 | |
IDENTIFIER | IdentifierTree | 识别符,与literal区分开 | a = 1 a 就是一个identifier |
IF | IfTree | ||
IMPORT | ImportTree | ||
INSTANCE_OF | InstanceOfTree | instanceof 表达式 | |
LABELED_STATEMENT | LabeledStatementTree | label语法 | label : statement |
METHOD | MethodTree | 方法定义 | 方法 modifiers typeParameters type name (parameters ) body 注解 modifiers type name () default defaultValue |
METHOD_INVOCATION | MethodInvocationTree | method invoke语法 | |
MODIFIERS | ModifiersTree | 修饰符(Modifier) 包括注解 | |
NEW_ARRAY | NewArrayTree | ||
NEW_CLASS | NewClassTree | ||
LAMBDA_EXPRESSION | LambdaExpressionTree | lambda表达式 | |
PRIMITIVE_TYPE | PrimitiveTypeTree | 基础类型 | |
RETURN | ReturnTree | return | |
EMPTY_STATEMENT | EmptyStatementTree | 空的";" | |
SWITCH | SwitchTree | ||
SYNCHRONIZED | SynchronizedTree | ||
THROW | ThrowTree | ||
TRY | TryTree | ||
PARAMETERIZED_TYPE | ParameterizedTypeTree | 泛型 | List<Integer> |
UNION_TYPE | UnionTypeTree | 多变量声明 | try { }catch(Exception e1 | Exception e2){ } |
INTERSECTION_TYPE | IntersectionTypeTree | T extends MyA & MyB | |
TYPE_CAST | TypeCastTree | 强转语句 | (int)a |
TYPE_PARAMETER | TypeParameterTree | ||
VARIABLE | VariableTree | 变量 | modifiers type name initializer ; modifiers type qualified-name.this |
WHILE_LOOP | WhileLoopTree | ||
POSTFIX_INCREMENT POSTFIX_DECREMENT PREFIX_INCREMENT PREFIX_DECREMENT UNARY_PLUS UNARY_MINUS BITWISE_COMPLEMENT LOGICAL_COMPLEMENT | UnaryTree | 运算符 | ++、--、+、-、~、!、*、/、% |
MULTIPLY DIVIDE REMAINDER PLUS MINUS LEFT_SHIFT RIGHT_SHIFT UNSIGNED_RIGHT_SHIFT LESS_THAN GREATER_THAN LESS_THAN_EQUAL GREATER_THAN_EQUAL EQUAL_TO NOT_EQUAL_TO AND XOR OR CONDITIONAL_AND CONDITIONAL_OR | BinaryTree | 两元运算 | |
MULTIPLY_ASSIGNMENT DIVIDE_ASSIGNMENT REMAINDER_ASSIGNMENT PLUS_ASSIGNMENT MINUS_ASSIGNMENT LEFT_SHIFT_ASSIGNMENT RIGHT_SHIFT_ASSIGNMENT UNSIGNED_RIGHT_SHIFT_ASSIGNMENT AND_ASSIGNMENT XOR_ASSIGNMENT OR_ASSIGNMENT | CompoundAssignmentTree | 赋值运算符 | +=、-=、*= |
INT_LITERAL LONG_LITERAL FLOAT_LITERAL DOUBLE_LITERAL BOOLEAN_LITERAL CHAR_LITERAL STRING_LITERAL NULL_LITERAL | LiteralTree | 字面值 | a = 1 (1就是) |
OTHER | null |
四、JCTree
com.sun.tools.javac.tree.JCTree 是Tree的一个抽象实现类,有各种实现类,代表着一个个的AST节点
JC具体类 | 实现Tree | Tag | Kind | 备注 | |
LetExpr | LETEXPR | 不支持 | |||
JCErroneous | ErroneousTree | ERRONEOUS | ERRONEOUS | ||
JCAnnotatedType | AnnotatedTypeTree | ANNOTATED_TYPE | ANNOTATED_TYPE | ||
JCModifiers | ModifiersTree | MODIFIERS | MODIFIERS | ✅ | |
JCAnnotation | AnnotationTree | ✅ | |||
JCTypeParameter | TypeParameterTree | TYPEPARAMETER | TYPE_PARAMETER | ||
JCTypeIntersection | IntersectionTypeTree | TYPEINTERSECTION | INTERSECTION_TYPE | ||
JCTypeUnion | UnionTypeTree | TYPEUNION | UNION_TYPE | ||
JCTypeApply | ParameterizedTypeTree | TYPEAPPLY | PARAMETERIZED_TYPE | ||
JCArrayTypeTree | ArrayTypeTree | TYPEARRAY | ARRAY_TYPE | ||
JCPrimitiveTypeTree | PrimitiveTypeTree | TYPEIDENT | PRIMITIVE_TYPE | ✅ | |
JCLiteral | LiteralTree | LITERAL | INT_LITERAL LONG_LITERAL ... 以LITERAL结尾的 | ✅ | |
JCIdent | IdentifierTree | IDENT | IDENTIFIER | ✅ | |
JCMemberReference | MemberReferenceTree | REFERENCE | MEMBER_REFERENCE | ||
JCFieldAccess | MemberSelectTree | SELECT | MEMBER_SELECT | ✅ | |
JCArrayAccess | ArrayAccessTree | INDEXED | ARRAY_ACCESS | ✅ | |
JCInstanceOf | InstanceOfTree | TYPETEST | INSTANCE_OF | ||
JCTypeCast | TypeCastTree | TYPE_CAST | TYPECAST | ||
JCBinary | BinaryTree | 根据操作符定 | 根据tag映射 | ||
JCAssignOp | CompoundAssignmentTree | 赋值,根据操作符定 支持的是 “+=”这种 | 根据tag映射 | ||
JCAssign | AssignmentTree | ASSIGN 支持的是直接赋值 | ASSIGNMENT | ✅ | |
JCParens | ParenthesizedTree | PARENS | PARENTHESIZED | ||
JCLambda | LambdaExpressionTree | LAMBDA | LAMBDA_EXPRESSION | ||
JCNewArray | NewArrayTree | NEWARRAY | NEW_ARRAY | ||
JCNewClass | NewClassTree | NEWCLASS | NEW_CLASS | ||
JCMethodInvocation | MethodInvocationTree | APPLY | METHOD_INVOCATION | ||
JCAssert | AssertTree | ASSERT | ASSERT | ||
JCThrow | ThrowTree | THROW | THROW | ✅ | |
JCReturn | ReturnTree | RETURN | RETURN | ✅ | |
JCContinue | ContinueTree | CONTINUE | CONTINUE | ||
JCBreak | BreakTree | BREAK | BREAK | ||
JCExpressionStatement | ExpressionStatementTree | EXEC | EXPRESSION_STATEMENT | ||
JCIf | IfTree | IF | IF | ||
JCConditional | ConditionalExpressionTree | CONDEXPR | CONDITIONAL_EXPRESSION | ||
JCCatch | CatchTree | CATCH | CATCH | ||
JCTry | TryTree | TRY | TRY | ||
JCSynchronized | SynchronizedTree | SYNCHRONIZED | SYNCHRONIZED | ||
JCCase | CaseTree | CASE | CASE | ||
JCSwitch | SwitchTree | SWITCH | SWITCH | ||
JCLabeledStatement | LabeledStatementTree | LABELLED | LABELED_STATEMENT | ||
JCEnhancedForLoop | EnhancedForLoopTree | FOREACHLOOP | ENHANCED_FOR_LOOP | ||
JCForLoop | ForLoopTree | FORLOOP | FOR_LOOP | ||
JCWhileLoop | WhileLoopTree | WHILELOOP | WHILE_LOOP | ||
JCDoWhileLoop | DoWhileLoopTree | DOLOOP | DO_WHILE_LOOP | ||
JCBlock | BlockTree | BLOCK | BLOCK | ||
JCSkip | EmptyStatementTree | SKIP | EMPTY_STATEMENT | ||
JCVariableDecl | VariableTree | VARDEF | VARIABLE | ✅ | |
JCMethodDecl | MethodTree | METHODDEF | METHOD | ✅ | |
JCClassDecl | ClassTree | CLASSDEF | ANNOTATION_TYPE INTERFACE ENUM CLASS | ✅ | |
JCImport | ImportTree | IMPORT | IMPORT | ✅ | |
JCCompilationUnit | CompilationUnitTree | TOPLEVEL | COMPILATION_UNIT |
五、JC类的Factory
细心阅读会发现,各种JC类的构造函数都是protected,也就是说,并不能直接进行初始化,所以现在要使用Factory,Factory是各种JC类的工厂定义
六、TreeMaker
TreeMaker实现了Factory接口,所以我们它会是我们经常使用的一个类
还需要关注的一个Names,这个基本是创建一个节点的开始
Names: 用来存储和表示解析后的词法,每个字符集合都会是一个Name对象,所有的对象都存储在Name.Table内部类中。
在学习以下内容时,一定要熟练掌握JCIdent和Names。
javac源码笔记与简单的编译原理 | Ren's Time Overflow Skyline ^_^
6.1、添加 import
// import com.leisure.lombok.thrift.AstTreeClass
// 获取标识符
JCTree.JCIdent jcIdent = treeMaker.Ident(names.fromString("com.leisure.lombok.thrift"));
// 获取标识符
Name className = names.fromString("AstTreeClass");
// 定义访问
JCTree.JCFieldAccess jcFieldAccess = treeMaker.Select(jcIdent, className);
// 添加import节点
JCTree.JCImport anImport = treeMaker.Import(jcFieldAccess, false);
// 加入AST树种
jcCompilationUnit.defs = jcCompilationUnit.defs.append(anImport);
6.2、定义属性
默认构造函数
//private AstTreeClass variable = new AstTreeClass()
// new AstTreeClass()
JCTree.JCNewClass newClass = treeMaker.NewClass(null, null, treeMaker.Ident(names.fromString("AstTreeClass")), List.nil(), null);
// private AstTreeClass variable = ...
JCTree.JCVariableDecl variableDecl = treeMaker.VarDef(treeMaker.Modifiers(Modifier.PRIVATE.ordinal()),
names.fromString("variable"), treeMaker.Ident(names.fromString("AstTreeClass")), newClass);
带参数的构造函数
使用这个我们就可以实现@Slf4j了(当然了,还需要有插件,才能真正像@Slf4j一样使用)
//public static final AstTreeClass staticVariable = new AstTreeClass(1)
JCTree.JCLiteral constantOne = treeMaker.Literal(1);
JCTree.JCNewClass newClass1 = treeMaker.NewClass(null, null, treeMaker.Ident(names.fromString("AstTreeClass")), List.of(constantOne), null);
JCTree.JCVariableDecl staticVariableDecl = treeMaker.VarDef(
treeMaker.Modifiers(Flags.PUBLIC + Flags.STATIC + Flags.FINAL),
names.fromString("staticVariable"),
treeMaker.Ident(names.fromString("AstTreeClass")),
newClass1
);
6.4、添加方法
String name = variableDecl.name.toString();
JCTree.JCExpression varType = variableDecl.vartype;
// getter,假设name长度大于1
String getterMethodName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
// this.name
JCTree.JCExpression thisName = treeMaker.Select(treeMaker.This(classDecl.sym.type), names.fromString(name));
JCTree.JCReturn jcReturn = treeMaker.Return(thisName);
// public type getName() {return this.name;}
JCTree.JCMethodDecl getter = treeMaker.MethodDef(
treeMaker.Modifiers(Flags.PUBLIC), // 访问标识
names.fromString(getterMethodName), // 方法名字
varType, // 返回类型
List.nil(), // 泛型形参列表
List.nil(), // 参数列表
List.nil(), // 异常列表
treeMaker.Block(0, List.of(jcReturn)), // block
null // 默认方法
);
// setter
// public void setName(nameType name) {this.name = name;}
String setterMethodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
// 这里只是生成了this.name = name表达式
JCTree.JCAssign assign = treeMaker.Assign(thisName, treeMaker.Ident(names.fromString(name)));
// 生成一条语句 this.name = name;
JCTree.JCExpressionStatement assignStat = treeMaker.Exec(assign);
JCTree.JCMethodDecl setterMethodDecl = treeMaker.MethodDef(
treeMaker.Modifiers(Flags.PUBLIC), // 访问标识
names.fromString(setterMethodName), // 方法名
treeMaker.TypeIdent(TypeTag.VOID), // 返回类型
List.nil(), // 泛型形参列表
List.of(treeMaker.VarDef(
treeMaker.Modifiers(Flags.PARAMETER), // 普通参数
variableDecl.name,
varType,
null // 初始化为空,方法入参时为空即可
)
), // 参数列表
List.nil(), // 异常列表
treeMaker.Block(0, List.of(assignStat)), // 方法体
null //默认方法
);
解决TreeMaker AssertionError: Value of x -1_你倒是跑啊的博客-CSDN博客
TreeMaker -> JCTree -> Tree ,接下来的一系列就是应用了
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)