GithubHelp home page GithubHelp logo

koresframework / kores Goto Github PK

View Code? Open in Web Editor NEW
4.0 4.0 0.0 8.45 MB

Generate source code & bytecode from an abstract representation tree (AST). Bytecode generation framework.

Home Page: http://koresframework.github.io/Kores/

License: Other

Java 22.21% Kotlin 77.79%
bytecode java kotlin source-generation source-representation

kores's People

Contributors

jonathanxd avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

kores's Issues

Replace CodeArgument with CodePart

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 CodeClassLoader

Create a class loader that loads TypeDefinition.

class CodeClassLoader {
  Map<String, SavedClass>
  CodeClassLoader(boolean store)
  defineClass(TypeDefinition, byte[])
}
class SavedClass {
  TypeDefinition
  byte[]
}

Improve generated class error debug.

Actually is hard to search the cause of error in the generated class.

  • Add Helper.tagLine(Identifier, CodeSource);
  • Add BytecodeGenerator(sourceFile: File)

Convert CodeAPI to Kotlin.

Convert CodeAPI to Kotlin 1.1.

After that, we can re-write some CodeAPI parts (like gen.visit.Common class).

Type Resolution

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> { ... }
}

Immutability problem returns

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.

Bitwise Operations and Negation operator

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

Enum Declaration

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

Java 9 module support

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()

Add ability to translate inner classes to Bytecode

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

Annotation Implementation

Implementation of annotations:

  • Class Annotations
  • Field Annotations
  • Method Annotations
    • Parameter Annotations

"Modular" CodeAPI

Modules:

  • CodeAPI Base

    • Base structure classes and base generator classes.
  • CodeAPI Source Generation

    • Source generator.
  • CodeAPI Bytecode Generation

    • Bytecode generator.
  • CodeAPI Bytecode translator

    • Bytecode to CodeAPI translator.
  • CodeAPI Java Source Translator¹

    • Java Source to CodeAPI translator.

¹ = Maybe not be implemented because CodeAPI will need to resolve types and method overloading.

Bytecode Generation Implementation

ASM Bytecode Generation features
  • Constructor
  • Methods
  • Index Named Parameters and Stack position.
  • Instance final fields with default values initialization at <init>
  • Method Invocation
  • Variable Access
  • Define variables
  • Literals (String, Numbers, Null)
  • If statement
  • Try-Catch-Finally statement
  • Loops (for, do, while)
  • Static fields with default values initialization at <clinit>
  • Foreach Iterator

Simplify CodeAPI

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

...

Sugar Syntax Registration

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>.

Try-With-Resources - CodeAPI

Sugar Syntax, (bytecode: Try-With-Resources generator will generate CodeAPI instructions and send to visitor).

Helper

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])

Processor

TryBlockProcessor: Support Argumenterizable
TryWithResourcesProcessor: [TryBlockProcessor]

Visitor

TryWithResourcesVisitor: Visit Variables, Generate finally block, unify generated finally blocks with FinallyBlockSource and send to TryCatchBlockVisitor.

Setter methods.

Add Setter methods.

Example:

interface Named {
  Named setName(String name);
}

Implementations MUST implements setter methods.

Fix Source code generics

Java source generics is generated incorrectly.
Example:
Generic.type(Map).of(String).of(Integer)
Is converted to:
Map< String > & < Integer >

CodeAPI instructions visitor

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

More builders

Add builders of:

  • MethodInvocation
  • Control flow parts: WhileBlock, Do-WhileBlock, IfBlock, ForBlock, ForEachBlock, SwitchBlock, TryBlock.

Generate If Statements and Try Catch - Bytecode

Options:

Create a If Expressions like

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

  • Readable and Easy to write.
  • Easy to implement
  • Easy to generate Bytecode and Source

Cons

  • Cannot create more operations
Analyze IfExpr and determine operations and actions (current)

ifExpression(ifExpr(access("X", int), Operators.LESS_THAN, access("Y", int)), source)

Pros

  • Easy to add new Operations without changing project source.
  • Easy to generate Source
  • Readable

Cons

  • Hard to generate Bytecode (Analyze structure)

Support javax.model conversions

Conversions:

  • TypeMirror to CodeType/GenericType
  • TypeElement to CodeType/GenericType (Not same as TypeMirror beucase TypeMirror is a type and not a declaration)
    ...

Options Implementation

Add options:

Finally:

  • Inline Finally blocks (bytecode)
  • Inline Finally blocks (source)

Foreach:

  • Foreach to Iterator (bytecode) default

Support anonymous classes

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.

Concat helper

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

Try Catch - Base, Bytecode & Source

Generate bytecode for Try Catch blocks.

  • Try Catch Single Exception
  • Try Catch Multiple exceptions
  • Finally Block
  • Improve Try Catch specification

Validate structures

Problem

Currently CodeAPI does not validate the structure, it means that you can add a VariableDeclaration to the body of a TypeDeclaration, which is invalid.

Solution

Introduce a Validator class, validation rules may vary depending on the Validator. CodeGenerators may provide your own version of Validator, the provided Validator will check structure against the rules of the CodeGenerator.

Support Switch

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.

3.0 Refactor Notes

This is not a issue, this is a note

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:

  • Package renamed: interfaces -> base.
  • Package impl moved to base.
  • Removed MultiBodied.
  • Removed PackageDeclaration.
  • Removed Helper class
  • Removed some CodeAPI methods in favour of builders
  • Chain-setters removed, use builders instead.
  • Removed TagLine 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.
  • Removed 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

Fix If comparison of two longs/doubles/float

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.

Generate bridge methods

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

}

Versioning template change

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

Generics

Implementation of generics.

  • GenericType
  • Generifiable interface
  • Generics.fill(GenericType, CodeType, CodeInterface|Field|Method|Variable): Fill all generic types.
  • Method Generics

Annotation Classes

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

Generate javac-like boolean ifs.

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:

Support comments

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
    etc...

Compare CodeType by Identification.

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. #

Add some 'Class' methods to CodeType

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.