Compare commits

...

2 Commits

Author SHA1 Message Date
d22e4b0611 Update.
All checks were successful
CI / Unit Tests (push) Successful in 27s
CI / Optimization Infrastructure Tests (push) Successful in 27s
CI / Integration Tests (push) Successful in 1m15s
CI / Performance Benchmark (push) Successful in 52s
2025-12-07 22:57:06 +01:00
f2f7dbbddc Update. 2025-12-07 16:31:49 +01:00
59 changed files with 3870 additions and 576 deletions

View File

@ -20,7 +20,8 @@ IR_OBJECTS = $(IR_SOURCES:.c=.o)
GC_SOURCES = runtime/gc/gc.c runtime/gc/gc_heap.c runtime/gc/gc_mark.c runtime/gc/gc_sweep.c runtime/gc/gc_roots.c
GC_OBJECTS = $(GC_SOURCES:.c=.o)
RUNTIME_SOURCES = runtime/runtime.c runtime/runtime_array.c runtime/runtime_object.c runtime/runtime_collections.c runtime/runtime_socket.c runtime/runtime_method_ref.c runtime/labeltable.c runtime/methodcache.c runtime/fastframe.c runtime/superinst.c $(GC_SOURCES)
RUNTIME_CORE_SOURCES = runtime/runtime_value.c runtime/runtime_stack.c runtime/runtime_static.c runtime/runtime_exception.c runtime/runtime_intern.c runtime/runtime_lookup.c
RUNTIME_SOURCES = runtime/runtime.c $(RUNTIME_CORE_SOURCES) runtime/runtime_array.c runtime/runtime_object.c runtime/runtime_collections.c runtime/runtime_socket.c runtime/runtime_method_ref.c runtime/labeltable.c runtime/methodcache.c runtime/fastframe.c runtime/superinst.c $(GC_SOURCES)
RUNTIME_OBJECTS = $(RUNTIME_SOURCES:.c=.o)
LOADER_SOURCES = loader/loader.c

View File

@ -0,0 +1,104 @@
public class ComprehensiveSocketExample {
public static void testInetAddress() {
System.out.println("\n--- InetAddress Tests ---");
InetAddress loopback = InetAddress.getLoopbackAddress();
System.out.println("Loopback address: " + loopback.getHostAddress());
System.out.println("Is loopback: " + loopback.isLoopbackAddress());
System.out.println("Is multicast: " + loopback.isMulticastAddress());
InetAddress localhost = InetAddress.getByName("localhost");
System.out.println("Localhost: " + localhost.getHostName());
System.out.println("Localhost IP: " + localhost.getHostAddress());
int reachable = localhost.isReachable(1000) ? 1 : 0;
System.out.println("Localhost reachable: " + reachable);
InetAddress.getAllByName("localhost");
localhost.getAddress();
System.out.println("InetAddress methods executed");
}
public static void testServerSocket() {
System.out.println("\n--- ServerSocket Tests ---");
ServerSocket server = new ServerSocket(0);
int port = server.getLocalPort();
System.out.println("Server port: " + port);
int bound = server.isBound() ? 1 : 0;
System.out.println("Server is bound: " + bound);
int closed = server.isClosed() ? 1 : 0;
System.out.println("Server is closed: " + closed);
server.setSoTimeout(5000);
int timeout = server.getSoTimeout();
System.out.println("Server timeout: " + timeout);
server.setReceiveBufferSize(16384);
int bufSize = server.getReceiveBufferSize();
System.out.println("Receive buffer size: " + bufSize);
server.setReuseAddress(true);
int reuse = server.getReuseAddress() ? 1 : 0;
System.out.println("Reuse address enabled: " + reuse);
System.out.println("ServerSocket configured successfully");
}
public static void testSocketOptions() {
System.out.println("\n--- Socket Options Tests ---");
Socket sock = new Socket();
sock.setSoTimeout(3000);
int timeout = sock.getSoTimeout();
System.out.println("Socket timeout: " + timeout);
sock.setTcpNoDelay(true);
int nodelay = sock.getTcpNoDelay() ? 1 : 0;
System.out.println("TCP NoDelay: " + nodelay);
sock.setSendBufferSize(8192);
int sendBuf = sock.getSendBufferSize();
System.out.println("Send buffer: " + sendBuf);
sock.setReceiveBufferSize(8192);
int recvBuf = sock.getReceiveBufferSize();
System.out.println("Receive buffer: " + recvBuf);
sock.setKeepAlive(true);
int keepAlive = sock.getKeepAlive() ? 1 : 0;
System.out.println("Keep alive: " + keepAlive);
sock.setReuseAddress(true);
int reuse = sock.getReuseAddress() ? 1 : 0;
System.out.println("Reuse address: " + reuse);
int connected = sock.isConnected() ? 1 : 0;
System.out.println("Socket connected: " + connected);
int sockClosed = sock.isClosed() ? 1 : 0;
System.out.println("Socket closed: " + sockClosed);
sock.close();
System.out.println("Socket options configured successfully");
}
public static int main() {
System.out.println("========================================");
System.out.println("Comprehensive Socket API Example");
System.out.println("========================================");
testInetAddress();
testServerSocket();
testSocketOptions();
System.out.println("========================================");
System.out.println("All Socket API tests completed successfully");
System.out.println("========================================");
return 0;
}
}

View File

@ -0,0 +1,29 @@
public class InetAddressExample {
public static int main() {
System.out.println("InetAddress Methods Example");
System.out.println("============================");
InetAddress loopback = InetAddress.getLoopbackAddress();
System.out.println("Loopback: " + loopback.getHostAddress());
System.out.println("Is loopback: " + loopback.isLoopbackAddress());
System.out.println("Is multicast: " + loopback.isMulticastAddress());
InetAddress localhost = InetAddress.getByName("localhost");
System.out.println("Localhost: " + localhost.getHostName());
System.out.println("Localhost address: " + localhost.getHostAddress());
System.out.println("Testing reachability...");
int reachable = localhost.isReachable(1000) ? 1 : 0;
System.out.println("Localhost reachable: " + reachable);
System.out.println("Getting all addresses for localhost...");
InetAddress.getAllByName("localhost");
System.out.println("Getting byte address...");
localhost.getAddress();
System.out.println("InetAddress tests completed");
return 0;
}
}

View File

@ -0,0 +1,54 @@
public class SimpleHttpClient {
public static int main() {
System.out.println("=================================");
System.out.println("Rava HTTP Client Example");
System.out.println("=================================");
System.out.println("");
String host = "127.0.0.1";
int port = 8080;
System.out.println("Connecting to " + host + ":" + port);
Socket socket = new Socket(host, port);
System.out.println("Connected successfully");
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
System.out.println("");
System.out.println("Sending HTTP GET request...");
out.write("GET / HTTP/1.1\r\n");
out.write("Host: localhost\r\n");
out.write("Connection: close\r\n");
out.write("\r\n");
out.flush();
System.out.println("Request sent, reading response...");
System.out.println("");
System.out.println("--- HTTP Response ---");
int bytesRead = 0;
int maxBytes = 1000;
while (bytesRead < maxBytes) {
int ch = in.read();
if (ch < 0) {
break;
}
System.out.print((char)ch);
bytesRead = bytesRead + 1;
}
System.out.println("");
System.out.println("--- End of Response ---");
System.out.println("");
socket.close();
System.out.println("Connection closed");
System.out.println("");
System.out.println("HTTP client example completed successfully!");
System.out.println("Total bytes received: " + bytesRead);
return 0;
}
}

View File

@ -0,0 +1,72 @@
public class SimpleHttpServer {
public static int main() {
int port = 8080;
System.out.println("=================================");
System.out.println("Rava HTTP Server Example");
System.out.println("=================================");
System.out.println("");
System.out.println("Starting HTTP server on port " + port);
ServerSocket server = new ServerSocket(port);
server.setReuseAddress(true);
System.out.println("Server listening on http://localhost:" + port);
System.out.println("Send an HTTP request to see the response");
System.out.println("");
System.out.println("Example:");
System.out.println(" curl http://localhost:8080/");
System.out.println(" or visit http://localhost:8080/ in your browser");
System.out.println("");
System.out.println("Waiting for connection...");
Socket client = server.accept();
System.out.println("Connection accepted!");
InputStream in = client.getInputStream();
OutputStream out = client.getOutputStream();
System.out.println("Reading request...");
int bytesRead = 0;
while (bytesRead < 100) {
int ch = in.read();
if (ch < 0) {
break;
}
bytesRead = bytesRead + 1;
}
System.out.println("Sending response...");
out.write("HTTP/1.1 200 OK\r\n");
out.write("Content-Type: text/html\r\n");
out.write("Connection: close\r\n");
out.write("\r\n");
out.write("<html>\n");
out.write("<head><title>Rava HTTP Server</title></head>\n");
out.write("<body style=\"font-family: Arial, sans-serif; max-width: 800px; margin: 50px auto; padding: 20px;\">\n");
out.write("<h1 style=\"color: #333;\">Hello from Rava!</h1>\n");
out.write("<p>This is a simple HTTP server written in Java and running on the <b>Rava</b> Java interpreter.</p>\n");
out.write("<h2>Features Demonstrated:</h2>\n");
out.write("<ul>\n");
out.write("<li>ServerSocket - listening for connections</li>\n");
out.write("<li>Socket - accepting client connections</li>\n");
out.write("<li>InputStream - reading HTTP requests</li>\n");
out.write("<li>OutputStream - sending HTTP responses</li>\n");
out.write("</ul>\n");
out.write("<hr>\n");
out.write("<p><small>Powered by <b>Rava</b> - A Java interpreter written in C</small></p>\n");
out.write("</body>\n");
out.write("</html>\n");
out.flush();
System.out.println("Response sent successfully");
client.close();
server.close();
System.out.println("");
System.out.println("Server shut down");
System.out.println("HTTP server example completed successfully!");
return 0;
}
}

View File

@ -0,0 +1,17 @@
public class SocketBindDebug {
public static int main() {
Socket sock = new Socket();
System.out.print("Before bind, isBound: ");
System.out.println(sock.isBound());
sock.bind("0.0.0.0", 8888);
System.out.print("After bind, isBound: ");
boolean bound = sock.isBound();
System.out.println(bound);
sock.close();
return bound ? 1 : 0;
}
}

View File

@ -0,0 +1,21 @@
public class SocketBindExample {
public static int main() {
System.out.println("Socket Bind Example");
System.out.println("==================");
Socket sock = new Socket();
System.out.print("Socket bound before bind(): ");
System.out.println(sock.isBound());
sock.bind("127.0.0.1", 8888);
System.out.print("Socket bound after bind(): ");
System.out.println(sock.isBound());
sock.close();
System.out.println("Socket bind example completed successfully");
return 0;
}
}

View File

@ -0,0 +1,29 @@
public class SocketBufferSizeExample {
public static int main() {
System.out.println("Socket Buffer Size Example");
System.out.println("==========================");
Socket sock = new Socket();
System.out.print("Initial send buffer size: ");
System.out.println(sock.getSendBufferSize());
System.out.print("Initial receive buffer size: ");
System.out.println(sock.getReceiveBufferSize());
System.out.println("\nSetting buffer sizes to 32KB...");
sock.setSendBufferSize(32768);
sock.setReceiveBufferSize(32768);
System.out.print("New send buffer size: ");
System.out.println(sock.getSendBufferSize());
System.out.print("New receive buffer size: ");
System.out.println(sock.getReceiveBufferSize());
sock.close();
System.out.println("\nBuffer size configuration completed successfully");
return 0;
}
}

View File

@ -0,0 +1,55 @@
public class SocketLifecycleExample {
public static int main() {
System.out.println("Socket Lifecycle Example");
System.out.println("========================");
Socket client = new Socket();
System.out.println("\nInitial state:");
System.out.print(" Connected: ");
System.out.println(client.isConnected());
System.out.print(" Closed: ");
System.out.println(client.isClosed());
System.out.print(" Bound: ");
System.out.println(client.isBound());
System.out.println("\nBinding socket to local address...");
client.bind("127.0.0.1", 6666);
System.out.print(" Bound: ");
System.out.println(client.isBound());
System.out.println("\nCreating server and connecting...");
ServerSocket server = new ServerSocket(6667);
InetAddress addr = InetAddress.getLoopbackAddress();
client.connect(addr, 6667);
System.out.print(" Connected: ");
System.out.println(client.isConnected());
System.out.println("\nShutdown state:");
System.out.print(" Input shutdown: ");
System.out.println(client.isInputShutdown());
System.out.print(" Output shutdown: ");
System.out.println(client.isOutputShutdown());
System.out.println("\nPerforming half-close (shutdown output)...");
client.shutdownOutput();
System.out.print(" Output shutdown: ");
System.out.println(client.isOutputShutdown());
System.out.print(" Still connected: ");
System.out.println(client.isConnected());
System.out.println("\nClosing socket...");
client.close();
System.out.print(" Closed: ");
System.out.println(client.isClosed());
server.close();
System.out.println("\nSocket lifecycle example completed successfully");
return 0;
}
}

View File

@ -0,0 +1,43 @@
public class SocketOptionsExample {
public static int main() {
Socket socket = new Socket();
System.out.println("Socket Options Example");
System.out.println("=====================");
System.out.print("Initial KeepAlive: ");
System.out.println(socket.getKeepAlive());
socket.setKeepAlive(true);
System.out.print("After setKeepAlive(true): ");
System.out.println(socket.getKeepAlive());
socket.setKeepAlive(false);
System.out.print("After setKeepAlive(false): ");
System.out.println(socket.getKeepAlive());
System.out.print("Initial ReuseAddress: ");
System.out.println(socket.getReuseAddress());
socket.setReuseAddress(true);
System.out.print("After setReuseAddress(true): ");
System.out.println(socket.getReuseAddress());
socket.setReuseAddress(false);
System.out.print("After setReuseAddress(false): ");
System.out.println(socket.getReuseAddress());
socket.setSendBufferSize(32768);
System.out.print("Send buffer size: ");
System.out.println(socket.getSendBufferSize());
socket.setReceiveBufferSize(32768);
System.out.print("Receive buffer size: ");
System.out.println(socket.getReceiveBufferSize());
socket.close();
System.out.println("Socket closed");
return 0;
}
}

View File

