mirror of
https://github.com/ParkerTenBroeck/coroutines.git
synced 2026-06-07 05:08:51 -04:00
improved package names, split demos
This commit is contained in:
parent
ecb18b417e
commit
a577a825f8
27 changed files with 350 additions and 272 deletions
|
|
@ -16,6 +16,21 @@ java {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
application {
|
tasks.withType<JavaCompile> {
|
||||||
mainClass = "demo.Main"
|
options.compilerArgs.add("--enable-preview")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register<JavaExec>("lexer"){
|
||||||
|
javaLauncher.set(javaToolchains.launcherFor(java.toolchain))
|
||||||
|
jvmArgs("--enable-preview")
|
||||||
|
group = "Demos"
|
||||||
|
mainClass = "lexer.Main"
|
||||||
|
classpath = sourceSets["main"].runtimeClasspath
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register<JavaExec>("sockets"){
|
||||||
|
javaLauncher.set(javaToolchains.launcherFor(java.toolchain))
|
||||||
|
group = "Demos"
|
||||||
|
mainClass = "sockets.Main"
|
||||||
|
classpath = sourceSets["main"].runtimeClasspath
|
||||||
}
|
}
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
package demo;
|
|
||||||
|
|
||||||
import com.parkertenbroeck.async_runtime.Jokio;
|
|
||||||
import com.parkertenbroeck.async_runtime.io.net.ServerSocket;
|
|
||||||
import com.parkertenbroeck.async_runtime.io.net.Socket;
|
|
||||||
import com.parkertenbroeck.future.Future;
|
|
||||||
import com.parkertenbroeck.generators.loadtime.future.Cancellation;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
public class AsyncExamples {
|
|
||||||
|
|
||||||
public static Future<Void, RuntimeException> run() throws IOException {
|
|
||||||
Jokio.runtime().await().spawn(server());
|
|
||||||
for(int i = 0; i < 50; i ++){
|
|
||||||
var builder = new StringBuilder();
|
|
||||||
for(int c = 0; c < 4096; c ++)
|
|
||||||
builder.append((char)((Math.random()*('z'-'a')+'a')));
|
|
||||||
Jokio.runtime().await().spawn(verify_echo(builder.toString()));
|
|
||||||
}
|
|
||||||
Runnable meow = () -> {
|
|
||||||
System.out.println();
|
|
||||||
};
|
|
||||||
meow.run();
|
|
||||||
|
|
||||||
return Future.ret();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Future<Void, IOException> server() throws IOException {
|
|
||||||
try(@Cancellation("close") var ss = ServerSocket.bind(new InetSocketAddress("0.0.0.0", 42069))){
|
|
||||||
while (true){
|
|
||||||
Jokio.runtime().await().spawn(echo(ss.accept().await()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Future<Void, IOException> echo(@Cancellation("close") Socket socket) throws IOException{
|
|
||||||
try(socket){
|
|
||||||
var buffer = ByteBuffer.allocate(4096);
|
|
||||||
while(true){
|
|
||||||
socket.read(buffer).await();
|
|
||||||
buffer.flip();
|
|
||||||
socket.write_all(buffer).await();
|
|
||||||
buffer.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Future<Void, IOException> verify_echo(String message) throws IOException {
|
|
||||||
byte[] msg_bytes = message.getBytes(StandardCharsets.UTF_8);
|
|
||||||
try(@Cancellation("close") var socket = Socket.connect(new InetSocketAddress("localhost", 42069)).await()){
|
|
||||||
var buffer = ByteBuffer.allocate(message.length());
|
|
||||||
while(true){
|
|
||||||
buffer.limit(message.length()).put(msg_bytes).position(0);
|
|
||||||
var wrote = socket.write_all(buffer).await();
|
|
||||||
buffer.clear().limit(wrote);
|
|
||||||
socket.read_all(buffer).await();
|
|
||||||
if(!buffer.position(0).equals(ByteBuffer.wrap(msg_bytes)))
|
|
||||||
throw new RuntimeException();
|
|
||||||
buffer.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
||||||
package demo;
|
|
||||||
|
|
||||||
import com.parkertenbroeck.gen.Gen;
|
|
||||||
|
|
||||||
public class Lexer {
|
|
||||||
public sealed interface Token{}
|
|
||||||
public enum Punc implements Token {
|
|
||||||
LPar,
|
|
||||||
RPar,
|
|
||||||
Add,
|
|
||||||
Sub,
|
|
||||||
Div,
|
|
||||||
Mul,
|
|
||||||
Equals,
|
|
||||||
Carrot,
|
|
||||||
Comma
|
|
||||||
}
|
|
||||||
|
|
||||||
public record Ident(String ident) implements Token {}
|
|
||||||
public record Numeric(double val) implements Token {}
|
|
||||||
|
|
||||||
public static Gen<Token, Void> parse(String input) {
|
|
||||||
int start;
|
|
||||||
int pos = 0;
|
|
||||||
while(true){
|
|
||||||
if (input.length() <= pos)
|
|
||||||
return Gen.ret();
|
|
||||||
start = pos;
|
|
||||||
char curr = input.charAt(pos++);
|
|
||||||
|
|
||||||
switch (curr){
|
|
||||||
case '(' -> Gen.yield(Punc.LPar);
|
|
||||||
case ')' -> Gen.yield(Punc.RPar);
|
|
||||||
case '+' -> Gen.yield(Punc.Add);
|
|
||||||
case '-' -> Gen.yield(Punc.Sub);
|
|
||||||
case '/' -> Gen.yield(Punc.Div);
|
|
||||||
case '*' -> Gen.yield(Punc.Mul);
|
|
||||||
case ',' -> Gen.yield(Punc.Comma);
|
|
||||||
case '^' -> Gen.yield(Punc.Carrot);
|
|
||||||
case '=' -> Gen.yield(Punc.Equals);
|
|
||||||
// case Character c when Character.isWhitespace(c) -> {}
|
|
||||||
// case Character c when Character.isAlphabetic(c) -> {
|
|
||||||
// while((Character.isLetter(curr) || Character.isLetterOrDigit(curr))){
|
|
||||||
// if(pos>=input.length())break;
|
|
||||||
// curr = input.charAt(pos++);
|
|
||||||
// }
|
|
||||||
// Gen.yield(new Ident(input.substring(start, pos-1)));
|
|
||||||
// }
|
|
||||||
// case Character c when '0' <= c && c <= '9' -> {
|
|
||||||
// boolean exp = false;
|
|
||||||
// while(('0' <= curr && curr <= '9') || curr == '_' || curr == '.'){
|
|
||||||
// if(pos>=input.length())break;
|
|
||||||
// curr = input.charAt(pos++);
|
|
||||||
// if(curr=='e'||curr=='E'){
|
|
||||||
// if(exp) throw new RuntimeException("Exponent Already included");
|
|
||||||
// exp = true;
|
|
||||||
// if(pos+2>=input.length())
|
|
||||||
// throw new RuntimeException("Expected another character after exponent");
|
|
||||||
// curr = input.charAt(++pos); pos++;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Gen.yield(new Numeric(Double.parseDouble(input.substring(start, pos-1).replace("_", ""))));
|
|
||||||
// }
|
|
||||||
default -> throw new RuntimeException("Invalid char " + curr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
package demo;
|
|
||||||
|
|
||||||
import com.parkertenbroeck.async_runtime.Jokio;
|
|
||||||
import com.parkertenbroeck.async_runtime.io.fs.File;
|
|
||||||
import com.parkertenbroeck.generators.RT;
|
|
||||||
import com.parkertenbroeck.future.Future;
|
|
||||||
import com.parkertenbroeck.gen.Gen;
|
|
||||||
import com.parkertenbroeck.generators.loadtime.future.Cancellation;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
public class Main implements Runnable {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
RT.runWithGeneratorSupport(Main.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
// lexer();
|
|
||||||
await();
|
|
||||||
// try {
|
|
||||||
// System.out.println(new Jokio().blocking(files()));
|
|
||||||
// } catch (IOException ignore) {}
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// static Future<String, IOException> files() throws IOException{
|
|
||||||
// try(@Cancellation("close") var file = File.open(Path.of("./src/Main.java"))){
|
|
||||||
// var buf = ByteBuffer.allocate((int) file.size());
|
|
||||||
// var read = file.read_all(buf).await();
|
|
||||||
// return Future.ret(new String(buf.array(), 0, read));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// <T, E extends Throwable> T async_lambda(Supplier<Future<T, E>> lambda) throws E{
|
|
||||||
// return new Jokio().blocking(lambda.get());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
private static int nya = 0;
|
|
||||||
class Meow{
|
|
||||||
void test(){
|
|
||||||
nya = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void await(){
|
|
||||||
|
|
||||||
new Meow().test();
|
|
||||||
try{
|
|
||||||
new Jokio().blocking(AsyncExamples.run());
|
|
||||||
}catch (Exception e){
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// void lexer(){
|
|
||||||
// var gen = Lexer.parse("f7(x,y,z,w, u,v, othersIg) = v-(x*y+y+ln(z)^2*sin(z*pi/2))/(w*u)+sqrt(othersIg*120e-1)");
|
|
||||||
// while(gen.next() instanceof Gen.Yield(var tok)) {
|
|
||||||
// System.out.println(tok);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
69
app/src/main/java/lexer/Lexer.java
Normal file
69
app/src/main/java/lexer/Lexer.java
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
package lexer;
|
||||||
|
|
||||||
|
import com.parkertenbroeck.generator.Gen;
|
||||||
|
|
||||||
|
public class Lexer {
|
||||||
|
public sealed interface Token{}
|
||||||
|
public enum Punc implements Token {
|
||||||
|
LPar,
|
||||||
|
RPar,
|
||||||
|
Add,
|
||||||
|
Sub,
|
||||||
|
Div,
|
||||||
|
Mul,
|
||||||
|
Equals,
|
||||||
|
Carrot,
|
||||||
|
Comma
|
||||||
|
}
|
||||||
|
|
||||||
|
public record Ident(String ident) implements Token {}
|
||||||
|
public record Numeric(double val) implements Token {}
|
||||||
|
|
||||||
|
public static Gen<Token, Void> parse(String input) {
|
||||||
|
int start;
|
||||||
|
int pos = 0;
|
||||||
|
while(true){
|
||||||
|
if (input.length() <= pos)
|
||||||
|
return Gen.ret();
|
||||||
|
start = pos;
|
||||||
|
char curr = input.charAt(pos++);
|
||||||
|
|
||||||
|
switch (curr){
|
||||||
|
case '(' -> Gen.yield(Punc.LPar);
|
||||||
|
case ')' -> Gen.yield(Punc.RPar);
|
||||||
|
case '+' -> Gen.yield(Punc.Add);
|
||||||
|
case '-' -> Gen.yield(Punc.Sub);
|
||||||
|
case '/' -> Gen.yield(Punc.Div);
|
||||||
|
case '*' -> Gen.yield(Punc.Mul);
|
||||||
|
case ',' -> Gen.yield(Punc.Comma);
|
||||||
|
case '^' -> Gen.yield(Punc.Carrot);
|
||||||
|
case '=' -> Gen.yield(Punc.Equals);
|
||||||
|
case char c when Character.isWhitespace(c) -> {}
|
||||||
|
case char c when Character.isAlphabetic(c) -> {
|
||||||
|
while((Character.isLetter(curr) || Character.isLetterOrDigit(curr))){
|
||||||
|
if(pos>=input.length())break;
|
||||||
|
curr = input.charAt(pos++);
|
||||||
|
}
|
||||||
|
Gen.yield(new Ident(input.substring(start, pos-1)));
|
||||||
|
}
|
||||||
|
case char c when '0' <= c && c <= '9' -> {
|
||||||
|
boolean exp = false;
|
||||||
|
while(('0' <= curr && curr <= '9') || curr == '_' || curr == '.'){
|
||||||
|
if(pos>=input.length())break;
|
||||||
|
curr = input.charAt(pos++);
|
||||||
|
if(curr=='e'||curr=='E'){
|
||||||
|
if(exp) throw new RuntimeException("Exponent Already included");
|
||||||
|
exp = true;
|
||||||
|
if(pos+2>=input.length())
|
||||||
|
throw new RuntimeException("Expected another character after exponent");
|
||||||
|
curr = input.charAt(++pos); pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Gen.yield(new Numeric(Double.parseDouble(input.substring(start, pos-1).replace("_", ""))));
|
||||||
|
}
|
||||||
|
default -> throw new RuntimeException("Invalid char " + curr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
app/src/main/java/lexer/Main.java
Normal file
20
app/src/main/java/lexer/Main.java
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
package lexer;
|
||||||
|
|
||||||
|
import com.parkertenbroeck.generator.Gen;
|
||||||
|
import com.parkertenbroeck.bcms.RT;
|
||||||
|
import com.parkertenbroeck.bcms.loadtime.StateMachineClassLoader;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
RT.runWithStateMachines(StateMachineClassLoader.Config.builtin(), (Object) args);
|
||||||
|
|
||||||
|
lexer();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lexer(){
|
||||||
|
var gen = Lexer.parse("f7(x,y,z,w, u,v, othersIg) = v-(x*y+y+ln(z)^2*sin(z*pi/2))/(w*u)+sqrt(othersIg*120e-1)");
|
||||||
|
while(gen.next() instanceof Gen.Yield(var tok)) {
|
||||||
|
System.out.println(tok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
app/src/main/java/sockets/Main.java
Normal file
21
app/src/main/java/sockets/Main.java
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
package sockets;
|
||||||
|
|
||||||
|
import com.parkertenbroeck.async_runtime.Jokio;
|
||||||
|
import com.parkertenbroeck.bcms.RT;
|
||||||
|
import com.parkertenbroeck.bcms.loadtime.StateMachineClassLoader;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
RT.runWithStateMachines(StateMachineClassLoader.Config.builtin(), (Object) args);
|
||||||
|
|
||||||
|
await();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void await(){
|
||||||
|
try{
|
||||||
|
new Jokio().blocking(Sockets.run());
|
||||||
|
}catch (Exception e){
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
87
app/src/main/java/sockets/Sockets.java
Normal file
87
app/src/main/java/sockets/Sockets.java
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
package sockets;
|
||||||
|
|
||||||
|
import com.parkertenbroeck.async_runtime.Delay;
|
||||||
|
import com.parkertenbroeck.async_runtime.Jokio;
|
||||||
|
import com.parkertenbroeck.async_runtime.io.net.ServerSocket;
|
||||||
|
import com.parkertenbroeck.async_runtime.io.net.Socket;
|
||||||
|
import com.parkertenbroeck.future.Future;
|
||||||
|
import com.parkertenbroeck.bcms.loadtime.future.Cancellation;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class Sockets {
|
||||||
|
|
||||||
|
private static long bytes_sent = 0;
|
||||||
|
private static long bytes_received = 0;
|
||||||
|
|
||||||
|
public static Future<Void, RuntimeException> run() throws IOException {
|
||||||
|
Jokio.runtime().await().spawn(server());
|
||||||
|
for(int i = 0; i < 50; i ++){
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
for(int c = 0; c < 4096*2; c ++)
|
||||||
|
builder.append((char)((Math.random()*('z'-'a')+'a')));
|
||||||
|
Jokio.runtime().await().spawn(verify_echo(builder.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
stats().await();
|
||||||
|
return Future.ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Future<Void, RuntimeException> stats() {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
long start_s = bytes_sent;
|
||||||
|
long start_r = bytes_received;
|
||||||
|
while(true){
|
||||||
|
Delay.delay(1000).await();
|
||||||
|
long end = System.currentTimeMillis();
|
||||||
|
var duration = (end-start)/1000.0;
|
||||||
|
start = end;
|
||||||
|
System.out.format("sent: % 10d B\treceived: % 10d B\tduration: % 2.3fs\n", bytes_sent, bytes_received, duration);
|
||||||
|
System.out.format("sent: % 2.5f Gib/s\treceived: % 2.5f Gib/s\n", (bytes_sent-start_s)/duration*7.4505805969238E-9, (bytes_received-start_r)/duration*7.4505805969238E-9);
|
||||||
|
start_s = bytes_sent;
|
||||||
|
start_r = bytes_received;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Future<Void, IOException> server() throws IOException {
|
||||||
|
try(@Cancellation("close") var ss = ServerSocket.bind(new InetSocketAddress("0.0.0.0", 42069))){
|
||||||
|
while (true){
|
||||||
|
Jokio.runtime().await().spawn(echo(ss.accept().await()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Future<Void, IOException> echo(@Cancellation("close") Socket socket) throws IOException{
|
||||||
|
try(socket){
|
||||||
|
var buffer = ByteBuffer.allocate(4096*2);
|
||||||
|
while(true){
|
||||||
|
bytes_received = socket.read(buffer).await() + bytes_received;
|
||||||
|
buffer.flip();
|
||||||
|
bytes_sent = socket.write_all(buffer).await() + bytes_sent;
|
||||||
|
buffer.clear().limit(buffer.capacity());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Future<Void, IOException> verify_echo(String message) throws IOException {
|
||||||
|
byte[] msg_bytes = message.getBytes(StandardCharsets.UTF_8);
|
||||||
|
ByteBuffer msg_cmp_buffer = ByteBuffer.wrap(msg_bytes);
|
||||||
|
|
||||||
|
var buffer = ByteBuffer.allocate(message.length());
|
||||||
|
buffer.put(msg_bytes).limit(msg_bytes.length).position(0);
|
||||||
|
|
||||||
|
try(@Cancellation("close") var socket = Socket.connect(new InetSocketAddress("localhost", 42069)).await()){
|
||||||
|
while(true){
|
||||||
|
bytes_sent = socket.write_all(buffer).await() + bytes_sent;
|
||||||
|
buffer.flip();
|
||||||
|
bytes_received = socket.read_all(buffer).await() + bytes_received;
|
||||||
|
buffer.flip();
|
||||||
|
if(!buffer.equals(msg_cmp_buffer))
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
`java-library`
|
`java-library`
|
||||||
}
|
}
|
||||||
|
|
@ -12,6 +14,7 @@ dependencies {
|
||||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
java {
|
java {
|
||||||
toolchain {
|
toolchain {
|
||||||
languageVersion = JavaLanguageVersion.of(24)
|
languageVersion = JavaLanguageVersion.of(24)
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ public class Socket implements AutoCloseable, Readable<IOException>, Writable<IO
|
||||||
public Future<Integer, IOException> write_all(ByteBuffer buffer){
|
public Future<Integer, IOException> write_all(ByteBuffer buffer){
|
||||||
var wrote = buffer.remaining();
|
var wrote = buffer.remaining();
|
||||||
return waker -> {
|
return waker -> {
|
||||||
socket.write(buffer);
|
var nya = socket.write(buffer);
|
||||||
if(!buffer.hasRemaining()) return wrote;
|
if(!buffer.hasRemaining()) return wrote;
|
||||||
SELECTOR.register(socket, SelectionKey.OP_WRITE, waker);
|
SELECTOR.register(socket, SelectionKey.OP_WRITE, waker);
|
||||||
return Future.Pending.INSTANCE;
|
return Future.Pending.INSTANCE;
|
||||||
|
|
@ -103,6 +103,7 @@ public class Socket implements AutoCloseable, Readable<IOException>, Writable<IO
|
||||||
public Future<Integer, IOException> read(ByteBuffer buffer){
|
public Future<Integer, IOException> read(ByteBuffer buffer){
|
||||||
return waker -> {
|
return waker -> {
|
||||||
var read = socket.read(buffer);
|
var read = socket.read(buffer);
|
||||||
|
if(read == -1)throw new IOException("Reached end of stream");
|
||||||
if(read!=0) return read;
|
if(read!=0) return read;
|
||||||
SELECTOR.register(socket, SelectionKey.OP_READ, waker);
|
SELECTOR.register(socket, SelectionKey.OP_READ, waker);
|
||||||
return Future.Pending.INSTANCE;
|
return Future.Pending.INSTANCE;
|
||||||
|
|
|
||||||
31
lib/src/main/java/com/parkertenbroeck/bcms/RT.java
Normal file
31
lib/src/main/java/com/parkertenbroeck/bcms/RT.java
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
package com.parkertenbroeck.bcms;
|
||||||
|
|
||||||
|
|
||||||
|
import com.parkertenbroeck.bcms.loadtime.StateMachineClassLoader;
|
||||||
|
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static java.lang.StackWalker.Option.*;
|
||||||
|
|
||||||
|
public class RT {
|
||||||
|
public static void runWithStateMachines(StateMachineClassLoader.Config config, Object... params){
|
||||||
|
if(RT.class.getClassLoader() instanceof StateMachineClassLoader)return;
|
||||||
|
|
||||||
|
var loader = new StateMachineClassLoader(RT.class.getClassLoader(), config);
|
||||||
|
try{
|
||||||
|
StackWalker walker = StackWalker.getInstance(Set.of(RETAIN_CLASS_REFERENCE, SHOW_REFLECT_FRAMES, SHOW_HIDDEN_FRAMES));
|
||||||
|
var frame = walker.walk(s -> s.skip(1).findFirst()).get();
|
||||||
|
var clazzL = loader.loadClass(frame.getClassName());
|
||||||
|
var method = clazzL.getDeclaredMethod(frame.getMethodName(), frame.getMethodType().parameterArray());
|
||||||
|
if((method.getModifiers() & Modifier.STATIC) == 0){
|
||||||
|
method.invoke(clazzL.getConstructor().newInstance(), params);
|
||||||
|
}else{
|
||||||
|
method.invoke(null, params);
|
||||||
|
}
|
||||||
|
System.exit(0);
|
||||||
|
}catch (Exception e){
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.parkertenbroeck.generators.loadtime;
|
package com.parkertenbroeck.bcms.loadtime;
|
||||||
|
|
||||||
import java.lang.classfile.CodeBuilder;
|
import java.lang.classfile.CodeBuilder;
|
||||||
import java.lang.classfile.instruction.LineNumber;
|
import java.lang.classfile.instruction.LineNumber;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.parkertenbroeck.generators.loadtime;
|
package com.parkertenbroeck.bcms.loadtime;
|
||||||
|
|
||||||
|
|
||||||
import java.lang.classfile.*;
|
import java.lang.classfile.*;
|
||||||
|
|
@ -30,7 +30,7 @@ public class FrameTracker {
|
||||||
ITEM_LONG_2ND = 13,
|
ITEM_LONG_2ND = 13,
|
||||||
ITEM_DOUBLE_2ND = 14;
|
ITEM_DOUBLE_2ND = 14;
|
||||||
|
|
||||||
public static ArrayList<Frame> frames(StateMachineBuilder smb, CodeModel src_com) {
|
public static ArrayList<Frame> frames(StateMachineBuilder<?> smb, CodeModel src_com) {
|
||||||
var ft = new FrameTracker(smb, src_com);
|
var ft = new FrameTracker(smb, src_com);
|
||||||
var frames = new ArrayList<Frame>();
|
var frames = new ArrayList<Frame>();
|
||||||
for(var coe : src_com){
|
for(var coe : src_com){
|
||||||
|
|
@ -496,6 +496,16 @@ public class FrameTracker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void pushFromStackMapFrame(List<Type> list, Type type){
|
||||||
|
list.add(type);
|
||||||
|
if(type.tag() == Type.LONG_TYPE.tag()){
|
||||||
|
list.add(Type.LONG2_TYPE);
|
||||||
|
}
|
||||||
|
if(type.tag() == Type.DOUBLE2_TYPE.tag()){
|
||||||
|
list.add(Type.DOUBLE2_TYPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void encounterLabel(Label l) {
|
public void encounterLabel(Label l) {
|
||||||
if(annotationStartMap.get(l) instanceof ArrayList<LocalVariableAnnotation> list)
|
if(annotationStartMap.get(l) instanceof ArrayList<LocalVariableAnnotation> list)
|
||||||
activeAnnotations.addAll(list);
|
activeAnnotations.addAll(list);
|
||||||
|
|
@ -508,10 +518,10 @@ public class FrameTracker {
|
||||||
stack.clear();
|
stack.clear();
|
||||||
locals.clear();
|
locals.clear();
|
||||||
for(var sl : tmp.stack())
|
for(var sl : tmp.stack())
|
||||||
pushStack(Type.verificationType(sl, this));
|
pushFromStackMapFrame(stack, Type.verificationType(sl, this));
|
||||||
|
|
||||||
for( var sl : tmp.locals())
|
for(var lv : tmp.locals())
|
||||||
locals.add(Type.verificationType(sl, this));
|
pushFromStackMapFrame(locals, Type.verificationType(lv, this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.parkertenbroeck.generators.loadtime;
|
package com.parkertenbroeck.bcms.loadtime;
|
||||||
|
|
||||||
import java.lang.constant.ClassDesc;
|
import java.lang.constant.ClassDesc;
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.parkertenbroeck.generators.loadtime;
|
package com.parkertenbroeck.bcms.loadtime;
|
||||||
|
|
||||||
public enum ReplacementKind {
|
public enum ReplacementKind {
|
||||||
ImmediateReplacingPop,
|
ImmediateReplacingPop,
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.parkertenbroeck.generators.loadtime;
|
package com.parkertenbroeck.bcms.loadtime;
|
||||||
|
|
||||||
import java.lang.classfile.CodeBuilder;
|
import java.lang.classfile.CodeBuilder;
|
||||||
import java.lang.classfile.TypeKind;
|
import java.lang.classfile.TypeKind;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.parkertenbroeck.generators.loadtime;
|
package com.parkertenbroeck.bcms.loadtime;
|
||||||
|
|
||||||
import java.lang.constant.ClassDesc;
|
import java.lang.constant.ClassDesc;
|
||||||
import java.lang.constant.MethodTypeDesc;
|
import java.lang.constant.MethodTypeDesc;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.parkertenbroeck.generators.loadtime;
|
package com.parkertenbroeck.bcms.loadtime;
|
||||||
|
|
||||||
import java.lang.classfile.CodeBuilder;
|
import java.lang.classfile.CodeBuilder;
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.parkertenbroeck.generators.loadtime;
|
package com.parkertenbroeck.bcms.loadtime;
|
||||||
|
|
||||||
import java.lang.classfile.CodeBuilder;
|
import java.lang.classfile.CodeBuilder;
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.parkertenbroeck.generators.loadtime;
|
package com.parkertenbroeck.bcms.loadtime;
|
||||||
|
|
||||||
import java.lang.classfile.CodeBuilder;
|
import java.lang.classfile.CodeBuilder;
|
||||||
import java.lang.classfile.Label;
|
import java.lang.classfile.Label;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.parkertenbroeck.generators.loadtime;
|
package com.parkertenbroeck.bcms.loadtime;
|
||||||
|
|
||||||
import java.lang.classfile.*;
|
import java.lang.classfile.*;
|
||||||
import java.lang.classfile.attribute.InnerClassInfo;
|
import java.lang.classfile.attribute.InnerClassInfo;
|
||||||
|
|
@ -65,7 +65,7 @@ public abstract class StateMachineBuilder<T extends StateMachineBuilder<T>> {
|
||||||
.replace("[", "_____")
|
.replace("[", "_____")
|
||||||
)
|
)
|
||||||
.collect(Collectors.joining("$"));
|
.collect(Collectors.joining("$"));
|
||||||
innerClassName = method_name;
|
innerClassName = method_name + "______" + param_cnd;
|
||||||
var name = cdn + "$" + innerClassName;
|
var name = cdn + "$" + innerClassName;
|
||||||
|
|
||||||
this.CD_this = ClassDesc.of(src_clm.thisClass().asSymbol().packageName(), name);
|
this.CD_this = ClassDesc.of(src_clm.thisClass().asSymbol().packageName(), name);
|
||||||
|
|
@ -116,7 +116,7 @@ public abstract class StateMachineBuilder<T extends StateMachineBuilder<T>> {
|
||||||
|
|
||||||
if(shouldBeInnerClass()){
|
if(shouldBeInnerClass()){
|
||||||
src_clm.findAttributes(Attributes.sourceFile()).forEach(clb::with);
|
src_clm.findAttributes(Attributes.sourceFile()).forEach(clb::with);
|
||||||
clb.with(InnerClassesAttribute.of(InnerClassInfo.of(CD_this, Optional.of(src_clm.thisClass().asSymbol()), Optional.of(innerClassName), AccessFlag.PUBLIC)));
|
clb.with(InnerClassesAttribute.of(InnerClassInfo.of(CD_this, Optional.empty(), Optional.empty(), AccessFlag.PUBLIC)));
|
||||||
clb.with(NestHostAttribute.of(src_clm.thisClass()));
|
clb.with(NestHostAttribute.of(src_clm.thisClass()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,7 +128,7 @@ public abstract class StateMachineBuilder<T extends StateMachineBuilder<T>> {
|
||||||
clb.withField(STATE_NAME, ConstantDescs.CD_int, ClassFile.ACC_PRIVATE);
|
clb.withField(STATE_NAME, ConstantDescs.CD_int, ClassFile.ACC_PRIVATE);
|
||||||
|
|
||||||
// constructor
|
// constructor
|
||||||
clb.withMethod(ConstantDescs.INIT_NAME, MTD_init, ClassFile.ACC_PUBLIC, mb -> mb.withCode(cob -> {
|
clb.withMethod(ConstantDescs.INIT_NAME, MTD_init, ClassFile.ACC_PRIVATE, mb -> mb.withCode(cob -> {
|
||||||
cob.aload(0).invokespecial(ConstantDescs.CD_Object, ConstantDescs.INIT_NAME, ConstantDescs.MTD_void);
|
cob.aload(0).invokespecial(ConstantDescs.CD_Object, ConstantDescs.INIT_NAME, ConstantDescs.MTD_void);
|
||||||
params(1, (param, slot, type) -> {
|
params(1, (param, slot, type) -> {
|
||||||
cob.aload(0).loadLocal(TypeKind.from(type), slot).putfield(CD_this, param, type);
|
cob.aload(0).loadLocal(TypeKind.from(type), slot).putfield(CD_this, param, type);
|
||||||
|
|
@ -1,25 +1,65 @@
|
||||||
package com.parkertenbroeck.generators.loadtime;
|
package com.parkertenbroeck.bcms.loadtime;
|
||||||
|
|
||||||
import com.parkertenbroeck.future.Future;
|
import com.parkertenbroeck.future.Future;
|
||||||
import com.parkertenbroeck.gen.Gen;
|
import com.parkertenbroeck.generator.Gen;
|
||||||
import com.parkertenbroeck.generators.loadtime.future.FutureSMBuilder;
|
import com.parkertenbroeck.bcms.loadtime.future.FutureSMBuilder;
|
||||||
import com.parkertenbroeck.generators.loadtime.gen.GenSMBuilder;
|
import com.parkertenbroeck.bcms.loadtime.gen.GenSMBuilder;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.classfile.*;
|
import java.lang.classfile.*;
|
||||||
import java.lang.classfile.attribute.*;
|
import java.lang.classfile.attribute.*;
|
||||||
import java.lang.classfile.constantpool.ClassEntry;
|
import java.lang.classfile.constantpool.ClassEntry;
|
||||||
import java.lang.constant.ClassDesc;
|
import java.lang.constant.ClassDesc;
|
||||||
import java.lang.reflect.AccessFlag;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class GeneratorClassLoader extends ClassLoader {
|
public class StateMachineClassLoader extends ClassLoader {
|
||||||
private final HashMap<String, Class<?>> customClazzMap = new HashMap<>();
|
private final HashMap<String, Class<?>> customClazzMap = new HashMap<>();
|
||||||
|
private final List<String> skip;
|
||||||
|
private final HashMap<ClassDesc, SMBB> builders;
|
||||||
|
|
||||||
public GeneratorClassLoader(ClassLoader parent) {
|
public interface SMBB{
|
||||||
|
StateMachineBuilder<?> build(ClassModel src_clm, MethodModel src_mem, CodeModel src_com);
|
||||||
|
}
|
||||||
|
public static class Config{
|
||||||
|
HashSet<String> skip = new HashSet<>();
|
||||||
|
HashMap<ClassDesc, SMBB> builders = new HashMap<>();
|
||||||
|
|
||||||
|
public static Config empty(){
|
||||||
|
return new Config();
|
||||||
|
}
|
||||||
|
public static Config builtin(){
|
||||||
|
return empty()
|
||||||
|
.skip("java", "jdk", "jre", "com.parkertenbroeck.generators.loadtime")
|
||||||
|
.with(Future.class, FutureSMBuilder::new)
|
||||||
|
.with(Gen.class, GenSMBuilder::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Config skip(String... paths){
|
||||||
|
skip.addAll(List.of(paths));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Config with(Class<?> ret, SMBB builder){
|
||||||
|
builders.put(ClassDesc.ofDescriptor(ret.descriptorString()), builder);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Config with(ClassDesc ret, SMBB builder){
|
||||||
|
builders.put(ret, builder);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public StateMachineClassLoader(ClassLoader parent) {
|
||||||
|
this(parent, Config.builtin());
|
||||||
|
}
|
||||||
|
|
||||||
|
public StateMachineClassLoader(ClassLoader parent, Config config) {
|
||||||
super(parent);
|
super(parent);
|
||||||
|
skip = config.skip.stream().toList();
|
||||||
|
builders = new HashMap<>(config.builders);
|
||||||
}
|
}
|
||||||
|
|
||||||
void add(String name, byte[] def){
|
void add(String name, byte[] def){
|
||||||
|
|
@ -36,23 +76,23 @@ public class GeneratorClassLoader extends ClassLoader {
|
||||||
public Class<?> loadClass(String name) throws ClassNotFoundException {
|
public Class<?> loadClass(String name) throws ClassNotFoundException {
|
||||||
if (customClazzMap.get(name) instanceof Class<?> clazz)
|
if (customClazzMap.get(name) instanceof Class<?> clazz)
|
||||||
return clazz;
|
return clazz;
|
||||||
if (name.startsWith("java"))
|
for(var item : skip)
|
||||||
|
if(name.startsWith(item))
|
||||||
return super.loadClass(name);
|
return super.loadClass(name);
|
||||||
|
|
||||||
|
|
||||||
var p = "/" + name.replace('.', '/') + ".class";
|
var p = "/" + name.replace('.', '/') + ".class";
|
||||||
try (var stream = GeneratorClassLoader.class.getResourceAsStream(p)) {
|
try (var stream = StateMachineClassLoader.class.getResourceAsStream(p)) {
|
||||||
var bytes = Objects.requireNonNull(stream).readAllBytes();
|
var bytes = Objects.requireNonNull(stream).readAllBytes();
|
||||||
add(name, searchReplaceMethods(bytes));
|
add(name, searchReplaceableMethods(bytes));
|
||||||
return customClazzMap.get(name);
|
return customClazzMap.get(name);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new ClassNotFoundException(name, e);
|
throw new ClassNotFoundException(name, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] searchReplaceMethods(byte[] in) {
|
public byte[] searchReplaceableMethods(byte[] in) {
|
||||||
var clm = ClassFile.of(ClassFile.AttributesProcessingOption.PASS_ALL_ATTRIBUTES).parse(in);
|
var clm = ClassFile.of(ClassFile.AttributesProcessingOption.PASS_ALL_ATTRIBUTES).parse(in);
|
||||||
var isGen = clm.thisClass().asSymbol().descriptorString().equals(Gen.class.descriptorString());
|
|
||||||
var isFuture = clm.thisClass().asSymbol().descriptorString().equals(Future.class.descriptorString());
|
|
||||||
|
|
||||||
|
|
||||||
var nestMem = new ArrayList<ClassDesc>();
|
var nestMem = new ArrayList<ClassDesc>();
|
||||||
|
|
@ -62,23 +102,21 @@ public class GeneratorClassLoader extends ClassLoader {
|
||||||
|
|
||||||
return ClassFile.of(ClassFile.AttributesProcessingOption.PASS_ALL_ATTRIBUTES, ClassFile.StackMapsOption.STACK_MAPS_WHEN_REQUIRED).build(clm.thisClass().asSymbol(), cb -> {
|
return ClassFile.of(ClassFile.AttributesProcessingOption.PASS_ALL_ATTRIBUTES, ClassFile.StackMapsOption.STACK_MAPS_WHEN_REQUIRED).build(clm.thisClass().asSymbol(), cb -> {
|
||||||
for (var ce : clm) {
|
for (var ce : clm) {
|
||||||
if (ce instanceof MethodModel mem && !isGen && !isFuture && mem.code().isPresent()) {
|
if (ce instanceof MethodModel mem && mem.code().isPresent()) {
|
||||||
StateMachineBuilder<?> builder;
|
StateMachineBuilder<?> builder = builders
|
||||||
if(mem.methodTypeSymbol().returnType().descriptorString().equals(Gen.class.descriptorString())){
|
.getOrDefault(
|
||||||
builder = new GenSMBuilder(clm, mem, mem.code().get());
|
mem.methodTypeSymbol().returnType(),
|
||||||
}else if(mem.methodTypeSymbol().returnType().descriptorString().equals(Future.class.descriptorString())){
|
(_, _, _) -> null
|
||||||
builder = new FutureSMBuilder(clm, mem, mem.code().get());
|
).build(clm, mem, mem.code().get());
|
||||||
}else{
|
|
||||||
builder= null;
|
|
||||||
}
|
|
||||||
if(builder!=null&&builder.hasAnyHandlers()){
|
if(builder!=null&&builder.hasAnyHandlers()){
|
||||||
add(builder.CD_this.packageName() + "." + builder.CD_this.displayName(), builder.buildStateMachine());
|
add(builder.CD_this.packageName() + "." + builder.CD_this.displayName(), builder.buildStateMachine());
|
||||||
cb.withMethod(mem.methodName(), mem.methodType(), mem.flags().flagsMask()&~ClassFile.ACC_SYNCHRONIZED, mb -> {
|
cb.withMethod(mem.methodName(), mem.methodType(), mem.flags().flagsMask()&~ClassFile.ACC_SYNCHRONIZED, mb -> {
|
||||||
mb.withCode(builder::buildSourceMethodShim);
|
mb.withCode(builder::buildSourceMethodShim);
|
||||||
});
|
});
|
||||||
if(builder.shouldBeInnerClass()){
|
if(builder.shouldBeInnerClass()){
|
||||||
innerCl.add(InnerClassInfo.of(builder.CD_this, Optional.of(clm.thisClass().asSymbol()), Optional.of(builder.innerClassName)));
|
innerCl.add(InnerClassInfo.of(builder.CD_this, Optional.empty(), Optional.empty()));
|
||||||
nestMem.add(ClassDesc.of(builder.CD_this.displayName()));
|
nestMem.add(builder.CD_this);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
cb.with(mem);
|
cb.with(mem);
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.parkertenbroeck.generators.loadtime.future;
|
package com.parkertenbroeck.bcms.loadtime.future;
|
||||||
|
|
||||||
import java.lang.annotation.*;
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
package com.parkertenbroeck.generators.loadtime.future;
|
package com.parkertenbroeck.bcms.loadtime.future;
|
||||||
|
|
||||||
import com.parkertenbroeck.future.Future;
|
import com.parkertenbroeck.future.Future;
|
||||||
import com.parkertenbroeck.future.Waker;
|
import com.parkertenbroeck.future.Waker;
|
||||||
import com.parkertenbroeck.generators.loadtime.*;
|
import com.parkertenbroeck.bcms.loadtime.*;
|
||||||
|
|
||||||
import java.lang.classfile.*;
|
import java.lang.classfile.*;
|
||||||
import java.lang.classfile.instruction.SwitchCase;
|
import java.lang.classfile.instruction.SwitchCase;
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package com.parkertenbroeck.generators.loadtime.gen;
|
package com.parkertenbroeck.bcms.loadtime.gen;
|
||||||
|
|
||||||
import com.parkertenbroeck.gen.Gen;
|
import com.parkertenbroeck.generator.Gen;
|
||||||
import com.parkertenbroeck.generators.loadtime.*;
|
import com.parkertenbroeck.bcms.loadtime.*;
|
||||||
|
|
||||||
import java.lang.classfile.*;
|
import java.lang.classfile.*;
|
||||||
import java.lang.constant.ClassDesc;
|
import java.lang.constant.ClassDesc;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.parkertenbroeck.gen;
|
package com.parkertenbroeck.generator;
|
||||||
|
|
||||||
public interface Gen<Y, R> {
|
public interface Gen<Y, R> {
|
||||||
Res<Y, R> next();
|
Res<Y, R> next();
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
package com.parkertenbroeck.generators;
|
|
||||||
|
|
||||||
|
|
||||||
import com.parkertenbroeck.generators.loadtime.GeneratorClassLoader;
|
|
||||||
|
|
||||||
public class RT {
|
|
||||||
public static void runWithGeneratorSupport(Class<? extends Runnable> clazz){
|
|
||||||
var loader = new GeneratorClassLoader(RT.class.getClassLoader());
|
|
||||||
try{
|
|
||||||
((Runnable)loader.loadClass(clazz.getName()).getConstructor().newInstance()).run();
|
|
||||||
}catch (Exception e){
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue