koresframework / kores Goto Github PK
View Code? Open in Web Editor NEWGenerate source code & bytecode from an abstract representation tree (AST). Bytecode generation framework.
Home Page: http://koresframework.github.io/Kores/
License: Other
Generate source code & bytecode from an abstract representation tree (AST). Bytecode generation framework.
Home Page: http://koresframework.github.io/Kores/
License: Other
Historically CodeArgument
was a important class for methods and arrays because it held the type of the value, but now CodeArgument
doesn't keep types anymore and is only a Box for CodePart
, remove this class will not be a problem.
Create a class loader that loads TypeDefinition.
class CodeClassLoader {
Map<String, SavedClass>
CodeClassLoader(boolean store)
defineClass(TypeDefinition, byte[])
}
class SavedClass {
TypeDefinition
byte[]
}
Actually is hard to search the cause of error in the generated class.
Helper.tagLine(Identifier, CodeSource);
BytecodeGenerator(sourceFile: File)
Convert CodeAPI to Kotlin 1.1.
After that, we can re-write some CodeAPI parts (like gen.visit.Common
class).
Resolves CodeType
to a Class
and a TypeElement
(javax.model
) using a CodeTypeResolver
.
interface CodeTypeResolver<out T> {
fun resolve(codeType: CodeType): T
class JavaClass(val classLoader: ClassLoader): CodeTypeResolver<Class<*>> { ... }
class TypeElement(val elements: Elements): CodeTypeResolver<TypeElement> { ... }
}
Implement else statement (easy)
After 3.0 rewrite, the immutability problem returns, we could resolve this using builders, but it will require a lot of code to be written, we could also resolve using pseudo-setters (or partial copy) like we did in 2.0:
Builder:
interface ModifiersHolder : CodePart {
val modifiers: List<CodeModifier>
fun builder(): ModifiersHolderBuilder
}
public interface Builder extends builder.Builder<T, S> {
Builder withModifiers(List<CodeModifier> value);
}
Pseudo-Setter (or partial copy):
interface ModifiersHolder : CodePart {
val modifiers: List<CodeModifier>
fun setModifiers(modifiers: List<CodeModifier>): ModifiersHolder
}
The problem of either is that exposes things that I don't like to expose, example: StaticBlock
extends MethodDeclaration
and MethodDeclaration
extends ModifiersHolder
, pseudo-setters and Builders will expose setModifiers
to StaticBlock
, we could only ignore the call of the method (like we did in 2.0).
3.0 will be postponed until this issue being resolved.
Implement bitwise and negation (-
) operations.
OperateHelper.operate(INT(9)).neg().build(); // -9
OperateHelper.operate(INT(9)).or(INT(10)).build(); // 9 | 10
OperateHelper.operate(INT(9)).xor(INT(10)).build(); // 9 ^ 10
OperateHelper.operate(INT(9)).not(INT(10)).build(); // in Java: 9 - ~10, desugar: 9 - (10 ^ -1)
OperateHelper.operate(INT(9)).and(INT(10)).build(); // 9 & 10
OperateHelper.operate(INT(9)).shiftRight(INT(10)).build(); // 9 >> 10
OperateHelper.operate(INT(9)).logicalShiftRight(INT(10)).build(); // 9 >>> 10
OperateHelper.operate(INT(9)).shiftLeft(INT(10)).build(); // 9 << 10
Create enums:
Base class: EnumDeclaration
, implementation: CodeEnum
.
Entry: EnumEntry
, implementation: EnumEntryImpl
Get entry ordinal: EnumDeclaration.getOrdinal(EnumEntry)
and EnumDeclaration.getOrdinal(Predicate<EnumEntry>)
.
Example code:
interface A {
void test();
}
CodeEnum declaration = CodeAPI.enumBuilder()
.withModifiers(Modifier.PUBLIC)
.withQualifiedName("com.MyEnum")
.withImplementations(A.class)
.withEntries(
CodeAPI.enumEntry("A", CodeAPI.sourceOfParts(...)), // Implements/override the method
CodeAPI.enumEntry("B", CodeAPI.typeSpec(int.class), CodeAPI.arguments(CodeAPI.argument(Literals.INT(0))), CodeAPI.sourceOfParts(...)), // Calling constructor
)
//.withBody(CodeAPI.sourceOfParts(...)) or implements/override methods here.
.build();
ModuleDeclaration module = ModuleDeclarationBuilder().builder()
.withName("my.module.name")
.withRequires("required_module"); // withRequires({module: ModuleDeclaration|String}[, modifier: CodeModifier])
.withExports("my.module") // withExports({module: ModuleDeclaration|String}[, to: List<ModuleDeclaration>]
.withUses("java.sql") // withUses({module: ModuleDeclaration|String})
.withProvides("my.module.Service", "my.module.ServiceImpl") // withProvides({type: CodeType|String?}, {impl: CodeType|String?})
.build()
Actually only PlainSourceGenerator can translate inner classes.
class A {
class B {
}
}
Will be translated into:
class A {}
class B {
B(A);
}
and
class A {
class B {
class C {
}
}
}
Will be translated into:
class A {}
class B {
B(A)
}
class C {
C(A, B)
}
Implementation of annotations:
Modules:
CodeAPI Base
CodeAPI Source Generation
CodeAPI Bytecode Generation
CodeAPI Bytecode translator
CodeAPI Java Source Translator¹
¹ = Maybe not be implemented because CodeAPI will need to resolve types and method overloading.
<init>
<clinit>
Support ASM-Dex (Dalvik class generation).
Actually is hard to write readable code with Code API, example:
...
CodeMethod codeMethod = new CodeMethod("getName", String.class, Collections.singletonList(CodeModifier.PUBLIC), sourceOf(
returnValue(accessVariable(accessThis(), "name", String.class))
));
...
Simplified:
....
CodeMethod codeMethod = publicMethod("getName", String.class,
source(returnThisField(String.class, "name"));
...
...
Ability to register SugarSyntax<T>
.
<T extends CodePart> registerSugarSyntax(Class<T> type, SugarSyntax<T> sugar)
The SugarSyntax<T>
will be wrapped into a SugarSyntaxVisitor
or SugarSyntaxGenerator
, that will delegate the generation of T
into sugar.Generator<T>
.
Sugar Syntax, (bytecode: Try-With-Resources generator will generate CodeAPI instructions and send to visitor).
Helper.tryWithResources(VariableDeclarations {Closeable} [declarations], CodeSource [body])
Helper.tryWithResources(VariableDeclarations {Closeable} [declarations], CodeSource [body], CodeSource [finally])
Helper.tryWithResources(VariableDeclarations {Closeable} [declarations], CodeSource [body], CatchBlocks [catchExceptions])
Helper.tryWithResources(VariableDeclarations {Closeable} [declarations], CodeSource [body], CatchBlocks [catchExceptions], CodeSource [finally])
TryBlockProcessor: Support Argumenterizable
TryWithResourcesProcessor: [TryBlockProcessor]
TryWithResourcesVisitor: Visit Variables, Generate finally block, unify generated finally blocks with FinallyBlockSource and send to TryCatchBlockVisitor.
Add Setter methods.
Example:
interface Named {
Named setName(String name);
}
Implementations MUST implements setter methods.
Java source generics is generated incorrectly.
Example:
Generic.type(Map).of(String).of(Integer)
Is converted to:
Map< String > & < Integer >
Save a disassembled version of classes saved by ResultSaver and add it to git.
interface InstructionVisitor<T> {
T visit(T part, MapData data, InstructionVisitManager manager)
}
class InstructionVisitManager<T> {
<P extends CodePart> register(Class<P> type, InstructionVisitor<P> visitor);
<P extends CodePart> P visit(P part, MapData data)
T visit(T part)
}
Actually only source code primitive cast is supporte.
Add builders of:
MethodInvocation
WhileBlock
, Do-WhileBlock
, IfBlock
, ForBlock
, ForEachBlock
, SwitchBlock
, TryBlock
.Options:
ifExpression(notNull(#), source)
- # != Null
ifExpression(lessThan(#, #), source)
#:1 < #:2
ifExpression(greaterThan(#, #), source)
#:1 > #:2
ifExpression(equalTo(#, #), source)
#:1 == #:2
ifExpression(equals(#, #), source)
#:1.equals(#:2)
ifExpression(not(?), source)
? == false
Pros
Cons
ifExpression(ifExpr(access("X", int), Operators.LESS_THAN, access("Y", int)), source)
Pros
Cons
Conversions:
TypeMirror
to CodeType/GenericType
TypeElement
to CodeType/GenericType
(Not same as TypeMirror beucase TypeMirror is a type and not a declaration)Add options:
Finally:
Foreach:
Currently anonymous classes are not supported (and cannot be expressed) because of problems with CodeAPI-BytecodeWriter
, but in 4.0.0 we plan to fix and improve the inner class handling system of CodeAPI-BytecodeWriter
.
Expressing anonymous classes:
ClassFactory.anonymousClass(superClass: CodeType, constructorSpec: TypeSpec, arguments: List<Code>, constructorBody: CodeSource, body: CodeSource) {}
The actual workaround is creating a local class and instantiating it.
Option
with default value true
.Class:
interface Concat extends CodePart {
List<CodePart> getConcatParts();
}
class ConcatHelper {
ConcatHelper();
ConcatHelper(CodePart part);
//////////////////////////////////////////////////
ConcatHelper append(CodePart part);
//////////////////////////////////////////////////
Concat build();
}
Example:
Concat concat = CodeAPI.concatHelper(STRING("Hello ")).append(accessLocalVariable("name", String.class)).append(" :D").build();
Make CodeSource
immutable and a mutable version (MutableCodeSource
)
Generate bytecode for Try Catch blocks.
codeapi.visitorgenerator
was first a prototype, but now became as permanent implementation. A rewrite of some classes may be good.
Currently CodeAPI does not validate the structure, it means that you can add a VariableDeclaration
to the body of a TypeDeclaration
, which is invalid.
Introduce a Validator
class, validation rules may vary depending on the Validator
. CodeGenerator
s may provide your own version of Validator
, the provided Validator
will check structure against the rules of the CodeGenerator
.
Local classes already can be expressed in CodeAPI, but no test code is provided.
Generate package-private accessor if a inner class call/access the outer class private members.
Generating switch:
Support only Number Literal
and String Literal
, generate tableswitch
and lookupswitch
.
Code:
CodeAPI.switch(CodeAPI.accessLocalVariable(int.class, "a"), CodeAPI.case(Literals.INT(1), <CodeSource>), CodeAPI.case(Literals.INT(3), <CodeSource>)); // Table Switch.
CodeAPI.switch(CodeAPI.accessLocalVariable(int.class, "a"), CodeAPI.case(Literals.INT(10), <CodeSource>), CodeAPI.case(Literals.INT(1000), <CodeSource>)); // Lookup switch.
The purpose of 3.0 refactor is to cleanup the structure and decrease amount of classes.
The class names is changed to a "clearer and easier" form.
3.0 refactor notes:
interfaces
-> base
.impl
moved to base
.MultiBodied
.PackageDeclaration
.Helper
classCodeAPI
methods in favour of buildersTagLine
in favour of new debugging features (see CodeAPI Bytecode debugging).MethodInvocation
extends ArgumentHolder
MethodSpecification
doesn't extends ArgumentHolder
anymore.Break
and Continue
replaced by ControlFlow
.AccessLocal
, AccessThis
, AccessOuter
and AccessSuper
replaced by Access
.Returnable
renamed to ReturnTypeHolder
.Casted
renamed to Cast
.VariableDeclaration
now extends VariableBase
instead of VariableAccess
.VariableOperate
now extends VariableAccess
instead of VariableDeclaration
.VariableOperate
, now generators should improve the Operate
Operate
now extends ValueHolder
.DoWhileBlock
replaced by WhileBlock.Type
.IfExpressionable
renamed to IfExpressionHolder
.Bodied
renamed to BodyHolder
.Implementer
renamed to ImplementationHolder
.Generifiable
renamed to GenericSignatureHolder
.Argumenterizable
renamed to ArgumentHolder
.Extender
renamed to SuperClassHolder
.Valuable
renamed to ValueHolder
.Modifierable
renamed to ModifiersHolder
.*Block
renamed to *Statement
.InstanceOf
renamed to InstanceOfCheck
Parameterizable
renamed to ParametersHolder
Return
extends ValueHolder
StaticBlock
extends ConstructorDeclaration
(Class constructor) instead of MethodDeclaration
FieldDeclaration
and VariableDeclaring
is not the same anymore (it includes all base classes of FieldBase
and VariableBase
)Important
Optional<T>
will be replaced by @Nullable
and @NotNull
annotations of JetBrains. (probably all Optional<T>
)
Not all changes are listed here.
WIP
Change from private BuilderGen
to BuilderGenerator
CodeAPI only generates if_icmp
opcode, but the comparsion of two doubles, floats and longs must be desugared:
lcmp //or dcmp(l/g) or fcmp(l/g)
if you try to compare two longs... boom:
java.lang.VerifyError: Bad type on operand stack
Exception Details:
Location:
me/jonathanscripter/codeapi/test/SimpleTest2_bytecode.<init>(Ljava/lang/String;)V @37: if_icmpge
Reason:
Type long_2nd (current frame, stack[3]) is not assignable to integer
Current Frame:
bci: @37
flags: { }
locals: { 'me/jonathanscripter/codeapi/test/SimpleTest2_bytecode', 'java/lang/String' }
stack: { long, long_2nd, long, long_2nd }
Bytecode:
0x0000000: 2ab7 000c 2a2b b500 0e2b c600 0db2 0014
0x0000010: 2bb6 0019 a700 0bb2 0014 121b b600 1914
0x0000020: 001c 1400 1ea2 000e b200 1412 21b6 0019
0x0000030: a700 0bb2 0014 1223 b600 19b1
Stackmap Table:
full_frame(@23,{Object[#3],Object[#37]},{})
same_frame(@31)
same_locals_1_stack_item_frame(@51,Long)
same_locals_1_stack_item_frame(@59,Long)
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
at java.lang.Class.getConstructor0(Class.java:3075)
at java.lang.Class.getConstructor(Class.java:1825)
at com.github.jonathanxd.codeapi.test.bytecode.SimpleTest2_Bytecode.simpleTest(SimpleTest2_Bytecode.java:150)
This fix will be cherry picked into version 2.0 (master) later.
If you have a class like:
class MyClass<T extends Iterable<?>> {
void iterate(T iter) {...}
}
CodeAPI will erases to:
class MyClass {
void iterate(Iterable i);
}
If you try to extend using CodeAPI and Override the method with a different signature (matching the generic type) and calls the iterable
method, it will throw AbstractMethodError. Example:
class V extends MyClass<List<?>> {
void iterate(List<?> list) { ... }
}
Iterable<String> iterable = new ArrayList<>();
MyClass<?> m = new V();
m.iterate(iterable); // AbstractMethodError. Only iterable(List) exists and has no bridge method.
CodeAPI would to generate:
class V extends MyClass<List<?>> {
void iterate(List<?> list) { ... }
bridge void iterate(Iterable<?> iterable) {
this.iterate((List<?>) iterable);
}
}
Change versioning template of sub-modules:
Current template: {Current Module Version}
Proposed template: {CodeAPI Module Version}_{Current Module Version}
Example:
CodeAPI: 3.1.0 and CodeAPI-BytecodeWriter: 3.1.1 = 3.1.0-3.1.1
Implementation of generics.
GenericType
Generifiable
interfaceGenerics.fill(GenericType, CodeType, CodeInterface|Field|Method|Variable)
: Fill all generic types.Base: AnnotationDeclaration
, Implementation: CodeAnnotation
Property: AnnotationProperty
, Implementation: AnnotationPropertyImpl
Example:
AnnotationDeclaration annotation = CodeAPI.annotationBuilder()
.withModifiers(Modifier.PUBLIC)
.withQualifiedName("com.MyAnnotation")
.withProperties(CodeAPI.property(String.class, "value"), CodeAPI.property(MyEnum.class, "type", CodeAPI.enumValue(MyEnum.class, "NONE")))
.build();
Currently CodeAPI compiles
if(a == true) { System.out.println("true"); }
to:
aload 1 // boolean a
iconst_0 // bolean false
if_icmpeq 123 // if (a == false) goto 123
getstatic java/lang/System.out:Ljava/io/PrintStream;
ldc "true"
invokevirtual java/io/PrintStream.println:(Ljava/lang/String;)V
123:
But the better (and javac-like) result is:
aload 1 // boolean a
ifeq 123 // branch if value1 == 0
getstatic java/lang/System.out:Ljava/io/PrintStream;
ldc "true"
invokevirtual java/io/PrintStream.println:(Ljava/lang/String;)V
123:
Add base.CommentHolder
that holds a CommentHolder.Type
and a List<Comment>
.
CommentHolder.Type
:
COMMENT
DOCUMENTATION
Comment
:
val Array<Comment>
class Plain(val plain: String) : Comment
class Link(val qualifiedName: String) : Comment
class Code(val code: String) : Comment
In 442908e we introduced a identification
property (It broke backward compatibility), the identification
property fixed a lot of comparison issues, but a lot of comparison codes remains using the old object comparison (see Identity
class). The identification
property always have the correct identification, no matter the structure of the CodeType
, the purpose is to switch all comparsion codes (and hashCode methods) to identification
comparison (and hash).
A lot of comparison tests should be write to make sure that the identification
will be always consistent. #
The implementation of Class
methods like isAssignableFrom
was avoided because CodeType can have different implementations (LoadedCodeType, PlainCodeType, TypeDeclaration, and so on), but in version 4.0 the type resolution will be implemented and it brings the possibility to implement methods like isAssignableFrom
, for PlainCodeType
, an exception will be throw (only if the type cannot be resolved). Other methods like getSupertype
and getInterfaces
may be implemented. TypeDeclaration does not extends SuperClassHolder
and ImplementationHolder
, this means that some TypeDeclarations does not have superclass and superinterfaces, then we will implement isAssignableFrom
, getSuperClass
and getInterfaces
in CodeTypeResolver
, all CodeTypes will have a defaultResolver
that holds the default CodeTypeResolver
provided by the implementation.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.