@ -0,0 +1,146 @@
public class SocketPerformanceBenchmark {
public static int main() {
System.out.println("================================================");
System.out.println("Socket API Performance Benchmark");
System.out.println("================================================");
System.out.println("");
System.out.println("This benchmark measures Socket API operations");
System.out.println("to demonstrate networking performance in Rava.");
System.out.println("");
int iterations = 10;
System.out.println("Test 1: ServerSocket Creation and Binding");
System.out.println("------------------------------------------");
long start1 = System.currentTimeMillis();
int i = 0;
while (i < iterations) {
ServerSocket server = new ServerSocket(0);
int port = server.getLocalPort();
server.close();
i = i + 1;
}
long end1 = System.currentTimeMillis();
long time1 = end1 - start1;
System.out.println("Created and closed " + iterations + " ServerSockets in " + time1 + "ms");
if (time1 > 0) {
long avg1 = time1 / iterations;
System.out.println("Average: " + avg1 + "ms per ServerSocket");
}
System.out.println("");
System.out.println("Test 2: Socket Object Creation");
System.out.println("-------------------------------");
long start2 = System.currentTimeMillis();
int j = 0;
while (j < iterations) {
Socket sock = new Socket();
sock.close();
j = j + 1;
}
long end2 = System.currentTimeMillis();
long time2 = end2 - start2;
System.out.println("Created and closed " + iterations + " Sockets in " + time2 + "ms");
if (time2 > 0) {
long avg2 = time2 / iterations;
System.out.println("Average: " + avg2 + "ms per Socket");
}
System.out.println("");
System.out.println("Test 3: Socket Option Configuration");
System.out.println("------------------------------------");
long start3 = System.currentTimeMillis();
int k = 0;
while (k < iterations) {
Socket socket = new Socket();
socket.setKeepAlive(true);
socket.setTcpNoDelay(true);
socket.setReuseAddress(true);
socket.setSendBufferSize(8192);
socket.setReceiveBufferSize(8192);
int keepAlive = socket.getKeepAlive() ? 1 : 0;
int noDelay = socket.getTcpNoDelay() ? 1 : 0;
int reuse = socket.getReuseAddress() ? 1 : 0;
int sendBuf = socket.getSendBufferSize();
int recvBuf = socket.getReceiveBufferSize();
socket.close();
k = k + 1;
}
long end3 = System.currentTimeMillis();
long time3 = end3 - start3;
System.out.println("Configured " + iterations + " Sockets with 5 options in " + time3 + "ms");
if (time3 > 0) {
long avg3 = time3 / iterations;
System.out.println("Average: " + avg3 + "ms per Socket configuration");
}
System.out.println("");
System.out.println("Test 4: InetAddress Resolution");
System.out.println("-------------------------------");
long start4 = System.currentTimeMillis();
int m = 0;
while (m < iterations) {
InetAddress local = InetAddress.getLoopbackAddress();
InetAddress localhost = InetAddress.getByName("localhost");
String host = localhost.getHostName();
String addr = localhost.getHostAddress();
int isLoop = localhost.isLoopbackAddress() ? 1 : 0;
m = m + 1;
}
long end4 = System.currentTimeMillis();
long time4 = end4 - start4;
System.out.println("Resolved " + iterations + " InetAddresses in " + time4 + "ms");
if (time4 > 0) {
long avg4 = time4 / iterations;
System.out.println("Average: " + avg4 + "ms per resolution");
}
System.out.println("");
System.out.println("Test 5: ServerSocket Options");
System.out.println("-----------------------------");
long start5 = System.currentTimeMillis();
int n = 0;
while (n < iterations) {
ServerSocket srv = new ServerSocket(0);
srv.setReuseAddress(true);
srv.setReceiveBufferSize(16384);
srv.setSoTimeout(5000);
int reuseAddr = srv.getReuseAddress() ? 1 : 0;
int bufferSize = srv.getReceiveBufferSize();
int socketTimeout = srv.getSoTimeout();
srv.close();
n = n + 1;
}
long end5 = System.currentTimeMillis();
long time5 = end5 - start5;
System.out.println("Configured " + iterations + " ServerSockets in " + time5 + "ms");
if (time5 > 0) {
long avg5 = time5 / iterations;
System.out.println("Average: " + avg5 + "ms per ServerSocket");
}
System.out.println("");
long totalTime = time1 + time2 + time3 + time4 + time5;
int totalOps = iterations * 5;
System.out.println("================================================");
System.out.println("Summary");
System.out.println("================================================");
System.out.println("Total operations: " + totalOps);
System.out.println("Total time: " + totalTime + "ms");
if (totalTime > 0) {
long avgOp = totalTime / totalOps;
long opsPerSec = (totalOps * 1000) / totalTime;
System.out.println("Average time per operation: " + avgOp + "ms");
System.out.println("Operations per second: " + opsPerSec);
}
System.out.println("");
System.out.println("Benchmark completed successfully!");
return 0;
}
}

View File

@ -0,0 +1,36 @@
public class SocketShutdownExample {
public static int main() {
System.out.println("Socket Graceful Shutdown Example");
System.out.println("=================================");
ServerSocket server = new ServerSocket(7777);
Socket client = new Socket();
InetAddress addr = InetAddress.getLoopbackAddress();
client.connect(addr, 7777);
System.out.print("Input shutdown: ");
System.out.println(client.isInputShutdown());
System.out.print("Output shutdown: ");
System.out.println(client.isOutputShutdown());
System.out.println("\nShutting down input...");
client.shutdownInput();
System.out.print("Input shutdown after shutdownInput(): ");
System.out.println(client.isInputShutdown());
System.out.println("\nShutting down output...");
client.shutdownOutput();
System.out.print("Output shutdown after shutdownOutput(): ");
System.out.println(client.isOutputShutdown());
client.close();
server.close();
System.out.println("\nGraceful shutdown example completed successfully");
return 0;
}
}

View File

@ -0,0 +1,22 @@
public class StreamMethodsExample {
public static int main() {
System.out.println("Stream Methods Example");
System.out.println("======================");
System.out.println("Stream methods flush() and skip() are now available");
System.out.println("These methods work with InputStream and OutputStream");
System.out.println("obtained from Socket connections.");
System.out.println("\nExample usage:");
System.out.println(" InputStream in = socket.getInputStream();");
System.out.println(" long skipped = in.skip(100); // Skip 100 bytes");
System.out.println(" ");
System.out.println(" OutputStream out = socket.getOutputStream();");
System.out.println(" out.write(data);");
System.out.println(" out.flush(); // Flush buffered data");
System.out.println("\nStream methods implementation complete!");
return 0;
}
}

View File

@ -0,0 +1,69 @@
public class StringErrorHandlingTest {
public static int main() {
System.out.println("===========================================");
System.out.println("String Error Handling & Edge Cases Test");
System.out.println("===========================================");
System.out.println("");
String test = "Hello";
System.out.println("Test string: \"" + test + "\" (length: " + test.length() + ")");
System.out.println("");
System.out.println("Test 1: charAt() with out of bounds index");
System.out.println("Trying charAt(10) on string of length 5...");
char outOfBounds = test.charAt(10);
System.out.println("Result: " + outOfBounds);
System.out.println("(Should handle gracefully or throw error)");
System.out.println("");
System.out.println("Test 2: charAt() with negative index");
System.out.println("Trying charAt(-1)...");
char negative = test.charAt(-1);
System.out.println("Result: " + negative);
System.out.println("");
System.out.println("Test 3: substring() with invalid range");
System.out.println("Trying substring(3, 1) (end before start)...");
String badRange = test.substring(3, 1);
System.out.println("Result: \"" + badRange + "\"");
System.out.println("");
System.out.println("Test 4: substring() with out of bounds end");
System.out.println("Trying substring(0, 100)...");
String badEnd = test.substring(0, 100);
System.out.println("Result: \"" + badEnd + "\"");
System.out.println("");
System.out.println("Test 5: substring() with negative indices");
System.out.println("Trying substring(-1, 3)...");
String negStart = test.substring(-1, 3);
System.out.println("Result: \"" + negStart + "\"");
System.out.println("");
System.out.println("Test 6: indexOf() with empty string");
System.out.println("Trying indexOf(\"\")...");
int emptyIdx = test.indexOf("");
System.out.println("Result: " + emptyIdx);
System.out.println("");
System.out.println("Test 7: Empty string operations");
String empty = "";
System.out.println("Empty string length: " + empty.length());
System.out.println("Empty equals empty: " + (empty.equals("") ? "true" : "false"));
System.out.println("Empty contains empty: " + (empty.contains("") ? "true" : "false"));
System.out.println("");
System.out.println("Test 8: String with special characters");
String special = "Hello\nWorld\t!";
System.out.println("String with newline and tab:");
System.out.println(" Length: " + special.length());
System.out.println(" indexOf(\"\\n\"): " + special.indexOf("\n"));
System.out.println("");
System.out.println("===========================================");
System.out.println("Error handling test complete");
System.out.println("===========================================");
return 0;
}
}

View File

@ -0,0 +1,106 @@
public class StringMethodsDemo {
public static int main() {
System.out.println("==========================================");
System.out.println("String Methods Demonstration");
System.out.println("==========================================");
System.out.println("");
String original = "Hello World";
System.out.println("Original string: \"" + original + "\"");
System.out.println("");
System.out.println("1. length() - Get string length");
int len = original.length();
System.out.println(" Length: " + len);
System.out.println("");
System.out.println("2. charAt(index) - Get character at position");
char first = original.charAt(0);
char space = original.charAt(5);
char last = original.charAt(10);
System.out.println(" charAt(0): " + first + " (H)");
System.out.println(" charAt(5): " + space + " (space)");
System.out.println(" charAt(10): " + last + " (d)");
System.out.println("");
System.out.println("3. substring(start, end) - Extract portion");
String hello = original.substring(0, 5);
String world = original.substring(6, 11);
System.out.println(" substring(0, 5): \"" + hello + "\"");
System.out.println(" substring(6, 11): \"" + world + "\"");
System.out.println("");
System.out.println("4. equals(other) - Compare strings");
String same = "Hello World";
String different = "hello world";
int eq1 = original.equals(same) ? 1 : 0;
int eq2 = original.equals(different) ? 1 : 0;
System.out.println(" equals(\"Hello World\"): " + (eq1 == 1 ? "true" : "false"));
System.out.println(" equals(\"hello world\"): " + (eq2 == 1 ? "true" : "false"));
System.out.println("");
System.out.println("5. indexOf(substring) - Find position");
int pos1 = original.indexOf("World");
int pos2 = original.indexOf("xyz");
System.out.println(" indexOf(\"World\"): " + pos1);
System.out.println(" indexOf(\"xyz\"): " + pos2 + " (not found)");
System.out.println("");
System.out.println("6. contains(substring) - Check if contains");
int has1 = original.contains("World") ? 1 : 0;
int has2 = original.contains("xyz") ? 1 : 0;
System.out.println(" contains(\"World\"): " + (has1 == 1 ? "true" : "false"));
System.out.println(" contains(\"xyz\"): " + (has2 == 1 ? "true" : "false"));
System.out.println("");
System.out.println("7. startsWith/endsWith - Check boundaries");
int starts = original.startsWith("Hello") ? 1 : 0;
int ends = original.endsWith("World") ? 1 : 0;
System.out.println(" startsWith(\"Hello\"): " + (starts == 1 ? "true" : "false"));
System.out.println(" endsWith(\"World\"): " + (ends == 1 ? "true" : "false"));
System.out.println("");
System.out.println("8. toLowerCase/toUpperCase - Case conversion");
String lower = original.toLowerCase();
String upper = original.toUpperCase();
System.out.println(" toLowerCase(): \"" + lower + "\"");
System.out.println(" toUpperCase(): \"" + upper + "\"");
System.out.println("");
System.out.println("9. trim() - Remove whitespace");
String padded = " Hello World ";
String trimmed = padded.trim();
System.out.println(" Original: \"" + padded + "\"");
System.out.println(" Trimmed: \"" + trimmed + "\"");
System.out.println("");
System.out.println("10. compareTo() - Lexicographic comparison");
int cmp1 = original.compareTo("Hello World");
int cmp2 = original.compareTo("ABC");
int cmp3 = original.compareTo("XYZ");
System.out.println(" compareTo(\"Hello World\"): " + cmp1 + " (equal)");
System.out.println(" compareTo(\"ABC\"): " + (cmp2 > 0 ? "positive" : "negative") + " (after ABC)");
System.out.println(" compareTo(\"XYZ\"): " + (cmp3 < 0 ? "negative" : "positive") + " (before XYZ)");
System.out.println("");
System.out.println("11. String concatenation with +");
String part1 = "Hello";
String part2 = " ";
String part3 = "World";
String concat = part1 + part2 + part3;
System.out.println(" \"" + part1 + "\" + \"" + part2 + "\" + \"" + part3 + "\" = \"" + concat + "\"");
System.out.println("");
System.out.println("12. Concatenation with numbers");
int num = 42;
String withNum = "The answer is " + num;
System.out.println(" \"The answer is \" + 42 = \"" + withNum + "\"");
System.out.println("");
System.out.println("==========================================");
System.out.println("All String methods working correctly!");
System.out.println("==========================================");
return 0;
}
}

44
ir/ir.c
View File

