Skip to content

Commit

Permalink
Added annotation and enum annotation element values
Browse files Browse the repository at this point in the history
  • Loading branch information
jumanji144 committed May 7, 2022
1 parent e0b1f6e commit e490052
Show file tree
Hide file tree
Showing 11 changed files with 158 additions and 22 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ dependencies {
implementation 'org.ow2.asm:asm-tree:9.3'

testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.2'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
testCompileOnly 'org.projectlombok:lombok:1.18.24'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.24'
Expand Down
5 changes: 5 additions & 0 deletions examples/Annotations.ja
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ field number I

invisible-annotation me/coley/InsnComment
value "This is a comment"
annotation annotation me/coley/CommentComment
value "Sub comment"
list args "This is a sub-list" end
end
target enum java/lang/annotation/RetentionPolicy RUNTIME
list args "Hello World" end
end
method public static main([Ljava/lang/String;)V
Expand Down
27 changes: 27 additions & 0 deletions src/main/java/me/darknet/assembler/compiler/Debug.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package me.darknet.assembler.compiler;

import java.lang.annotation.ElementType;

@interface Exported {
String value();

@interface E {
String value();
}
}

@interface BuildConfig {

@Exported("BUILD_TYPE")
ElementType[] value();

Exported value2();

String value3();
}

@BuildConfig(value = {ElementType.FIELD}, value2 = @Exported("BUILD_TYPE"), value3 = "debug")
public class Debug {


}
Original file line number Diff line number Diff line change
Expand Up @@ -121,16 +121,41 @@ public MethodVisitor visitMethod(AccessModsGroup accessMods, IdentifierGroup des
return new ASMBaseMethodVisitor(mv, md, currentClass, isStatic);
}

public void paramValue(String name, Group value, AnnotationVisitor av) throws AssemblerException{

if(value.type == GroupType.ARGS){
ArgsGroup args = (ArgsGroup) value;
AnnotationVisitor arrayVis = av.visitArray(name);
for (Group group : args.getBody().children) {
paramValue(name, group, arrayVis);
}
arrayVis.visitEnd();
} else if(value.type == GroupType.ENUM) {
EnumGroup enumGroup = (EnumGroup) value;
av.visitEnum(name, enumGroup.getDescriptor().content(), enumGroup.getEnumValue().content());
} else if(value.type == GroupType.ANNOTATION) {
AnnotationGroup annotationGroup = (AnnotationGroup) value;
AnnotationVisitor annotationVis = av.visitAnnotation(name, annotationGroup.getClassGroup().content());
for(AnnotationParamGroup param : annotationGroup.getParams()) {
annotationParam(param, annotationVis);
}
annotationVis.visitEnd();
} else {
av.visit(name, value.content());
}

}

public void annotationParam(AnnotationParamGroup annotationParam, AnnotationVisitor av) throws AssemblerException {
if(annotationParam.value.type == GroupType.ARGS) {
ArgsGroup args = (ArgsGroup) annotationParam.value;
AnnotationVisitor arrayVis = av.visitArray(annotationParam.name.content());
for (Group group : args.getBody().children) {
arrayVis.visit("", GroupUtil.convert(currentClass, group));
paramValue(annotationParam.name.content(), group, arrayVis);
}
arrayVis.visitEnd();
}else {
av.visit(annotationParam.name.content(), GroupUtil.convert(currentClass, annotationParam.value));
paramValue(annotationParam.name.content(), annotationParam.value, av);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ public enum AnnotationTarget {
FIELD,
METHOD,
CLASS,
UNKNOWN
}
1 change: 1 addition & 0 deletions src/main/java/me/darknet/assembler/parser/Group.java
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ public enum GroupType {

ANNOTATION,
ANNOTATION_PARAMETER,
ENUM,
INVISIBLE_ANNOTATION,
INSTRUCTION,
STACK_LIMIT,
Expand Down
54 changes: 46 additions & 8 deletions src/main/java/me/darknet/assembler/parser/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ public class Parser {
public static final String KEYWORD_PUBLIC = "public";
public static final String KEYWORD_PRIVATE = "private";
public static final String KEYWORD_PROTECTED = "protected";
public static final String KEYWORD_SYNCHRONIZED = "synchronized";
public static final String KEYWORD_VOLATILE = "volatile";
public static final String KEYWORD_TRANSIENT = "transient";
public static final String KEYWORD_NATIVE = "native";
public static final String KEYWORD_ABSTRACT = "abstract";
public static final String KEYWORD_STRICT = "strictfp";
public static final String KEYWORD_EXTENDS = "extends";
public static final String KEYWORD_IMPLEMENTS = "implements";
public static final String KEYWORD_FINAL = "final";
Expand All @@ -35,7 +41,8 @@ public class Parser {
public static final String KEYWORD_ARGS = "args";
public static final String KEYWORD_TYPE = ".type";
public static final String KEYWORD_ANNOTATION = "annotation";
public static final String KEYWORD_INVISBLE_ANNOTATION = "invisible-annotation";
public static final String KEYWORD_INVISIBLE_ANNOTATION = "invisible-annotation";
public static final String KEYWORD_ENUM = "enum";
private static final String[] keywords = {
KEYWORD_CLASS,
KEYWORD_METHOD,
Expand All @@ -60,9 +67,26 @@ public class Parser {
KEYWORD_ARGS,
KEYWORD_TYPE,
KEYWORD_ANNOTATION,
KEYWORD_INVISBLE_ANNOTATION
KEYWORD_INVISIBLE_ANNOTATION,
KEYWORD_TRANSIENT,
KEYWORD_VOLATILE,
KEYWORD_STRICT,
KEYWORD_NATIVE,
KEYWORD_ABSTRACT,
};

public static final List<String> accessModifiers = Arrays.asList(
"public",
"private",
"protected",
"static",
"final",
"synchronized",
"native",
"abstract",
"strictfp"
);

public List<Token> tokenize(String source, String code) {

List<Token> tokens = new ArrayList<>();
Expand Down Expand Up @@ -333,17 +357,14 @@ public Group group(ParserContext ctx) throws AssemblerException {
case KEYWORD_ARGS: {
return new ArgsGroup(token, readBody(ctx));
}
case KEYWORD_INVISBLE_ANNOTATION:
case KEYWORD_INVISIBLE_ANNOTATION:
case KEYWORD_ANNOTATION: {
List<AnnotationParamGroup> params = new ArrayList<>();
IdentifierGroup classGroup = ctx.explicitIdentifier();
while(ctx.hasNextToken()) {
IdentifierGroup name = ctx.explicitIdentifier();
if(name.content().equals(KEYWORD_END)) {
Token next = ctx.peekToken();
if(next.type != KEYWORD) {
throw new AssemblerException("Expected annotation target", next.location);
}
AnnotationTarget target;
switch (next.content) {
case KEYWORD_FIELD:
Expand All @@ -356,9 +377,19 @@ public Group group(ParserContext ctx) throws AssemblerException {
target = AnnotationTarget.CLASS;
break;
default:
throw new AssemblerException("Invalid annotation target", next.location);
target = AnnotationTarget.UNKNOWN;
break;
}
return new AnnotationGroup(token, target, token.content.equals(KEYWORD_INVISBLE_ANNOTATION), classGroup, params.toArray(new AnnotationParamGroup[0]));
return new AnnotationGroup(token, target, token.content.equals(KEYWORD_INVISIBLE_ANNOTATION), classGroup, params.toArray(new AnnotationParamGroup[0]));
}
Token next = ctx.peekToken();
// enum intrinsic annotation
if(next.content.equals(KEYWORD_ENUM)) {
Token enumToken = ctx.nextToken();
IdentifierGroup enumGroup = ctx.explicitIdentifier();
IdentifierGroup enumValue = ctx.explicitIdentifier();
params.add(new AnnotationParamGroup(name.value, name, new EnumGroup(enumToken, enumGroup, enumValue)));
continue;
}
Group param = ctx.parseNext();
params.add(new AnnotationParamGroup(name.value, name, param));
Expand All @@ -368,8 +399,15 @@ public Group group(ParserContext ctx) throws AssemblerException {

case KEYWORD_PUBLIC:
case KEYWORD_PRIVATE:
case KEYWORD_PROTECTED:
case KEYWORD_STATIC:
case KEYWORD_FINAL:
case KEYWORD_SYNCHRONIZED:
case KEYWORD_VOLATILE:
case KEYWORD_TRANSIENT:
case KEYWORD_NATIVE:
case KEYWORD_ABSTRACT:
case KEYWORD_STRICT:
return new AccessModGroup(token);

}
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/me/darknet/assembler/parser/ParserContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ public void pushGroup(Group group) {
groups.add(group);
}

/**
* Reads the next token and directly interprets it as an identifier group
* @return identifier group
*/
public IdentifierGroup explicitIdentifier() {
return new IdentifierGroup(nextToken());
}
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/me/darknet/assembler/parser/groups/EnumGroup.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package me.darknet.assembler.parser.groups;

import lombok.Getter;
import me.darknet.assembler.parser.Group;
import me.darknet.assembler.parser.Token;

public class EnumGroup extends Group {

@Getter
IdentifierGroup descriptor;
@Getter
IdentifierGroup enumValue;

public EnumGroup(Token token, IdentifierGroup descriptor, IdentifierGroup value) {
super(GroupType.ENUM, token, descriptor, value);
this.descriptor = descriptor;
this.enumValue = value;
}

}
32 changes: 20 additions & 12 deletions src/test/java/CompilerTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
import me.darknet.assembler.parser.AssemblerException;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.io.IOException;
import java.io.InputStream;
Expand Down Expand Up @@ -42,20 +45,25 @@ public static void loadAllExamples() throws IOException {
}
}

@Test
public void testAllExamples() throws AssemblerException {
public static List<Arguments> getFeatures() {
List<Arguments> args = new ArrayList<>(features.size());
for (int i = 0; i < features.size(); i++) {
String feature = features.get(i);
byte[] bytes = featuresBytes.get(i);
System.out.print("Testing " + feature);
try {
Assembler.assemble(feature, 52, bytes);
} catch (Exception e) {
System.out.println(" FAILED");
continue;
}
System.out.println("... OK");
args.add(Arguments.of(features.get(i), featuresBytes.get(i)));
}
return args;
}

@ParameterizedTest
@MethodSource("getFeatures")
public void testExample(String feature, byte[] bytes) throws AssemblerException {
System.out.print("Testing " + feature);
try {
Assembler.assemble(feature, 52, bytes);
} catch (Exception e) {
System.out.println(" FAILED");
return;
}
System.out.println("... OK");
}

}
6 changes: 6 additions & 0 deletions src/test/resources/features/Annotations.ja
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ field number I

invisible-annotation me/coley/InsnComment
value "This is a comment"
annotation annotation me/coley/CommentComment
value "Sub comment"
list args "This is a sub-list" end
enum enum java/lang/annotation/Target FIELD
end
target enum java/lang/annotation/RetentionPolicy RUNTIME
list args "Hello World" end
end
method public static main([Ljava/lang/String;)V
Expand Down

0 comments on commit e490052

Please sign in to comment.