@ -290,8 +290,52 @@ static const char* _rava_opcode_name(RavaOpCode_e opcode) {
case RAVA_OP_SOCKET_GET_INPUT_STREAM: return "SOCKET_GET_INPUT_STREAM";
case RAVA_OP_SOCKET_GET_OUTPUT_STREAM: return "SOCKET_GET_OUTPUT_STREAM";
case RAVA_OP_INPUT_STREAM_READ: return "INPUT_STREAM_READ";
case RAVA_OP_INPUT_STREAM_READ_BYTES: return "INPUT_STREAM_READ_BYTES";
case RAVA_OP_INPUT_STREAM_AVAILABLE: return "INPUT_STREAM_AVAILABLE";
case RAVA_OP_INPUT_STREAM_SKIP: return "INPUT_STREAM_SKIP";
case RAVA_OP_OUTPUT_STREAM_WRITE: return "OUTPUT_STREAM_WRITE";
case RAVA_OP_OUTPUT_STREAM_FLUSH: return "OUTPUT_STREAM_FLUSH";
case RAVA_OP_STREAM_CLOSE: return "STREAM_CLOSE";
case RAVA_OP_INETADDRESS_GET_BY_NAME: return "INETADDRESS_GET_BY_NAME";
case RAVA_OP_INETADDRESS_GET_LOCAL_HOST: return "INETADDRESS_GET_LOCAL_HOST";
case RAVA_OP_INETADDRESS_GET_LOOPBACK: return "INETADDRESS_GET_LOOPBACK";
case RAVA_OP_INETADDRESS_GET_HOST_NAME: return "INETADDRESS_GET_HOST_NAME";
case RAVA_OP_INETADDRESS_GET_HOST_ADDRESS: return "INETADDRESS_GET_HOST_ADDRESS";
case RAVA_OP_INETADDRESS_IS_LOOPBACK: return "INETADDRESS_IS_LOOPBACK";
case RAVA_OP_INETADDRESS_IS_ANY_LOCAL: return "INETADDRESS_IS_ANY_LOCAL";
case RAVA_OP_INETADDRESS_GET_ALL_BY_NAME: return "INETADDRESS_GET_ALL_BY_NAME";
case RAVA_OP_INETADDRESS_GET_ADDRESS: return "INETADDRESS_GET_ADDRESS";
case RAVA_OP_INETADDRESS_IS_MULTICAST_ADDRESS: return "INETADDRESS_IS_MULTICAST_ADDRESS";
case RAVA_OP_INETADDRESS_IS_REACHABLE: return "INETADDRESS_IS_REACHABLE";
case RAVA_OP_SOCKET_GET_PORT: return "SOCKET_GET_PORT";
case RAVA_OP_SOCKET_GET_LOCAL_PORT: return "SOCKET_GET_LOCAL_PORT";
case RAVA_OP_SOCKET_GET_INET_ADDRESS: return "SOCKET_GET_INET_ADDRESS";
case RAVA_OP_SOCKET_GET_LOCAL_ADDRESS: return "SOCKET_GET_LOCAL_ADDRESS";
case RAVA_OP_SERVER_SOCKET_GET_LOCAL_PORT: return "SERVER_SOCKET_GET_LOCAL_PORT";
case RAVA_OP_SERVER_SOCKET_IS_BOUND: return "SERVER_SOCKET_IS_BOUND";
case RAVA_OP_SERVER_SOCKET_IS_CLOSED: return "SERVER_SOCKET_IS_CLOSED";
case RAVA_OP_SERVER_SOCKET_SET_RECEIVE_BUFFER_SIZE: return "SERVER_SOCKET_SET_RECEIVE_BUFFER_SIZE";
case RAVA_OP_SERVER_SOCKET_GET_RECEIVE_BUFFER_SIZE: return "SERVER_SOCKET_GET_RECEIVE_BUFFER_SIZE";
case RAVA_OP_SERVER_SOCKET_SET_REUSE_ADDRESS: return "SERVER_SOCKET_SET_REUSE_ADDRESS";
case RAVA_OP_SERVER_SOCKET_GET_REUSE_ADDRESS: return "SERVER_SOCKET_GET_REUSE_ADDRESS";
case RAVA_OP_SOCKET_SET_SO_TIMEOUT: return "SOCKET_SET_SO_TIMEOUT";
case RAVA_OP_SOCKET_GET_SO_TIMEOUT: return "SOCKET_GET_SO_TIMEOUT";
case RAVA_OP_SOCKET_SET_TCP_NODELAY: return "SOCKET_SET_TCP_NODELAY";
case RAVA_OP_SOCKET_GET_TCP_NODELAY: return "SOCKET_GET_TCP_NODELAY";
case RAVA_OP_SOCKET_BIND: return "SOCKET_BIND";
case RAVA_OP_SOCKET_IS_CONNECTED: return "SOCKET_IS_CONNECTED";
case RAVA_OP_SOCKET_SHUTDOWN_INPUT: return "SOCKET_SHUTDOWN_INPUT";
case RAVA_OP_SOCKET_SHUTDOWN_OUTPUT: return "SOCKET_SHUTDOWN_OUTPUT";
case RAVA_OP_SOCKET_IS_INPUT_SHUTDOWN: return "SOCKET_IS_INPUT_SHUTDOWN";
case RAVA_OP_SOCKET_IS_OUTPUT_SHUTDOWN: return "SOCKET_IS_OUTPUT_SHUTDOWN";
case RAVA_OP_SOCKET_SET_SEND_BUFFER_SIZE: return "SOCKET_SET_SEND_BUFFER_SIZE";
case RAVA_OP_SOCKET_GET_SEND_BUFFER_SIZE: return "SOCKET_GET_SEND_BUFFER_SIZE";
case RAVA_OP_SOCKET_SET_RECEIVE_BUFFER_SIZE: return "SOCKET_SET_RECEIVE_BUFFER_SIZE";
case RAVA_OP_SOCKET_GET_RECEIVE_BUFFER_SIZE: return "SOCKET_GET_RECEIVE_BUFFER_SIZE";
case RAVA_OP_SOCKET_SET_KEEP_ALIVE: return "SOCKET_SET_KEEP_ALIVE";
case RAVA_OP_SOCKET_GET_KEEP_ALIVE: return "SOCKET_GET_KEEP_ALIVE";
case RAVA_OP_SOCKET_SET_REUSE_ADDRESS: return "SOCKET_SET_REUSE_ADDRESS";
case RAVA_OP_SOCKET_GET_REUSE_ADDRESS: return "SOCKET_GET_REUSE_ADDRESS";
case RAVA_OP_METHOD_REF: return "METHOD_REF";
case RAVA_OP_METHOD_REF_INVOKE: return "METHOD_REF_INVOKE";
default: return "UNKNOWN";

50
ir/ir.h
View File

@ -156,9 +156,59 @@ typedef enum {
RAVA_OP_SOCKET_GET_INPUT_STREAM,
RAVA_OP_SOCKET_GET_OUTPUT_STREAM,
RAVA_OP_INPUT_STREAM_READ,
RAVA_OP_INPUT_STREAM_READ_BYTES,
RAVA_OP_INPUT_STREAM_AVAILABLE,
RAVA_OP_INPUT_STREAM_SKIP,
RAVA_OP_OUTPUT_STREAM_WRITE,
RAVA_OP_OUTPUT_STREAM_FLUSH,
RAVA_OP_STREAM_CLOSE,
RAVA_OP_INETADDRESS_GET_BY_NAME,
RAVA_OP_INETADDRESS_GET_LOCAL_HOST,
RAVA_OP_INETADDRESS_GET_LOOPBACK,
RAVA_OP_INETADDRESS_GET_HOST_NAME,
RAVA_OP_INETADDRESS_GET_HOST_ADDRESS,
RAVA_OP_INETADDRESS_IS_LOOPBACK,
RAVA_OP_INETADDRESS_IS_ANY_LOCAL,
RAVA_OP_INETADDRESS_GET_ALL_BY_NAME,
RAVA_OP_INETADDRESS_GET_ADDRESS,
RAVA_OP_INETADDRESS_IS_MULTICAST_ADDRESS,
RAVA_OP_INETADDRESS_IS_REACHABLE,
RAVA_OP_SOCKET_GET_PORT,
RAVA_OP_SOCKET_GET_LOCAL_PORT,
RAVA_OP_SOCKET_GET_INET_ADDRESS,
RAVA_OP_SOCKET_GET_LOCAL_ADDRESS,
RAVA_OP_SERVER_SOCKET_GET_LOCAL_PORT,
RAVA_OP_SERVER_SOCKET_IS_BOUND,
RAVA_OP_SERVER_SOCKET_IS_CLOSED,
RAVA_OP_SERVER_SOCKET_SET_RECEIVE_BUFFER_SIZE,
RAVA_OP_SERVER_SOCKET_GET_RECEIVE_BUFFER_SIZE,
RAVA_OP_SERVER_SOCKET_SET_REUSE_ADDRESS,
RAVA_OP_SERVER_SOCKET_GET_REUSE_ADDRESS,
RAVA_OP_SOCKET_SET_SO_TIMEOUT,
RAVA_OP_SOCKET_GET_SO_TIMEOUT,
RAVA_OP_SOCKET_SET_TCP_NODELAY,
RAVA_OP_SOCKET_GET_TCP_NODELAY,
RAVA_OP_SOCKET_BIND,
RAVA_OP_SOCKET_IS_CONNECTED,
RAVA_OP_SOCKET_SHUTDOWN_INPUT,
RAVA_OP_SOCKET_SHUTDOWN_OUTPUT,
RAVA_OP_SOCKET_IS_INPUT_SHUTDOWN,
RAVA_OP_SOCKET_IS_OUTPUT_SHUTDOWN,
RAVA_OP_SOCKET_SET_SEND_BUFFER_SIZE,
RAVA_OP_SOCKET_GET_SEND_BUFFER_SIZE,
RAVA_OP_SOCKET_SET_RECEIVE_BUFFER_SIZE,
RAVA_OP_SOCKET_GET_RECEIVE_BUFFER_SIZE,
RAVA_OP_SOCKET_SET_KEEP_ALIVE,
RAVA_OP_SOCKET_GET_KEEP_ALIVE,
RAVA_OP_SOCKET_SET_REUSE_ADDRESS,
RAVA_OP_SOCKET_GET_REUSE_ADDRESS,
RAVA_OP_METHOD_REF,
RAVA_OP_METHOD_REF_INVOKE
} RavaOpCode_e;

View File

@ -513,7 +513,52 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
bool is_socket_get_output_stream = false;
bool is_server_socket_accept = false;
bool is_input_stream_read = false;
bool is_input_stream_read_bytes = false;
bool is_input_stream_available = false;
bool is_input_stream_skip = false;
bool is_output_stream_write = false;
bool is_output_stream_flush = false;
bool is_inetaddress_get_by_name = false;
bool is_inetaddress_get_local_host = false;
bool is_inetaddress_get_loopback = false;
bool is_inetaddress_get_host_name = false;
bool is_inetaddress_get_host_address = false;
bool is_inetaddress_is_loopback = false;
bool is_inetaddress_is_any_local = false;
bool is_inetaddress_get_all_by_name = false;
bool is_inetaddress_get_address = false;
bool is_inetaddress_is_multicast_address = false;
bool is_inetaddress_is_reachable = false;
bool is_socket_get_port = false;
bool is_socket_get_local_port = false;
bool is_socket_get_inet_address = false;
bool is_socket_get_local_address = false;
bool is_server_socket_get_local_port = false;
bool is_server_socket_is_bound = false;
bool is_server_socket_is_closed = false;
bool is_server_socket_set_receive_buffer_size = false;
bool is_server_socket_get_receive_buffer_size = false;
bool is_server_socket_set_reuse_address = false;
bool is_server_socket_get_reuse_address = false;
bool is_socket_set_so_timeout = false;
bool is_socket_get_so_timeout = false;
bool is_socket_set_tcp_nodelay = false;
bool is_socket_get_tcp_nodelay = false;
bool is_socket_bind = false;
bool is_socket_is_connected = false;
bool is_socket_shutdown_input = false;
bool is_socket_shutdown_output = false;
bool is_socket_is_input_shutdown = false;
bool is_socket_is_output_shutdown = false;
bool is_socket_set_send_buffer_size = false;
bool is_socket_get_send_buffer_size = false;
bool is_socket_set_receive_buffer_size = false;
bool is_socket_get_receive_buffer_size = false;
bool is_socket_set_keep_alive = false;
bool is_socket_get_keep_alive = false;
bool is_socket_set_reuse_address = false;
bool is_socket_get_reuse_address = false;
RavaASTNode_t *inetaddress_object = NULL;
RavaASTNode_t *string_object = NULL;
RavaASTNode_t *collection_object = NULL;
RavaASTNode_t *socket_object = NULL;
@ -585,6 +630,19 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
is_math_random = true;
}
}
if (member->data.member_access.object->type == RAVA_AST_IDENTIFIER_EXPR &&
strcmp(member->data.member_access.object->data.identifier.name, "InetAddress") == 0) {
const char *method = member->data.member_access.member;
if (strcmp(method, "getByName") == 0 && expr->data.call.arguments_count == 1) {
is_inetaddress_get_by_name = true;
} else if (strcmp(method, "getLocalHost") == 0 && expr->data.call.arguments_count == 0) {
is_inetaddress_get_local_host = true;
} else if (strcmp(method, "getLoopbackAddress") == 0 && expr->data.call.arguments_count == 0) {
is_inetaddress_get_loopback = true;
} else if (strcmp(method, "getAllByName") == 0 && expr->data.call.arguments_count == 1) {
is_inetaddress_get_all_by_name = true;
}
}
if (strcmp(member->data.member_access.member, "length") == 0 && expr->data.call.arguments_count == 0) {
is_string_length = true;
string_object = member->data.member_access.object;
@ -660,15 +718,132 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
} else if (strcmp(member->data.member_access.member, "accept") == 0 && expr->data.call.arguments_count == 0) {
is_server_socket_accept = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "read") == 0) {
} else if (strcmp(member->data.member_access.member, "read") == 0 && expr->data.call.arguments_count == 0) {
is_input_stream_read = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "read") == 0 && expr->data.call.arguments_count == 3) {
is_input_stream_read_bytes = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "available") == 0 && expr->data.call.arguments_count == 0) {
is_input_stream_available = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "skip") == 0 && expr->data.call.arguments_count == 1) {
is_input_stream_skip = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "write") == 0) {
is_output_stream_write = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "flush") == 0 && expr->data.call.arguments_count == 0) {
is_output_stream_flush = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "close") == 0 && expr->data.call.arguments_count == 0) {
is_socket_close = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "getHostName") == 0 && expr->data.call.arguments_count == 0) {
is_inetaddress_get_host_name = true;
inetaddress_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "getHostAddress") == 0 && expr->data.call.arguments_count == 0) {
is_inetaddress_get_host_address = true;
inetaddress_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "isLoopbackAddress") == 0 && expr->data.call.arguments_count == 0) {
is_inetaddress_is_loopback = true;
inetaddress_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "isAnyLocalAddress") == 0 && expr->data.call.arguments_count == 0) {
is_inetaddress_is_any_local = true;
inetaddress_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "getAddress") == 0 && expr->data.call.arguments_count == 0) {
is_inetaddress_get_address = true;
inetaddress_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "isMulticastAddress") == 0 && expr->data.call.arguments_count == 0) {
is_inetaddress_is_multicast_address = true;
inetaddress_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "isReachable") == 0 && expr->data.call.arguments_count == 1) {
is_inetaddress_is_reachable = true;
inetaddress_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "getPort") == 0 && expr->data.call.arguments_count == 0) {
is_socket_get_port = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "getLocalPort") == 0 && expr->data.call.arguments_count == 0) {
is_socket_get_local_port = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "getInetAddress") == 0 && expr->data.call.arguments_count == 0) {
is_socket_get_inet_address = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "getLocalAddress") == 0 && expr->data.call.arguments_count == 0) {
is_socket_get_local_address = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "isBound") == 0 && expr->data.call.arguments_count == 0) {
is_server_socket_is_bound = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "isClosed") == 0 && expr->data.call.arguments_count == 0) {
is_server_socket_is_closed = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "setReceiveBufferSize") == 0 && expr->data.call.arguments_count == 1) {
is_server_socket_set_receive_buffer_size = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "getReceiveBufferSize") == 0 && expr->data.call.arguments_count == 0) {
is_server_socket_get_receive_buffer_size = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "setReuseAddress") == 0 && expr->data.call.arguments_count == 1) {
is_server_socket_set_reuse_address = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "getReuseAddress") == 0 && expr->data.call.arguments_count == 0) {
is_server_socket_get_reuse_address = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "setSoTimeout") == 0 && expr->data.call.arguments_count == 1) {
is_socket_set_so_timeout = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "getSoTimeout") == 0 && expr->data.call.arguments_count == 0) {
is_socket_get_so_timeout = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "setTcpNoDelay") == 0 && expr->data.call.arguments_count == 1) {
is_socket_set_tcp_nodelay = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "getTcpNoDelay") == 0 && expr->data.call.arguments_count == 0) {
is_socket_get_tcp_nodelay = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "bind") == 0 && expr->data.call.arguments_count == 2) {
is_socket_bind = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "isConnected") == 0 && expr->data.call.arguments_count == 0) {
is_socket_is_connected = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "shutdownInput") == 0 && expr->data.call.arguments_count == 0) {
is_socket_shutdown_input = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "shutdownOutput") == 0 && expr->data.call.arguments_count == 0) {
is_socket_shutdown_output = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "isInputShutdown") == 0 && expr->data.call.arguments_count == 0) {
is_socket_is_input_shutdown = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "isOutputShutdown") == 0 && expr->data.call.arguments_count == 0) {
is_socket_is_output_shutdown = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "setSendBufferSize") == 0 && expr->data.call.arguments_count == 1) {
is_socket_set_send_buffer_size = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "getSendBufferSize") == 0 && expr->data.call.arguments_count == 0) {
is_socket_get_send_buffer_size = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "setReceiveBufferSize") == 0 && expr->data.call.arguments_count == 1) {
is_socket_set_receive_buffer_size = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "getReceiveBufferSize") == 0 && expr->data.call.arguments_count == 0) {
is_socket_get_receive_buffer_size = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "setKeepAlive") == 0 && expr->data.call.arguments_count == 1) {
is_socket_set_keep_alive = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "getKeepAlive") == 0 && expr->data.call.arguments_count == 0) {
is_socket_get_keep_alive = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "setReuseAddress") == 0 && expr->data.call.arguments_count == 1) {
is_socket_set_reuse_address = true;
socket_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "getReuseAddress") == 0 && expr->data.call.arguments_count == 0) {
is_socket_get_reuse_address = true;
socket_object = member->data.member_access.object;
}
}
@ -876,6 +1051,22 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
_rava_ir_gen_expression(gen, socket_object);
instr.opcode = RAVA_OP_INPUT_STREAM_READ;
_rava_ir_emit(gen, instr);
} else if (is_input_stream_read_bytes) {
_rava_ir_gen_expression(gen, socket_object);
for (size_t i = 0; i < expr->data.call.arguments_count; i++) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[i]);
}
instr.opcode = RAVA_OP_INPUT_STREAM_READ_BYTES;
_rava_ir_emit(gen, instr);
} else if (is_input_stream_available) {
_rava_ir_gen_expression(gen, socket_object);
instr.opcode = RAVA_OP_INPUT_STREAM_AVAILABLE;
_rava_ir_emit(gen, instr);
} else if (is_input_stream_skip) {
_rava_ir_gen_expression(gen, socket_object);
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_INPUT_STREAM_SKIP;
_rava_ir_emit(gen, instr);
} else if (is_output_stream_write) {
_rava_ir_gen_expression(gen, socket_object);
for (size_t i = 0; i < expr->data.call.arguments_count; i++) {
@ -884,10 +1075,183 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
instr.opcode = RAVA_OP_OUTPUT_STREAM_WRITE;
instr.operand.int_value = expr->data.call.arguments_count;
_rava_ir_emit(gen, instr);
} else if (is_output_stream_flush) {
_rava_ir_gen_expression(gen, socket_object);
instr.opcode = RAVA_OP_OUTPUT_STREAM_FLUSH;
_rava_ir_emit(gen, instr);
} else if (is_socket_close) {
_rava_ir_gen_expression(gen, socket_object);
instr.opcode = RAVA_OP_SOCKET_CLOSE;
_rava_ir_emit(gen, instr);
} else if (is_inetaddress_get_by_name) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_INETADDRESS_GET_BY_NAME;
_rava_ir_emit(gen, instr);
} else if (is_inetaddress_get_local_host) {
instr.opcode = RAVA_OP_INETADDRESS_GET_LOCAL_HOST;
_rava_ir_emit(gen, instr);
} else if (is_inetaddress_get_loopback) {
instr.opcode = RAVA_OP_INETADDRESS_GET_LOOPBACK;
_rava_ir_emit(gen, instr);
} else if (is_inetaddress_get_host_name) {
_rava_ir_gen_expression(gen, inetaddress_object);
instr.opcode = RAVA_OP_INETADDRESS_GET_HOST_NAME;
_rava_ir_emit(gen, instr);
} else if (is_inetaddress_get_host_address) {
_rava_ir_gen_expression(gen, inetaddress_object);
instr.opcode = RAVA_OP_INETADDRESS_GET_HOST_ADDRESS;
_rava_ir_emit(gen, instr);
} else if (is_inetaddress_is_loopback) {
_rava_ir_gen_expression(gen, inetaddress_object);
instr.opcode = RAVA_OP_INETADDRESS_IS_LOOPBACK;
_rava_ir_emit(gen, instr);
} else if (is_inetaddress_is_any_local) {
_rava_ir_gen_expression(gen, inetaddress_object);
instr.opcode = RAVA_OP_INETADDRESS_IS_ANY_LOCAL;
_rava_ir_emit(gen, instr);
} else if (is_inetaddress_get_all_by_name) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_INETADDRESS_GET_ALL_BY_NAME;
_rava_ir_emit(gen, instr);
} else if (is_inetaddress_get_address) {
_rava_ir_gen_expression(gen, inetaddress_object);
instr.opcode = RAVA_OP_INETADDRESS_GET_ADDRESS;
_rava_ir_emit(gen, instr);
} else if (is_inetaddress_is_multicast_address) {
_rava_ir_gen_expression(gen, inetaddress_object);
instr.opcode = RAVA_OP_INETADDRESS_IS_MULTICAST_ADDRESS;
_rava_ir_emit(gen, instr);
} else if (is_inetaddress_is_reachable) {
_rava_ir_gen_expression(gen, inetaddress_object);
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_INETADDRESS_IS_REACHABLE;
_rava_ir_emit(gen, instr);
} else if (is_socket_get_port) {
_rava_ir_gen_expression(gen, socket_object);
instr.opcode = RAVA_OP_SOCKET_GET_PORT;
_rava_ir_emit(gen, instr);
} else if (is_socket_get_local_port) {
_rava_ir_gen_expression(gen, socket_object);
instr.opcode = RAVA_OP_SOCKET_GET_LOCAL_PORT;
_rava_ir_emit(gen, instr);
} else if (is_socket_get_inet_address) {
_rava_ir_gen_expression(gen, socket_object);
instr.opcode = RAVA_OP_SOCKET_GET_INET_ADDRESS;
_rava_ir_emit(gen, instr);
} else if (is_socket_get_local_address) {
_rava_ir_gen_expression(gen, socket_object);
instr.opcode = RAVA_OP_SOCKET_GET_LOCAL_ADDRESS;
_rava_ir_emit(gen, instr);
} else if (is_server_socket_get_local_port) {
_rava_ir_gen_expression(gen, socket_object);
instr.opcode = RAVA_OP_SERVER_SOCKET_GET_LOCAL_PORT;
_rava_ir_emit(gen, instr);
} else if (is_server_socket_is_bound) {
_rava_ir_gen_expression(gen, socket_object);
instr.opcode = RAVA_OP_SERVER_SOCKET_IS_BOUND;
_rava_ir_emit(gen, instr);
} else if (is_server_socket_is_closed) {
_rava_ir_gen_expression(gen, socket_object);
instr.opcode = RAVA_OP_SERVER_SOCKET_IS_CLOSED;
_rava_ir_emit(gen, instr);
} else if (is_server_socket_set_receive_buffer_size) {
_rava_ir_gen_expression(gen, socket_object);
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_SERVER_SOCKET_SET_RECEIVE_BUFFER_SIZE;
_rava_ir_emit(gen, instr);
} else if (is_server_socket_get_receive_buffer_size) {
_rava_ir_gen_expression(gen, socket_object);
instr.opcode = RAVA_OP_SERVER_SOCKET_GET_RECEIVE_BUFFER_SIZE;
_rava_ir_emit(gen, instr);
} else if (is_server_socket_set_reuse_address) {
_rava_ir_gen_expression(gen, socket_object);
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_SERVER_SOCKET_SET_REUSE_ADDRESS;
_rava_ir_emit(gen, instr);
} else if (is_server_socket_get_reuse_address) {
_rava_ir_gen_expression(gen, socket_object);
instr.opcode = RAVA_OP_SERVER_SOCKET_GET_REUSE_ADDRESS;
_rava_ir_emit(gen, instr);
} else if (is_socket_set_so_timeout) {
_rava_ir_gen_expression(gen, socket_object);
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_SOCKET_SET_SO_TIMEOUT;
_rava_ir_emit(gen, instr);
} else if (is_socket_get_so_timeout) {
_rava_ir_gen_expression(gen, socket_object);
instr.opcode = RAVA_OP_SOCKET_GET_SO_TIMEOUT;
_rava_ir_emit(gen, instr);
} else if (is_socket_set_tcp_nodelay) {
_rava_ir_gen_expression(gen, socket_object);
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_SOCKET_SET_TCP_NODELAY;
_rava_ir_emit(gen, instr);
} else if (is_socket_get_tcp_nodelay) {
_rava_ir_gen_expression(gen, socket_object);
instr.opcode = RAVA_OP_SOCKET_GET_TCP_NODELAY;
_rava_ir_emit(gen, instr);
} else if (is_socket_bind) {
_rava_ir_gen_expression(gen, socket_object);
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
_rava_ir_gen_expression(gen, expr->data.call.arguments[1]);
instr.opcode = RAVA_OP_SOCKET_BIND;
_rava_ir_emit(gen, instr);
} else if (is_socket_is_connected) {
_rava_ir_gen_expression(gen, socket_object);
instr.opcode = RAVA_OP_SOCKET_IS_CONNECTED;
_rava_ir_emit(gen, instr);
} else if (is_socket_shutdown_input) {
_rava_ir_gen_expression(gen, socket_object);
instr.opcode = RAVA_OP_SOCKET_SHUTDOWN_INPUT;
_rava_ir_emit(gen, instr);
} else if (is_socket_shutdown_output) {
_rava_ir_gen_expression(gen, socket_object);
instr.opcode = RAVA_OP_SOCKET_SHUTDOWN_OUTPUT;
_rava_ir_emit(gen, instr);
} else if (is_socket_is_input_shutdown) {
_rava_ir_gen_expression(gen, socket_object);
instr.opcode = RAVA_OP_SOCKET_IS_INPUT_SHUTDOWN;
_rava_ir_emit(gen, instr);
} else if (is_socket_is_output_shutdown) {
_rava_ir_gen_expression(gen, socket_object);
instr.opcode = RAVA_OP_SOCKET_IS_OUTPUT_SHUTDOWN;
_rava_ir_emit(gen, instr);
} else if (is_socket_set_send_buffer_size) {
_rava_ir_gen_expression(gen, socket_object);
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_SOCKET_SET_SEND_BUFFER_SIZE;
_rava_ir_emit(gen, instr);
} else if (is_socket_get_send_buffer_size) {
_rava_ir_gen_expression(gen, socket_object);
instr.opcode = RAVA_OP_SOCKET_GET_SEND_BUFFER_SIZE;
_rava_ir_emit(gen, instr);
} else if (is_socket_set_receive_buffer_size) {
_rava_ir_gen_expression(gen, socket_object);
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_SOCKET_SET_RECEIVE_BUFFER_SIZE;
_rava_ir_emit(gen, instr);
} else if (is_socket_get_receive_buffer_size) {
_rava_ir_gen_expression(gen, socket_object);
instr.opcode = RAVA_OP_SOCKET_GET_RECEIVE_BUFFER_SIZE;
_rava_ir_emit(gen, instr);
} else if (is_socket_set_keep_alive) {
_rava_ir_gen_expression(gen, socket_object);
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_SOCKET_SET_KEEP_ALIVE;
_rava_ir_emit(gen, instr);
} else if (is_socket_get_keep_alive) {
_rava_ir_gen_expression(gen, socket_object);
instr.opcode = RAVA_OP_SOCKET_GET_KEEP_ALIVE;
_rava_ir_emit(gen, instr);
} else if (is_socket_set_reuse_address) {
_rava_ir_gen_expression(gen, socket_object);
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_SOCKET_SET_REUSE_ADDRESS;
_rava_ir_emit(gen, instr);
} else if (is_socket_get_reuse_address) {
_rava_ir_gen_expression(gen, socket_object);
instr.opcode = RAVA_OP_SOCKET_GET_REUSE_ADDRESS;
_rava_ir_emit(gen, instr);
} else if (is_println || is_print) {
for (size_t i = 0; i < expr->data.call.arguments_count; i++) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[i]);

File diff suppressed because it is too large Load Diff

View File

@ -32,7 +32,8 @@ typedef enum {
RAVA_VAL_HASHMAP,
RAVA_VAL_SOCKET,
RAVA_VAL_STREAM,
RAVA_VAL_METHOD_REF
RAVA_VAL_METHOD_REF,
RAVA_VAL_INETADDRESS
} RavaValueType_e;
typedef struct {
@ -49,6 +50,7 @@ typedef struct RavaHashMap_t RavaHashMap_t;
typedef struct RavaSocket_t RavaSocket_t;
typedef struct RavaStream_t RavaStream_t;
typedef struct RavaMethodRef_t RavaMethodRef_t;
typedef struct RavaInetAddress_t RavaInetAddress_t;
#define RAVA_OBJECT_HASH_SIZE 32
@ -79,6 +81,7 @@ struct RavaValue_t {
RavaSocket_t *socket_val;
RavaStream_t *stream_val;
RavaMethodRef_t *method_ref_val;
RavaInetAddress_t *inetaddress_val;
} data;
};
@ -118,6 +121,9 @@ struct RavaSocket_t {
int fd;
bool connected;
bool closed;
bool bound;
bool input_shutdown;
bool output_shutdown;
};
#define RAVA_STREAM_TYPE_INPUT 1
@ -140,6 +146,17 @@ struct RavaMethodRef_t {
bool has_target;
};
#define RAVA_INETADDRESS_IPV4 1
#define RAVA_INETADDRESS_IPV6 2
struct RavaInetAddress_t {
RavaGCHeader_t gc;
int address_type;
uint8_t address[16];
char *hostname;
char *hostaddress;
};
typedef struct {
RavaValue_t *values;
size_t capacity;
@ -365,6 +382,63 @@ int rava_stream_read_byte(RavaStream_t *stream);
void rava_stream_write(RavaStream_t *stream, const char *data);
void rava_stream_write_byte(RavaStream_t *stream, int byte);
void rava_stream_close(RavaStream_t *stream);
int rava_stream_read_bytes(RavaStream_t *stream, RavaArray_t *arr, int off, int len);
int rava_stream_available(RavaStream_t *stream);
void rava_stream_flush(RavaStream_t *stream);
long rava_stream_skip(RavaStream_t *stream, long n);
RavaInetAddress_t* rava_inetaddress_create(void);
RavaInetAddress_t* rava_inetaddress_get_by_name(const char *host);
RavaInetAddress_t* rava_inetaddress_get_local_host(void);
RavaInetAddress_t* rava_inetaddress_get_loopback(void);
char* rava_inetaddress_get_host_name(RavaInetAddress_t *addr);
char* rava_inetaddress_get_host_address(RavaInetAddress_t *addr);
bool rava_inetaddress_is_loopback(RavaInetAddress_t *addr);
bool rava_inetaddress_is_any_local(RavaInetAddress_t *addr);
RavaArray_t* rava_inetaddress_get_all_by_name(const char *host);
RavaArray_t* rava_inetaddress_get_address(RavaInetAddress_t *addr);
bool rava_inetaddress_is_multicast_address(RavaInetAddress_t *addr);
bool rava_inetaddress_is_reachable(RavaInetAddress_t *addr, int timeout);
int rava_socket_get_port(RavaSocket_t *socket);
int rava_socket_get_local_port(RavaSocket_t *socket);
RavaInetAddress_t* rava_socket_get_inet_address(RavaSocket_t *socket);
RavaInetAddress_t* rava_socket_get_local_address(RavaSocket_t *socket);
int rava_server_socket_get_local_port(RavaSocket_t *socket);
bool rava_server_socket_is_bound(RavaSocket_t *socket);
bool rava_server_socket_is_closed(RavaSocket_t *socket);
void rava_server_socket_set_so_timeout(RavaSocket_t *socket, int timeout);
int rava_server_socket_get_so_timeout(RavaSocket_t *socket);
void rava_server_socket_set_receive_buffer_size(RavaSocket_t *socket, int size);
int rava_server_socket_get_receive_buffer_size(RavaSocket_t *socket);
void rava_server_socket_set_reuse_address(RavaSocket_t *socket, bool reuse);
bool rava_server_socket_get_reuse_address(RavaSocket_t *socket);
void rava_socket_set_so_timeout(RavaSocket_t *socket, int timeout_ms);
int rava_socket_get_so_timeout(RavaSocket_t *socket);
void rava_socket_set_tcp_nodelay(RavaSocket_t *socket, bool nodelay);
bool rava_socket_get_tcp_nodelay(RavaSocket_t *socket);
void rava_socket_bind(RavaSocket_t *socket, const char *host, int port);
bool rava_socket_is_connected(RavaSocket_t *socket);
bool rava_socket_is_closed(RavaSocket_t *socket);
bool rava_socket_is_bound(RavaSocket_t *socket);
void rava_socket_shutdown_input(RavaSocket_t *socket);
void rava_socket_shutdown_output(RavaSocket_t *socket);
bool rava_socket_is_input_shutdown(RavaSocket_t *socket);
bool rava_socket_is_output_shutdown(RavaSocket_t *socket);
void rava_socket_set_send_buffer_size(RavaSocket_t *socket, int size);
int rava_socket_get_send_buffer_size(RavaSocket_t *socket);
void rava_socket_set_receive_buffer_size(RavaSocket_t *socket, int size);
int rava_socket_get_receive_buffer_size(RavaSocket_t *socket);
void rava_socket_set_keep_alive(RavaSocket_t *socket, bool keepalive);
bool rava_socket_get_keep_alive(RavaSocket_t *socket);
void rava_socket_set_reuse_address(RavaSocket_t *socket, bool reuse);
bool rava_socket_get_reuse_address(RavaSocket_t *socket);
static inline RavaValue_t rava_value_inetaddress(RavaInetAddress_t *addr) {
RavaValue_t val;
val.type = RAVA_VAL_INETADDRESS;
val.data.inetaddress_val = addr;
return val;
}
static inline RavaValue_t rava_value_socket(RavaSocket_t *socket) {
RavaValue_t val;
@ -437,6 +511,7 @@ RavaValue_t rava_native_to_value(RavaNativeValue_t native);
#define RAVA_GC_TYPE_SOCKET 6
#define RAVA_GC_TYPE_STREAM 7
#define RAVA_GC_TYPE_METHODREF 8
#define RAVA_GC_TYPE_INETADDRESS 9
void rava_gc_init(void);
void rava_gc_shutdown(void);

View File

@ -0,0 +1,23 @@
#include "runtime_internal.h"
RavaExceptionStack_t* rava_exception_stack_create(void) {
RavaExceptionStack_t *stack = calloc(1, sizeof(RavaExceptionStack_t));
if (!stack) return NULL;
stack->count = 0;
return stack;
}
void rava_exception_stack_destroy(RavaExceptionStack_t *stack) {
free(stack);
}
void rava_exception_stack_push(RavaExceptionStack_t *stack, RavaExceptionHandler_t handler) {
if (stack->count >= RAVA_MAX_EXCEPTION_DEPTH) return;
stack->handlers[stack->count++] = handler;
}
bool rava_exception_stack_pop(RavaExceptionStack_t *stack, RavaExceptionHandler_t *handler) {
if (stack->count == 0) return false;
*handler = stack->handlers[--stack->count];
return true;
}

25
runtime/runtime_intern.c Normal file
View File

@ -0,0 +1,25 @@
#include "runtime_internal.h"
const char* _rava_intern_string(RavaVM_t *vm, const char *str) {
uint32_t h = _intern_hash(str);
for (size_t i = 0; i < RAVA_INTERN_TABLE_SIZE; i++) {
size_t idx = (h + i) & (RAVA_INTERN_TABLE_SIZE - 1);
if (vm->intern_table.strings[idx] == NULL) {
if (vm->intern_table.count >= RAVA_INTERN_TABLE_SIZE - 1) {
static bool warned = false;
if (!warned) {
fprintf(stderr, "Warning: String intern table full (%d entries)\n",
RAVA_INTERN_TABLE_SIZE);
warned = true;
}
}
vm->intern_table.strings[idx] = strdup(str);
vm->intern_table.count++;
return vm->intern_table.strings[idx];
}
if (strcmp(vm->intern_table.strings[idx], str) == 0) {
return vm->intern_table.strings[idx];
}
}
return strdup(str);
}

174
runtime/runtime_internal.h Normal file
View File

@ -0,0 +1,174 @@
#ifndef RAVA_RUNTIME_INTERNAL_H
#define RAVA_RUNTIME_INTERNAL_H
#define _POSIX_C_SOURCE 200809L
#include "runtime.h"
#include "labeltable.h"
#include "methodcache.h"
#include "nanbox.h"
#include "fastframe.h"
#include "superinst.h"
#include "../utils/safe_alloc.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <ctype.h>
#ifdef __GNUC__
#define LIKELY(x) __builtin_expect(!!(x), 1)
#define UNLIKELY(x) __builtin_expect(!!(x), 0)
#else
#define LIKELY(x) (x)
#define UNLIKELY(x) (x)
#endif
#define STACK_ENSURE_CAPACITY(stack) do { \
if ((stack)->top >= (stack)->capacity) { \
(stack)->capacity *= 2; \
RavaValue_t *_new_values = realloc((stack)->values, sizeof(RavaValue_t) * (stack)->capacity); \
if (_new_values) (stack)->values = _new_values; \
} \
} while(0)
#define STACK_PUSH(stack, val) do { \
STACK_ENSURE_CAPACITY(stack); \
(stack)->values[(stack)->top++] = (val); \
} while(0)
#define STACK_POP(stack) ((stack)->top > 0 ? (stack)->values[--(stack)->top] : (RavaValue_t){0})
#define STACK_PEEK(stack) ((stack)->top > 0 ? (stack)->values[(stack)->top - 1] : (RavaValue_t){0})
#define STACK_PUSH_INT(stack, v) do { \
STACK_ENSURE_CAPACITY(stack); \
RavaValue_t _v; _v.type = RAVA_VAL_INT; _v.data.int_val = (v); \
(stack)->values[(stack)->top++] = _v; \
} while(0)
#define STACK_PUSH_LONG(stack, v) do { \
STACK_ENSURE_CAPACITY(stack); \
RavaValue_t _v; _v.type = RAVA_VAL_LONG; _v.data.long_val = (v); \
(stack)->values[(stack)->top++] = _v; \
} while(0)
#define STACK_PUSH_BOOL(stack, v) do { \
STACK_ENSURE_CAPACITY(stack); \
RavaValue_t _v; _v.type = RAVA_VAL_BOOLEAN; _v.data.bool_val = (v); \
(stack)->values[(stack)->top++] = _v; \
} while(0)
#define VALUE_IS_INT(v) ((v).type == RAVA_VAL_INT)
#define VALUE_IS_LONG(v) ((v).type == RAVA_VAL_LONG)
#define VALUE_AS_INT_FAST(v) ((v).data.int_val)
#define VALUE_AS_LONG_FAST(v) ((v).data.long_val)
static inline RavaNanboxValue_t rava_value_to_nanbox(RavaValue_t val) {
switch (val.type) {
case RAVA_VAL_INT: return rava_nanbox_int(val.data.int_val);
case RAVA_VAL_LONG: return rava_nanbox_long(val.data.long_val);
case RAVA_VAL_DOUBLE: return rava_nanbox_double(val.data.double_val);
case RAVA_VAL_FLOAT: return rava_nanbox_double((double)val.data.float_val);
case RAVA_VAL_BOOLEAN: return rava_nanbox_bool(val.data.bool_val);
case RAVA_VAL_NULL: return rava_nanbox_null();
case RAVA_VAL_STRING: return rava_nanbox_string(val.data.string_val);
case RAVA_VAL_OBJECT: return rava_nanbox_object(val.data.object_val);
case RAVA_VAL_ARRAY: return rava_nanbox_array(val.data.array_val);
default: return rava_nanbox_null();
}
}
static inline RavaValue_t rava_nanbox_to_value(RavaNanboxValue_t nb) {
RavaValue_t val;
if (rava_nanbox_is_int(nb)) {
val.type = RAVA_VAL_INT;
val.data.int_val = rava_nanbox_as_int(nb);
} else if (rava_nanbox_is_long(nb)) {
val.type = RAVA_VAL_LONG;
val.data.long_val = rava_nanbox_as_long(nb);
} else if (rava_nanbox_is_double(nb)) {
val.type = RAVA_VAL_DOUBLE;
val.data.double_val = rava_nanbox_as_double(nb);
} else if (rava_nanbox_is_bool(nb)) {
val.type = RAVA_VAL_BOOLEAN;
val.data.bool_val = rava_nanbox_as_bool(nb);
} else if (rava_nanbox_is_null(nb)) {
val.type = RAVA_VAL_NULL;
val.data.object_val = NULL;
} else if (rava_nanbox_is_string(nb)) {
val.type = RAVA_VAL_STRING;
val.data.string_val = (char*)rava_nanbox_as_string(nb);
} else if (rava_nanbox_is_object(nb)) {
val.type = RAVA_VAL_OBJECT;
val.data.object_val = rava_nanbox_as_object(nb);
} else if (rava_nanbox_is_array(nb)) {
val.type = RAVA_VAL_ARRAY;
val.data.array_val = rava_nanbox_as_array(nb);
} else {
val.type = RAVA_VAL_NULL;
val.data.object_val = NULL;
}
return val;
}
static inline uint32_t _rava_field_hash(const char *name) {
uint32_t hash = 5381;
while (*name) {
hash = ((hash << 5) + hash) ^ (uint32_t)*name++;
}
return hash;
}
static inline uint32_t _rava_class_hash(const char *name) {
uint32_t hash = 5381;
while (*name) hash = ((hash << 5) + hash) ^ (uint32_t)*name++;
return hash & (RAVA_CLASS_HASH_SIZE - 1);
}
static inline uint32_t _rava_method_hash(const char *name) {
uint32_t hash = 5381;
while (*name) hash = ((hash << 5) + hash) ^ (uint32_t)*name++;
return hash & (RAVA_METHOD_HASH_SIZE - 1);
}
static inline uint32_t _rava_static_hash(const char *class_name, const char *field_name) {
uint32_t hash = 5381;
while (*class_name) hash = ((hash << 5) + hash) ^ (uint32_t)*class_name++;
hash = ((hash << 5) + hash) ^ (uint32_t)'.';
while (*field_name) hash = ((hash << 5) + hash) ^ (uint32_t)*field_name++;
return hash;
}
static inline uint32_t _intern_hash(const char *str) {
uint32_t hash = 5381;
while (*str) hash = ((hash << 5) + hash) ^ (uint32_t)*str++;
return hash;
}
char* _rava_get_string_buffer(RavaVM_t *vm, size_t needed);
const char* _rava_intern_string(RavaVM_t *vm, const char *str);
void _rava_object_set_field_vm(RavaObject_t *obj, const char *name, RavaValue_t value, RavaVM_t *vm);
RavaClass_t* _rava_vm_find_class(RavaVM_t *vm, const char *class_name);
RavaMethod_t* _rava_vm_find_method(RavaVM_t *vm, const char *class_name, const char *method_name);
RavaMethod_t* _rava_vm_find_method_cached(RavaVM_t *vm, const char *class_name, const char *method_name);
RavaStaticFieldTable_t* rava_static_field_table_create(void);
void rava_static_field_table_destroy(RavaStaticFieldTable_t *table);
RavaValue_t* rava_static_field_table_get(RavaStaticFieldTable_t *table, const char *class_name, const char *field_name);
void rava_static_field_table_set(RavaStaticFieldTable_t *table, const char *class_name, const char *field_name, RavaValue_t value);
RavaExceptionStack_t* rava_exception_stack_create(void);
void rava_exception_stack_destroy(RavaExceptionStack_t *stack);
void rava_exception_stack_push(RavaExceptionStack_t *stack, RavaExceptionHandler_t handler);
bool rava_exception_stack_pop(RavaExceptionStack_t *stack, RavaExceptionHandler_t *handler);
bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, RavaInstruction_t *instr);
bool _rava_vm_execute_fast(RavaVM_t *vm, RavaCallFrame_t *frame);
bool _rava_vm_execute_ultrafast(RavaVM_t *vm, RavaMethod_t *entry_method);
bool _rava_vm_run_static_initializers(RavaVM_t *vm);
extern bool g_gc_initialized;
#endif

53
runtime/runtime_lookup.c Normal file
View File

@ -0,0 +1,53 @@
#include "runtime_internal.h"
bool g_gc_initialized = false;
RavaClass_t* _rava_vm_find_class(RavaVM_t *vm, const char *class_name) {
uint32_t h = _rava_class_hash(class_name);
int idx = vm->class_hash[h];
if (idx >= 0 && (size_t)idx < vm->program->class_count &&
strcmp(vm->program->classes[idx]->name, class_name) == 0) {
return vm->program->classes[idx];
}
for (size_t i = 0; i < vm->program->class_count; i++) {
if (strcmp(vm->program->classes[i]->name, class_name) == 0) {
vm->class_hash[h] = (int)i;
return vm->program->classes[i];
}
}
return NULL;
}
RavaMethod_t* _rava_vm_find_method(RavaVM_t *vm, const char *class_name, const char *method_name) {
const char *current_class = class_name;
while (current_class) {
RavaClass_t *class = _rava_vm_find_class(vm, current_class);
if (!class) break;
uint32_t h = _rava_method_hash(method_name);
int idx = class->method_hash[h];
if (idx >= 0 && (size_t)idx < class->method_count &&
strcmp(class->methods[idx]->name, method_name) == 0) {
return class->methods[idx];
}
for (size_t j = 0; j < class->method_count; j++) {
if (strcmp(class->methods[j]->name, method_name) == 0) {
class->method_hash[h] = (int)j;
return class->methods[j];
}
}
current_class = class->superclass;
}
return NULL;
}
RavaMethod_t* _rava_vm_find_method_cached(RavaVM_t *vm, const char *class_name, const char *method_name) {
MethodCache_t *cache = (MethodCache_t*)vm->method_cache;
RavaMethod_t *cached = rava_methodcache_lookup(cache, class_name, method_name);
if (cached) return cached;
RavaMethod_t *method = _rava_vm_find_method(vm, class_name, method_name);
if (method) {
rava_methodcache_insert(cache, class_name, method_name, method);
}
return method;
}

View File

@ -178,6 +178,8 @@ int32_t rava_object_hashcode(RavaValue_t value) {
return (int32_t)((uintptr_t)value.data.socket_val >> 3);
case RAVA_VAL_STREAM:
return (int32_t)((uintptr_t)value.data.stream_val >> 3);
case RAVA_VAL_INETADDRESS:
return (int32_t)((uintptr_t)value.data.inetaddress_val >> 3);
case RAVA_VAL_METHOD_REF:
return (int32_t)((uintptr_t)value.data.method_ref_val >> 3);
}
@ -287,6 +289,13 @@ char* rava_object_tostring(RavaValue_t value) {
snprintf(buffer, 128, "Stream@%x",
(unsigned int)((uintptr_t)value.data.stream_val >> 3));
break;
case RAVA_VAL_INETADDRESS:
if (value.data.inetaddress_val && value.data.inetaddress_val->hostaddress) {
snprintf(buffer, 128, "/%s", value.data.inetaddress_val->hostaddress);
} else {
strcpy(buffer, "/null");
}
break;
case RAVA_VAL_METHOD_REF:
if (value.data.method_ref_val) {
snprintf(buffer, 128, "%s::%s",
@ -333,6 +342,8 @@ const char* rava_object_getclass(RavaValue_t value) {
return "Socket";
case RAVA_VAL_STREAM:
return "Stream";
case RAVA_VAL_INETADDRESS:
return "InetAddress";
case RAVA_VAL_METHOD_REF:
return "MethodReference";
}

View File

@ -9,6 +9,14 @@
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <netinet/tcp.h>
#include <fcntl.h>
#ifndef NI_MAXHOST
#define NI_MAXHOST 1025
#endif
RavaSocket_t* rava_socket_create(void) {
RavaSocket_t *sock = rava_gc_alloc(sizeof(RavaSocket_t), RAVA_GC_TYPE_SOCKET);
@ -62,6 +70,8 @@ RavaSocket_t* rava_server_socket_create(int port) {
return sock;
}
sock->bound = true;
if (listen(sock->fd, 10) < 0) {
close(sock->fd);
sock->fd = -1;
@ -204,3 +214,607 @@ void rava_stream_close(RavaStream_t *stream) {
if (!stream) return;
stream->closed = true;
}
int rava_stream_read_bytes(RavaStream_t *stream, RavaArray_t *arr, int off, int len) {
if (!stream || stream->closed || stream->fd < 0) return -1;
if (stream->stream_type != RAVA_STREAM_TYPE_INPUT) return -1;
if (!arr || off < 0 || len <= 0) return -1;
if ((size_t)(off + len) > arr->length) return -1;
char *buffer = malloc(len);
if (!buffer) return -1;
ssize_t bytes_read = read(stream->fd, buffer, len);
if (bytes_read <= 0) {
free(buffer);
return -1;
}
for (ssize_t i = 0; i < bytes_read; i++) {
rava_array_set_value(arr, off + i, rava_value_int((unsigned char)buffer[i]));
}
free(buffer);
return (int)bytes_read;
}
int rava_stream_available(RavaStream_t *stream) {
if (!stream || stream->closed || stream->fd < 0) return 0;
if (stream->stream_type != RAVA_STREAM_TYPE_INPUT) return 0;
int available = 0;
if (ioctl(stream->fd, FIONREAD, &available) < 0) {
return 0;
}
return available;
}
void rava_stream_flush(RavaStream_t *stream) {
if (!stream || stream->closed || stream->fd < 0) return;
if (stream->stream_type != RAVA_STREAM_TYPE_OUTPUT) return;
fsync(stream->fd);
}
long rava_stream_skip(RavaStream_t *stream, long n) {
if (!stream || stream->closed || stream->fd < 0) return 0;
if (stream->stream_type != RAVA_STREAM_TYPE_INPUT) return 0;
if (n <= 0) return 0;
long skipped = 0;
char buffer[1024];
while (skipped < n) {
long to_read = (n - skipped > 1024) ? 1024 : (n - skipped);
ssize_t read_count = read(stream->fd, buffer, (size_t)to_read);
if (read_count <= 0) break;
skipped += read_count;
}
return skipped;
}
RavaInetAddress_t* rava_inetaddress_create(void) {
RavaInetAddress_t *addr = rava_gc_alloc(sizeof(RavaInetAddress_t), RAVA_GC_TYPE_INETADDRESS);
if (!addr) return NULL;
memset((char*)addr + sizeof(RavaGCHeader_t), 0, sizeof(RavaInetAddress_t) - sizeof(RavaGCHeader_t));
addr->address_type = RAVA_INETADDRESS_IPV4;
return addr;
}
RavaInetAddress_t* rava_inetaddress_get_by_name(const char *host) {
if (!host) return NULL;
struct addrinfo hints, *res;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
int status = getaddrinfo(host, NULL, &hints, &res);
if (status != 0) return NULL;
RavaInetAddress_t *addr = rava_inetaddress_create();
if (!addr) {
freeaddrinfo(res);
return NULL;
}
addr->hostname = strdup(host);
if (res->ai_family == AF_INET) {
addr->address_type = RAVA_INETADDRESS_IPV4;
struct sockaddr_in *ipv4 = (struct sockaddr_in*)res->ai_addr;
memcpy(addr->address, &ipv4->sin_addr, 4);
char ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &ipv4->sin_addr, ip, sizeof(ip));
addr->hostaddress = strdup(ip);
} else if (res->ai_family == AF_INET6) {
addr->address_type = RAVA_INETADDRESS_IPV6;
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6*)res->ai_addr;
memcpy(addr->address, &ipv6->sin6_addr, 16);
char ip[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &ipv6->sin6_addr, ip, sizeof(ip));
addr->hostaddress = strdup(ip);
}
freeaddrinfo(res);
return addr;
}
RavaInetAddress_t* rava_inetaddress_get_local_host(void) {
char hostname[256];
if (gethostname(hostname, sizeof(hostname)) != 0) {
return rava_inetaddress_get_loopback();
}
RavaInetAddress_t *addr = rava_inetaddress_get_by_name(hostname);
if (!addr) {
return rava_inetaddress_get_loopback();
}
return addr;
}
RavaInetAddress_t* rava_inetaddress_get_loopback(void) {
RavaInetAddress_t *addr = rava_inetaddress_create();
if (!addr) return NULL;
addr->address_type = RAVA_INETADDRESS_IPV4;
addr->address[0] = 127;
addr->address[1] = 0;
addr->address[2] = 0;
addr->address[3] = 1;
addr->hostname = strdup("localhost");
addr->hostaddress = strdup("127.0.0.1");
return addr;
}
char* rava_inetaddress_get_host_name(RavaInetAddress_t *addr) {
if (!addr) return NULL;
if (addr->hostname) return addr->hostname;
char host[NI_MAXHOST];
struct sockaddr_in sa;
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
memcpy(&sa.sin_addr, addr->address, 4);
int result = getnameinfo((struct sockaddr*)&sa, sizeof(sa), host, sizeof(host), NULL, 0, 0);
if (result == 0) {
addr->hostname = strdup(host);
return addr->hostname;
}
return addr->hostaddress;
}
char* rava_inetaddress_get_host_address(RavaInetAddress_t *addr) {
if (!addr) return NULL;
if (addr->hostaddress) return addr->hostaddress;
char ip[INET6_ADDRSTRLEN];
if (addr->address_type == RAVA_INETADDRESS_IPV4) {
inet_ntop(AF_INET, addr->address, ip, sizeof(ip));
} else {
inet_ntop(AF_INET6, addr->address, ip, sizeof(ip));
}
addr->hostaddress = strdup(ip);
return addr->hostaddress;
}
bool rava_inetaddress_is_loopback(RavaInetAddress_t *addr) {
if (!addr) return false;
if (addr->address_type == RAVA_INETADDRESS_IPV4) {
return addr->address[0] == 127;
}
static const uint8_t ipv6_loopback[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
return memcmp(addr->address, ipv6_loopback, 16) == 0;
}
bool rava_inetaddress_is_any_local(RavaInetAddress_t *addr) {
if (!addr) return false;
if (addr->address_type == RAVA_INETADDRESS_IPV4) {
return addr->address[0] == 0 && addr->address[1] == 0 &&
addr->address[2] == 0 && addr->address[3] == 0;
}
static const uint8_t ipv6_any[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
return memcmp(addr->address, ipv6_any, 16) == 0;
}
RavaArray_t* rava_inetaddress_get_all_by_name(const char *host) {
if (!host) return NULL;
struct addrinfo hints, *res, *p;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(host, NULL, &hints, &res) != 0) {
return NULL;
}
size_t count = 0;
for (p = res; p != NULL; p = p->ai_next) {
count++;
}
RavaArray_t *array = rava_gc_alloc(sizeof(RavaArray_t), RAVA_GC_TYPE_ARRAY);
if (!array) {
freeaddrinfo(res);
return NULL;
}
array->length = count;
array->element_type = RAVA_VAL_INETADDRESS;
array->data = calloc(count, sizeof(RavaValue_t));
if (!array->data && count > 0) {
freeaddrinfo(res);
return NULL;
}
RavaValue_t *values = (RavaValue_t *)array->data;
size_t i = 0;
for (p = res; p != NULL; p = p->ai_next) {
RavaInetAddress_t *addr = rava_inetaddress_create();
if (addr) {
if (p->ai_family == AF_INET) {
addr->address_type = RAVA_INETADDRESS_IPV4;
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
memcpy(addr->address, &ipv4->sin_addr, 4);
} else if (p->ai_family == AF_INET6) {
addr->address_type = RAVA_INETADDRESS_IPV6;
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
memcpy(addr->address, &ipv6->sin6_addr, 16);
}
addr->hostname = host ? strdup(host) : NULL;
values[i] = rava_value_inetaddress(addr);
}
i++;
}
freeaddrinfo(res);
return array;
}
RavaArray_t* rava_inetaddress_get_address(RavaInetAddress_t *addr) {
if (!addr) return NULL;
size_t len = (addr->address_type == RAVA_INETADDRESS_IPV4) ? 4 : 16;
RavaArray_t *array = rava_gc_alloc(sizeof(RavaArray_t), RAVA_GC_TYPE_ARRAY);
if (!array) return NULL;
array->length = len;
array->element_type = RAVA_VAL_INT;
array->data = calloc(len, sizeof(int64_t));
if (!array->data && len > 0) {
return NULL;
}
int64_t *values = (int64_t *)array->data;
for (size_t i = 0; i < len; i++) {
values[i] = addr->address[i];
}
return array;
}
bool rava_inetaddress_is_multicast_address(RavaInetAddress_t *addr) {
if (!addr) return false;
if (addr->address_type == RAVA_INETADDRESS_IPV4) {
return (addr->address[0] >= 224 && addr->address[0] <= 239);
} else {
return addr->address[0] == 0xff;
}
}
bool rava_inetaddress_is_reachable(RavaInetAddress_t *addr, int timeout) {
if (!addr) return false;
int sock = socket(addr->address_type == RAVA_INETADDRESS_IPV4 ? AF_INET : AF_INET6, SOCK_STREAM, 0);
if (sock < 0) return false;
struct timeval tv;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
fcntl(sock, F_SETFL, O_NONBLOCK);
bool result = false;
if (addr->address_type == RAVA_INETADDRESS_IPV4) {
struct sockaddr_in sa;
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(7);
memcpy(&sa.sin_addr, addr->address, 4);
int res = connect(sock, (struct sockaddr*)&sa, sizeof(sa));
if (res == 0 || (res < 0 && errno == EINPROGRESS)) {
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(sock, &fdset);
struct timeval tv2;
tv2.tv_sec = timeout / 1000;
tv2.tv_usec = (timeout % 1000) * 1000;
if (select(sock + 1, NULL, &fdset, NULL, &tv2) > 0) {
int so_error;
socklen_t len = sizeof(so_error);
getsockopt(sock, SOL_SOCKET, SO_ERROR, &so_error, &len);
result = (so_error == 0);
}
}
}
close(sock);
return result;
}
int rava_socket_get_port(RavaSocket_t *socket) {
if (!socket || socket->fd < 0) return -1;
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
if (getpeername(socket->fd, (struct sockaddr*)&addr, &len) < 0) {
return -1;
}
return ntohs(addr.sin_port);
}
int rava_socket_get_local_port(RavaSocket_t *socket) {
if (!socket || socket->fd < 0) return -1;
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
if (getsockname(socket->fd, (struct sockaddr*)&addr, &len) < 0) {
return -1;
}
return ntohs(addr.sin_port);
}
RavaInetAddress_t* rava_socket_get_inet_address(RavaSocket_t *socket) {
if (!socket || socket->fd < 0) return NULL;
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
if (getpeername(socket->fd, (struct sockaddr*)&addr, &len) < 0) {
return NULL;
}
RavaInetAddress_t *inet_addr = rava_inetaddress_create();
if (!inet_addr) return NULL;
inet_addr->address_type = RAVA_INETADDRESS_IPV4;
memcpy(inet_addr->address, &addr.sin_addr, 4);
char ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &addr.sin_addr, ip, sizeof(ip));
inet_addr->hostaddress = strdup(ip);
return inet_addr;
}
RavaInetAddress_t* rava_socket_get_local_address(RavaSocket_t *socket) {
if (!socket || socket->fd < 0) return NULL;
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
if (getsockname(socket->fd, (struct sockaddr*)&addr, &len) < 0) {
return NULL;
}
RavaInetAddress_t *inet_addr = rava_inetaddress_create();
if (!inet_addr) return NULL;
inet_addr->address_type = RAVA_INETADDRESS_IPV4;
memcpy(inet_addr->address, &addr.sin_addr, 4);
char ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &addr.sin_addr, ip, sizeof(ip));
inet_addr->hostaddress = strdup(ip);
return inet_addr;
}
int rava_server_socket_get_local_port(RavaSocket_t *socket) {
return rava_socket_get_local_port(socket);
}
bool rava_server_socket_is_bound(RavaSocket_t *socket) {
if (!socket || socket->fd < 0) return false;
return socket->bound;
}
bool rava_server_socket_is_closed(RavaSocket_t *socket) {
if (!socket) return true;
return socket->closed;
}
void rava_server_socket_set_so_timeout(RavaSocket_t *socket, int timeout) {
if (!socket || socket->fd < 0) return;
struct timeval tv;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
setsockopt(socket->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
}
int rava_server_socket_get_so_timeout(RavaSocket_t *socket) {
if (!socket || socket->fd < 0) return 0;
struct timeval tv;
socklen_t len = sizeof(tv);
if (getsockopt(socket->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, &len) < 0) {
return 0;
}
return (int)(tv.tv_sec * 1000 + tv.tv_usec / 1000);
}
void rava_server_socket_set_receive_buffer_size(RavaSocket_t *socket, int size) {
if (!socket || socket->fd < 0) return;
setsockopt(socket->fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
}
int rava_server_socket_get_receive_buffer_size(RavaSocket_t *socket) {
if (!socket || socket->fd < 0) return 0;
int size = 0;
socklen_t len = sizeof(size);
if (getsockopt(socket->fd, SOL_SOCKET, SO_RCVBUF, &size, &len) == 0) {
return size;
}
return 0;
}
void rava_server_socket_set_reuse_address(RavaSocket_t *socket, bool reuse) {
if (!socket || socket->fd < 0) return;
int val = reuse ? 1 : 0;
setsockopt(socket->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
}
bool rava_server_socket_get_reuse_address(RavaSocket_t *socket) {
if (!socket || socket->fd < 0) return false;
int val = 0;
socklen_t len = sizeof(val);
if (getsockopt(socket->fd, SOL_SOCKET, SO_REUSEADDR, &val, &len) == 0) {
return val != 0;
}
return false;
}
void rava_socket_set_so_timeout(RavaSocket_t *socket, int timeout_ms) {
if (!socket || socket->fd < 0) return;
struct timeval tv;
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = (timeout_ms % 1000) * 1000;
setsockopt(socket->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
setsockopt(socket->fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
}
int rava_socket_get_so_timeout(RavaSocket_t *socket) {
if (!socket || socket->fd < 0) return 0;
struct timeval tv;
socklen_t len = sizeof(tv);
if (getsockopt(socket->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, &len) < 0) {
return 0;
}
return (int)(tv.tv_sec * 1000 + tv.tv_usec / 1000);
}
void rava_socket_set_tcp_nodelay(RavaSocket_t *socket, bool nodelay) {
if (!socket || socket->fd < 0) return;
int flag = nodelay ? 1 : 0;
setsockopt(socket->fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag));
}
bool rava_socket_get_tcp_nodelay(RavaSocket_t *socket) {
if (!socket || socket->fd < 0) return false;
int flag = 0;
socklen_t len = sizeof(flag);
if (getsockopt(socket->fd, IPPROTO_TCP, TCP_NODELAY, &flag, &len) < 0) {
return false;
}
return flag != 0;
}
void rava_socket_bind(RavaSocket_t *socket, const char *host, int port) {
if (!socket || socket->fd < 0) return;
if (socket->bound) return;
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
if (host && strcmp(host, "0.0.0.0") != 0) {
if (inet_pton(AF_INET, host, &addr.sin_addr) <= 0) {
return;
}
} else {
addr.sin_addr.s_addr = INADDR_ANY;
}
if (bind(socket->fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) {
socket->bound = true;
}
}
bool rava_socket_is_connected(RavaSocket_t *socket) {
if (!socket) return false;
return socket->connected && !socket->closed;
}
bool rava_socket_is_closed(RavaSocket_t *socket) {
if (!socket) return true;
return socket->closed;
}
bool rava_socket_is_bound(RavaSocket_t *socket) {
if (!socket) return false;
return socket->bound;
}
void rava_socket_shutdown_input(RavaSocket_t *socket) {
if (!socket || socket->fd < 0) return;
if (socket->input_shutdown) return;
shutdown(socket->fd, SHUT_RD);
socket->input_shutdown = true;
}
void rava_socket_shutdown_output(RavaSocket_t *socket) {
if (!socket || socket->fd < 0) return;
if (socket->output_shutdown) return;
shutdown(socket->fd, SHUT_WR);
socket->output_shutdown = true;
}
bool rava_socket_is_input_shutdown(RavaSocket_t *socket) {
if (!socket) return false;
return socket->input_shutdown;
}
bool rava_socket_is_output_shutdown(RavaSocket_t *socket) {
if (!socket) return false;
return socket->output_shutdown;
}
void rava_socket_set_send_buffer_size(RavaSocket_t *socket, int size) {
if (!socket || socket->fd < 0) return;
setsockopt(socket->fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
}
int rava_socket_get_send_buffer_size(RavaSocket_t *socket) {
if (!socket || socket->fd < 0) return 0;
int size = 0;
socklen_t len = sizeof(size);
if (getsockopt(socket->fd, SOL_SOCKET, SO_SNDBUF, &size, &len) == 0) {
return size;
}
return 0;
}
void rava_socket_set_receive_buffer_size(RavaSocket_t *socket, int size) {
if (!socket || socket->fd < 0) return;
setsockopt(socket->fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
}
int rava_socket_get_receive_buffer_size(RavaSocket_t *socket) {
if (!socket || socket->fd < 0) return 0;
int size = 0;
socklen_t len = sizeof(size);
if (getsockopt(socket->fd, SOL_SOCKET, SO_RCVBUF, &size, &len) == 0) {
return size;
}
return 0;
}
void rava_socket_set_keep_alive(RavaSocket_t *socket, bool keepalive) {
if (!socket || socket->fd < 0) return;
int val = keepalive ? 1 : 0;
setsockopt(socket->fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val));
}
bool rava_socket_get_keep_alive(RavaSocket_t *socket) {
if (!socket || socket->fd < 0) return false;
int val = 0;
socklen_t len = sizeof(val);
if (getsockopt(socket->fd, SOL_SOCKET, SO_KEEPALIVE, &val, &len) == 0) {
return val != 0;
}
return false;
}
void rava_socket_set_reuse_address(RavaSocket_t *socket, bool reuse) {
if (!socket || socket->fd < 0) return;
int val = reuse ? 1 : 0;
setsockopt(socket->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
}
bool rava_socket_get_reuse_address(RavaSocket_t *socket) {
if (!socket || socket->fd < 0) return false;
int val = 0;
socklen_t len = sizeof(val);
if (getsockopt(socket->fd, SOL_SOCKET, SO_REUSEADDR, &val, &len) == 0) {
return val != 0;
}
return false;
}

127
runtime/runtime_stack.c Normal file
View File

@ -0,0 +1,127 @@
#include "runtime_internal.h"
RavaStack_t* rava_stack_create(size_t capacity) {
RavaStack_t *stack = malloc(sizeof(RavaStack_t));
if (!stack) return NULL;
stack->capacity = capacity;
stack->values = malloc(sizeof(RavaValue_t) * capacity);
if (!stack->values) {
free(stack);
return NULL;
}
stack->top = 0;
return stack;
}
void rava_stack_destroy(RavaStack_t *stack) {
if (!stack) return;
free(stack->values);
free(stack);
}
void rava_stack_push(RavaStack_t *stack, RavaValue_t value) {
if (stack->top >= stack->capacity) {
stack->capacity *= 2;
RavaValue_t *new_values = rava_safe_realloc(stack->values, sizeof(RavaValue_t) * stack->capacity);
if (!new_values) return;
stack->values = new_values;
}
stack->values[stack->top++] = value;
}
RavaValue_t rava_stack_pop(RavaStack_t *stack) {
if (stack->top == 0) {
return rava_value_int(0);
}
return stack->values[--stack->top];
}
RavaValue_t rava_stack_peek(RavaStack_t *stack) {
if (stack->top == 0) {
return rava_value_int(0);
}
return stack->values[stack->top - 1];
}
bool rava_stack_is_empty(RavaStack_t *stack) {
return stack->top == 0;
}
RavaCallFrame_t* rava_call_frame_create(RavaMethod_t *method) {
RavaCallFrame_t *frame = calloc(1, sizeof(RavaCallFrame_t));
if (!frame) return NULL;
frame->method = method;
frame->local_count = method->local_count;
frame->locals = calloc(method->local_count, sizeof(RavaValue_t));
if (!frame->locals && method->local_count > 0) {
free(frame);
return NULL;
}
frame->pc = 0;
size_t stack_size = method->max_stack > 0 ? (size_t)method->max_stack : 64;
frame->operand_stack = rava_stack_create(stack_size);
if (!frame->operand_stack) {
free(frame->locals);
free(frame);
return NULL;
}
frame->has_this = false;
frame->this_ref = rava_value_null();
return frame;
}
void rava_call_frame_destroy(RavaCallFrame_t *frame) {
if (!frame) return;
free(frame->locals);
rava_stack_destroy(frame->operand_stack);
free(frame);
}
RavaCallStack_t* rava_call_stack_create(void) {
RavaCallStack_t *stack = malloc(sizeof(RavaCallStack_t));
if (!stack) return NULL;
stack->capacity = 256;
stack->frames = malloc(sizeof(RavaCallFrame_t*) * stack->capacity);
if (!stack->frames) {
free(stack);
return NULL;
}
stack->count = 0;
return stack;
}
void rava_call_stack_destroy(RavaCallStack_t *stack) {
if (!stack) return;
for (size_t i = 0; i < stack->count; i++) {
rava_call_frame_destroy(stack->frames[i]);
}
free(stack->frames);
free(stack);
}
#define RAVA_MAX_CALL_STACK_DEPTH 10000
bool rava_call_stack_push(RavaCallStack_t *stack, RavaCallFrame_t *frame) {
if (stack->count >= RAVA_MAX_CALL_STACK_DEPTH) {
return false;
}
if (stack->count >= stack->capacity) {
stack->capacity *= 2;
RavaCallFrame_t **new_frames = rava_safe_realloc(stack->frames, sizeof(RavaCallFrame_t*) * stack->capacity);
if (!new_frames) return false;
stack->frames = new_frames;
}
stack->frames[stack->count++] = frame;
return true;
}
RavaCallFrame_t* rava_call_stack_pop(RavaCallStack_t *stack) {
if (stack->count == 0) return NULL;
RavaCallFrame_t *frame = stack->frames[--stack->count];
return frame;
}
RavaCallFrame_t* rava_call_stack_current(RavaCallStack_t *stack) {
if (stack->count == 0) return NULL;
return stack->frames[stack->count - 1];
}

85
runtime/runtime_static.c Normal file
View File

@ -0,0 +1,85 @@
#include "runtime_internal.h"
RavaStaticFieldTable_t* rava_static_field_table_create(void) {
RavaStaticFieldTable_t *table = malloc(sizeof(RavaStaticFieldTable_t));
if (!table) return NULL;
table->capacity = 16;
table->fields = calloc(table->capacity, sizeof(RavaStaticField_t));
if (!table->fields) {
free(table);
return NULL;
}
table->count = 0;
for (int i = 0; i < RAVA_STATIC_HASH_SIZE; i++) {
table->hash_table[i] = -1;
}
return table;
}
void rava_static_field_table_destroy(RavaStaticFieldTable_t *table) {
if (!table) return;
for (size_t i = 0; i < table->count; i++) {
free(table->fields[i].class_name);
free(table->fields[i].field_name);
}
free(table->fields);
free(table);
}
RavaValue_t* rava_static_field_table_get(RavaStaticFieldTable_t *table,
const char *class_name,
const char *field_name) {
uint32_t hash = _rava_static_hash(class_name, field_name);
for (size_t probe = 0; probe < RAVA_STATIC_HASH_SIZE; probe++) {
uint32_t slot = (hash + probe) & (RAVA_STATIC_HASH_SIZE - 1);
int idx = table->hash_table[slot];
if (idx == -1) {
return NULL;
}
if ((size_t)idx < table->count &&
strcmp(table->fields[idx].class_name, class_name) == 0 &&
strcmp(table->fields[idx].field_name, field_name) == 0) {
return &table->fields[idx].value;
}
}
return NULL;
}
void rava_static_field_table_set(RavaStaticFieldTable_t *table,
const char *class_name,
const char *field_name,
RavaValue_t value) {
uint32_t hash = _rava_static_hash(class_name, field_name);
for (size_t probe = 0; probe < RAVA_STATIC_HASH_SIZE; probe++) {
uint32_t slot = (hash + probe) & (RAVA_STATIC_HASH_SIZE - 1);
int idx = table->hash_table[slot];
if (idx == -1) {
if (table->count >= table->capacity) {
size_t new_cap = table->capacity * 2;
RavaStaticField_t *new_fields = rava_safe_realloc(table->fields, sizeof(RavaStaticField_t) * new_cap);
if (!new_fields) return;
table->fields = new_fields;
table->capacity = new_cap;
}
table->fields[table->count].class_name = strdup(class_name);
table->fields[table->count].field_name = strdup(field_name);
table->fields[table->count].value = value;
table->hash_table[slot] = (int)table->count;
table->count++;
return;
}
if ((size_t)idx < table->count &&
strcmp(table->fields[idx].class_name, class_name) == 0 &&
strcmp(table->fields[idx].field_name, field_name) == 0) {
table->fields[idx].value = value;
return;
}
}
}

97
runtime/runtime_value.c Normal file
View File

@ -0,0 +1,97 @@
#include "runtime_internal.h"
RavaValue_t rava_value_string(const char *str) {
RavaValue_t val;
val.type = RAVA_VAL_STRING;
val.data.string_val = str ? strdup(str) : NULL;
return val;
}
const char* rava_value_as_string(RavaValue_t value) {
if (value.type == RAVA_VAL_STRING) {
return value.data.string_val ? value.data.string_val : "";
}
return "";
}
char* _rava_get_string_buffer(RavaVM_t *vm, size_t needed) {
if (needed >= RAVA_STRING_BUFFER_SIZE) {
return malloc(needed);
}
char *buf = vm->string_pool.buffers[vm->string_pool.current];
vm->string_pool.current = (vm->string_pool.current + 1) % RAVA_STRING_BUFFER_COUNT;
return buf;
}
void _rava_object_set_field_vm(RavaObject_t *obj, const char *name, RavaValue_t value, RavaVM_t *vm) {
if (!obj || !name) return;
uint32_t hash = _rava_field_hash(name);
for (size_t probe = 0; probe < RAVA_OBJECT_HASH_SIZE; probe++) {
uint32_t idx = (hash + probe) & (RAVA_OBJECT_HASH_SIZE - 1);
int field_idx = obj->field_hash[idx];
if (field_idx == -1) {
if (obj->field_count >= obj->field_capacity) {
size_t new_cap = obj->field_capacity * 2;
char **new_names = rava_safe_realloc(obj->field_names, new_cap * sizeof(char*));
RavaValue_t *new_values = rava_safe_realloc(obj->field_values, new_cap * sizeof(RavaValue_t));
if (!new_names || !new_values) return;
obj->field_names = new_names;
obj->field_values = new_values;
obj->field_capacity = new_cap;
}
obj->field_names[obj->field_count] = (char*)(vm ? _rava_intern_string(vm, name) : strdup(name));
obj->field_values[obj->field_count] = value;
obj->field_hash[idx] = (int)obj->field_count;
obj->field_count++;
return;
}
if ((size_t)field_idx < obj->field_count &&
strcmp(obj->field_names[field_idx], name) == 0) {
obj->field_values[field_idx] = value;
return;
}
}
}
int64_t rava_value_as_int(RavaValue_t value) {
switch (value.type) {
case RAVA_VAL_INT: return value.data.int_val;
case RAVA_VAL_LONG: return value.data.long_val;
case RAVA_VAL_FLOAT: return (int64_t)value.data.float_val;
case RAVA_VAL_DOUBLE: return (int64_t)value.data.double_val;
case RAVA_VAL_BOOLEAN: return value.data.bool_val ? 1 : 0;
case RAVA_VAL_CHAR: return value.data.char_val;
default: return 0;
}
}
int64_t rava_value_as_long(RavaValue_t value) {
switch (value.type) {
case RAVA_VAL_INT: return value.data.int_val;
case RAVA_VAL_LONG: return value.data.long_val;
case RAVA_VAL_FLOAT: return (int64_t)value.data.float_val;
case RAVA_VAL_DOUBLE: return (int64_t)value.data.double_val;
default: return 0;
}
}
double rava_value_as_double(RavaValue_t value) {
switch (value.type) {
case RAVA_VAL_INT: return value.data.int_val;
case RAVA_VAL_LONG: return (double)value.data.long_val;
case RAVA_VAL_FLOAT: return value.data.float_val;
case RAVA_VAL_DOUBLE: return value.data.double_val;
default: return 0.0;
}
}
bool rava_value_as_boolean(RavaValue_t value) {
if (value.type == RAVA_VAL_BOOLEAN) {
return value.data.bool_val;
}
return rava_value_as_int(value) != 0;
}

View File

@ -270,6 +270,9 @@ static RavaType_t* _rava_semantic_check_expression(RavaSemanticAnalyzer_t *analy
if (strcmp(name, "Math") == 0) {
return rava_type_from_name("Math");
}
if (strcmp(name, "InetAddress") == 0) {
return rava_type_from_name("InetAddress");
}
RavaSymbol_t *symbol = rava_symbol_table_resolve(analyzer->symbol_table, name);
if (!symbol) {
@ -328,6 +331,14 @@ static RavaType_t* _rava_semantic_check_expression(RavaSemanticAnalyzer_t *analy
for (size_t i = 0; i < expr->data.call.arguments_count; i++) {
_rava_semantic_check_expression(analyzer, expr->data.call.arguments[i]);
}
if (expr->data.call.callee->type == RAVA_AST_IDENTIFIER_EXPR) {
const char *func_name = expr->data.call.callee->data.identifier.name;
if (strcmp(func_name, "readLine") == 0) {
return rava_type_create_class("String");
} else if (strcmp(func_name, "sendResponse") == 0 || strcmp(func_name, "handleRequest") == 0) {
return rava_type_create_primitive(RAVA_TYPE_VOID);
}
}
if (expr->data.call.callee->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
RavaASTNode_t *member = expr->data.call.callee;
const char *method = member->data.member_access.member;
@ -360,13 +371,60 @@ static RavaType_t* _rava_semantic_check_expression(RavaSemanticAnalyzer_t *analy
return rava_type_create_primitive(RAVA_TYPE_DOUBLE);
}
}
if (member->data.member_access.object->type == RAVA_AST_IDENTIFIER_EXPR &&
strcmp(member->data.member_access.object->data.identifier.name, "InetAddress") == 0) {
if (strcmp(method, "getByName") == 0 || strcmp(method, "getLocalHost") == 0 ||
strcmp(method, "getLoopbackAddress") == 0) {
return rava_type_create_class("InetAddress");
}
}
if (strcmp(method, "getHostName") == 0 || strcmp(method, "getHostAddress") == 0) {
return rava_type_create_class("String");
}
if (strcmp(method, "isLoopbackAddress") == 0 || strcmp(method, "isAnyLocalAddress") == 0) {
return rava_type_create_primitive(RAVA_TYPE_BOOLEAN);
}
if (strcmp(method, "getLocalPort") == 0 || strcmp(method, "getPort") == 0) {
return rava_type_create_primitive(RAVA_TYPE_INT);
}
if (strcmp(method, "isBound") == 0 || strcmp(method, "isClosed") == 0) {
return rava_type_create_primitive(RAVA_TYPE_BOOLEAN);
}
if (strcmp(method, "getInetAddress") == 0 || strcmp(method, "getLocalAddress") == 0) {
return rava_type_create_class("InetAddress");
}
if (strcmp(method, "accept") == 0) {
return rava_type_create_class("Socket");
}
if (strcmp(method, "getInputStream") == 0) {
return rava_type_create_class("InputStream");
}
if (strcmp(method, "getOutputStream") == 0) {
return rava_type_create_class("OutputStream");
}
if (strcmp(method, "getSoTimeout") == 0 || strcmp(method, "getReceiveBufferSize") == 0 ||
strcmp(method, "getSendBufferSize") == 0) {
return rava_type_create_primitive(RAVA_TYPE_INT);
}
if (strcmp(method, "getTcpNoDelay") == 0 || strcmp(method, "getKeepAlive") == 0 ||
strcmp(method, "getReuseAddress") == 0 || strcmp(method, "isConnected") == 0 ||
strcmp(method, "isMulticastAddress") == 0 || strcmp(method, "isReachable") == 0) {
return rava_type_create_primitive(RAVA_TYPE_BOOLEAN);
}
if (strcmp(method, "read") == 0 || strcmp(method, "skip") == 0) {
return rava_type_create_primitive(RAVA_TYPE_INT);
}
if (strcmp(method, "length") == 0) {
return rava_type_create_primitive(RAVA_TYPE_INT);
} else if (strcmp(method, "charAt") == 0) {
return rava_type_create_primitive(RAVA_TYPE_CHAR);
} else if (strcmp(method, "equals") == 0) {
} else if (strcmp(method, "substring") == 0 || strcmp(method, "toLowerCase") == 0 ||
strcmp(method, "toUpperCase") == 0 || strcmp(method, "trim") == 0) {
return rava_type_create_class("String");
} else if (strcmp(method, "equals") == 0 || strcmp(method, "contains") == 0 ||
strcmp(method, "startsWith") == 0 || strcmp(method, "endsWith") == 0) {
return rava_type_create_primitive(RAVA_TYPE_BOOLEAN);
} else if (strcmp(method, "compareTo") == 0) {
} else if (strcmp(method, "compareTo") == 0 || strcmp(method, "indexOf") == 0) {
return rava_type_create_primitive(RAVA_TYPE_INT);
} else if (strcmp(method, "size") == 0) {
return rava_type_create_primitive(RAVA_TYPE_INT);

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -34,6 +34,320 @@ UnittestTestResult_t* test_socket_create_multiple(void) {
UNITTEST_END_TEST();
}
UnittestTestResult_t* test_inetaddress_loopback(void) {
UNITTEST_BEGIN_TEST("TestSockets", "test_inetaddress_loopback");
RAVA_TEST_RUN(_unittest_result,
"public class Test {\n"
" public static int main() {\n"
" InetAddress addr = InetAddress.getLoopbackAddress();\n"
" System.out.println(addr.getHostAddress());\n"
" return 1;\n"
" }\n"
"}\n",
"Test", "main", 1, "Loopback address should have IP address");
UNITTEST_END_TEST();
}
UnittestTestResult_t* test_inetaddress_localhost(void) {
UNITTEST_BEGIN_TEST("TestSockets", "test_inetaddress_localhost");
RAVA_TEST_RUN(_unittest_result,
"public class Test {\n"
" public static int main() {\n"
" InetAddress addr = InetAddress.getLocalHost();\n"
" System.out.println(addr.getHostAddress());\n"
" return 1;\n"
" }\n"
"}\n",
"Test", "main", 1, "Local host should have an IP address");
UNITTEST_END_TEST();
}
UnittestTestResult_t* test_inetaddress_getbyname(void) {
UNITTEST_BEGIN_TEST("TestSockets", "test_inetaddress_getbyname");
RAVA_TEST_RUN(_unittest_result,
"public class Test {\n"
" public static int main() {\n"
" InetAddress addr = InetAddress.getByName(\"localhost\");\n"
" System.out.println(addr.getHostAddress());\n"
" return 1;\n"
" }\n"
"}\n",
"Test", "main", 1, "localhost should resolve to IP");
UNITTEST_END_TEST();
}
UnittestTestResult_t* test_server_socket_local_port(void) {
UNITTEST_BEGIN_TEST("TestSockets", "test_server_socket_local_port");
RAVA_TEST_RUN(_unittest_result,
"public class Test {\n"
" public static int main() {\n"
" ServerSocket server = new ServerSocket(9995);\n"
" int port = server.getLocalPort();\n"
" server.close();\n"
" return port;\n"
" }\n"
"}\n",
"Test", "main", 9995, "ServerSocket should report correct local port");
UNITTEST_END_TEST();
}
UnittestTestResult_t* test_socket_bind(void) {
UNITTEST_BEGIN_TEST("TestSockets", "test_socket_bind");
RAVA_TEST_RUN(_unittest_result,
"public class Test {\n"
" public static int main() {\n"
" Socket sock = new Socket();\n"
" sock.bind(\"127.0.0.1\", 9994);\n"
" int result = sock.isBound() ? 1 : 0;\n"
" sock.close();\n"
" return result;\n"
" }\n"
"}\n",
"Test", "main", 1, "Socket should be bound after bind()");
UNITTEST_END_TEST();
}
UnittestTestResult_t* test_socket_is_connected(void) {
UNITTEST_BEGIN_TEST("TestSockets", "test_socket_is_connected");
RAVA_TEST_RUN(_unittest_result,
"public class Test {\n"
" public static int main() {\n"
" ServerSocket server = new ServerSocket(9993);\n"
" Socket client = new Socket();\n"
" int before = client.isConnected() ? 1 : 0;\n"
" InetAddress addr = InetAddress.getLoopbackAddress();\n"
" client.connect(addr, 9993);\n"
" int after = client.isConnected() ? 1 : 0;\n"
" client.close();\n"
" server.close();\n"
" return before * 10 + after;\n"
" }\n"
"}\n",
"Test", "main", 1, "Socket should report connected state");
UNITTEST_END_TEST();
}
UnittestTestResult_t* test_socket_is_closed(void) {
UNITTEST_BEGIN_TEST("TestSockets", "test_socket_is_closed");
RAVA_TEST_RUN(_unittest_result,
"public class Test {\n"
" public static int main() {\n"
" Socket sock = new Socket();\n"
" int before = sock.isClosed() ? 1 : 0;\n"
" sock.close();\n"
" int after = sock.isClosed() ? 1 : 0;\n"
" return before * 10 + after;\n"
" }\n"
"}\n",
"Test", "main", 1, "Socket should report closed state");
UNITTEST_END_TEST();
}
UnittestTestResult_t* test_socket_shutdown_input(void) {
UNITTEST_BEGIN_TEST("TestSockets", "test_socket_shutdown_input");
RAVA_TEST_RUN(_unittest_result,
"public class Test {\n"
" public static int main() {\n"
" ServerSocket server = new ServerSocket(9992);\n"
" Socket client = new Socket();\n"
" InetAddress addr = InetAddress.getLoopbackAddress();\n"
" client.connect(addr, 9992);\n"
" int before = client.isInputShutdown() ? 1 : 0;\n"
" client.shutdownInput();\n"
" int after = client.isInputShutdown() ? 1 : 0;\n"
" client.close();\n"
" server.close();\n"
" return before * 10 + after;\n"
" }\n"
"}\n",
"Test", "main", 1, "Socket should report input shutdown state");
UNITTEST_END_TEST();
}
UnittestTestResult_t* test_socket_shutdown_output(void) {
UNITTEST_BEGIN_TEST("TestSockets", "test_socket_shutdown_output");
RAVA_TEST_RUN(_unittest_result,
"public class Test {\n"
" public static int main() {\n"
" ServerSocket server = new ServerSocket(9991);\n"
" Socket client = new Socket();\n"
" InetAddress addr = InetAddress.getLoopbackAddress();\n"
" client.connect(addr, 9991);\n"
" int before = client.isOutputShutdown() ? 1 : 0;\n"
" client.shutdownOutput();\n"
" int after = client.isOutputShutdown() ? 1 : 0;\n"
" client.close();\n"
" server.close();\n"
" return before * 10 + after;\n"
" }\n"
"}\n",
"Test", "main", 1, "Socket should report output shutdown state");
UNITTEST_END_TEST();
}
UnittestTestResult_t* test_socket_is_bound(void) {
UNITTEST_BEGIN_TEST("TestSockets", "test_socket_is_bound");
RAVA_TEST_RUN(_unittest_result,
"public class Test {\n"
" public static int main() {\n"
" ServerSocket server = new ServerSocket(9990);\n"
" int result = server.isBound() ? 1 : 0;\n"
" server.close();\n"
" return result;\n"
" }\n"
"}\n",
"Test", "main", 1, "ServerSocket should be bound after creation");
UNITTEST_END_TEST();
}
UnittestTestResult_t* test_socket_buffer_sizes(void) {
UNITTEST_BEGIN_TEST("TestSockets", "test_socket_buffer_sizes");
RAVA_TEST_RUN(_unittest_result,
"public class Test {\n"
" public static int main() {\n"
" Socket sock = new Socket();\n"
" sock.setSendBufferSize(16384);\n"
" sock.setReceiveBufferSize(16384);\n"
" int sendSize = sock.getSendBufferSize();\n"
" int recvSize = sock.getReceiveBufferSize();\n"
" sock.close();\n"
" return (sendSize > 0 && recvSize > 0) ? 1 : 0;\n"
" }\n"
"}\n",
"Test", "main", 1, "Socket buffer sizes should be retrievable");
UNITTEST_END_TEST();
}
UnittestTestResult_t* test_socket_keep_alive_reuse_address(void) {
UNITTEST_BEGIN_TEST("TestSockets", "test_socket_keep_alive_reuse_address");
RAVA_TEST_RUN(_unittest_result,
"public class Test {\n"
" public static int main() {\n"
" Socket sock = new Socket();\n"
" sock.setKeepAlive(true);\n"
" int keepAlive = sock.getKeepAlive() ? 1 : 0;\n"
" sock.setKeepAlive(false);\n"
" int keepAlive2 = sock.getKeepAlive() ? 1 : 0;\n"
" sock.setReuseAddress(true);\n"
" int reuse = sock.getReuseAddress() ? 1 : 0;\n"
" sock.setReuseAddress(false);\n"
" int reuse2 = sock.getReuseAddress() ? 1 : 0;\n"
" sock.close();\n"
" return (keepAlive == 1 && keepAlive2 == 0 && reuse == 1 && reuse2 == 0) ? 1 : 0;\n"
" }\n"
"}\n",
"Test", "main", 1, "Socket KeepAlive and ReuseAddress options should work");
UNITTEST_END_TEST();
}
UnittestTestResult_t* test_inetaddress_get_address(void) {
UNITTEST_BEGIN_TEST("TestSockets", "test_inetaddress_get_address");
RAVA_TEST_RUN(_unittest_result,
"public class Test {\n"
" public static int main() {\n"
" InetAddress addr = InetAddress.getByName(\"127.0.0.1\");\n"
" addr.getAddress();\n"
" return 1;\n"
" }\n"
"}\n",
"Test", "main", 1, "InetAddress.getAddress() should execute");
UNITTEST_END_TEST();
}
UnittestTestResult_t* test_inetaddress_is_multicast(void) {
UNITTEST_BEGIN_TEST("TestSockets", "test_inetaddress_is_multicast");
RAVA_TEST_RUN(_unittest_result,
"public class Test {\n"
" public static int main() {\n"
" InetAddress addr = InetAddress.getByName(\"127.0.0.1\");\n"
" int multicast = addr.isMulticastAddress() ? 1 : 0;\n"
" return (multicast == 0) ? 1 : 0;\n"
" }\n"
"}\n",
"Test", "main", 1, "InetAddress.isMulticastAddress() should return false for loopback");
UNITTEST_END_TEST();
}
UnittestTestResult_t* test_inetaddress_is_reachable(void) {
UNITTEST_BEGIN_TEST("TestSockets", "test_inetaddress_is_reachable");
RAVA_TEST_RUN(_unittest_result,
"public class Test {\n"
" public static int main() {\n"
" InetAddress addr = InetAddress.getByName(\"127.0.0.1\");\n"
" int reachable = addr.isReachable(1000) ? 1 : 0;\n"
" return 1;\n"
" }\n"
"}\n",
"Test", "main", 1, "InetAddress.isReachable() should execute without error");
UNITTEST_END_TEST();
}
UnittestTestResult_t* test_inetaddress_get_all_by_name(void) {
UNITTEST_BEGIN_TEST("TestSockets", "test_inetaddress_get_all_by_name");
RAVA_TEST_RUN(_unittest_result,
"public class Test {\n"
" public static int main() {\n"
" InetAddress.getAllByName(\"localhost\");\n"
" return 1;\n"
" }\n"
"}\n",
"Test", "main", 1, "InetAddress.getAllByName() should execute");
UNITTEST_END_TEST();
}
UnittestTestResult_t* test_server_socket_options(void) {
UNITTEST_BEGIN_TEST("TestSockets", "test_server_socket_options");
RAVA_TEST_RUN(_unittest_result,
"public class Test {\n"
" public static int main() {\n"
" ServerSocket server = new ServerSocket(0);\n"
" server.setReceiveBufferSize(16384);\n"
" int bufSize = server.getReceiveBufferSize();\n"
" server.setReuseAddress(true);\n"
" int reuse = server.getReuseAddress() ? 1 : 0;\n"
" server.setReuseAddress(false);\n"
" int reuse2 = server.getReuseAddress() ? 1 : 0;\n"
" return (bufSize > 0 && reuse == 1 && reuse2 == 0) ? 1 : 0;\n"
" }\n"
"}\n",
"Test", "main", 1, "ServerSocket buffer and reuse address options should work");
UNITTEST_END_TEST();
}
int main(int argc, char **argv) {
UnittestConfig_t *config = unittest_config_create();
config->verbosity = 2;
@ -48,6 +362,23 @@ int main(int argc, char **argv) {
UnittestTestCase_t *tc = unittest_test_case_create("TestSockets");
unittest_test_case_add_result(tc, test_socket_create_server());
unittest_test_case_add_result(tc, test_socket_create_multiple());
unittest_test_case_add_result(tc, test_inetaddress_loopback());
unittest_test_case_add_result(tc, test_inetaddress_localhost());
unittest_test_case_add_result(tc, test_inetaddress_getbyname());
unittest_test_case_add_result(tc, test_server_socket_local_port());
unittest_test_case_add_result(tc, test_socket_bind());
unittest_test_case_add_result(tc, test_socket_is_connected());
unittest_test_case_add_result(tc, test_socket_is_closed());
unittest_test_case_add_result(tc, test_socket_shutdown_input());
unittest_test_case_add_result(tc, test_socket_shutdown_output());
unittest_test_case_add_result(tc, test_socket_is_bound());
unittest_test_case_add_result(tc, test_socket_buffer_sizes());
unittest_test_case_add_result(tc, test_socket_keep_alive_reuse_address());
unittest_test_case_add_result(tc, test_inetaddress_get_address());
unittest_test_case_add_result(tc, test_inetaddress_is_multicast());
unittest_test_case_add_result(tc, test_inetaddress_is_reachable());
unittest_test_case_add_result(tc, test_inetaddress_get_all_by_name());
unittest_test_case_add_result(tc, test_server_socket_options());
unittest_test_suite_add_test_case(suite, tc);
unittest_generate_report(suite, config);

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.