Initial commit of dem beast./plot.py

This commit is contained in:
retoor 2025-12-02 06:54:32 +01:00
commit c9cf356cbd
58 changed files with 9092 additions and 0 deletions

157
Makefile Normal file
View File

@ -0,0 +1,157 @@
CC = gcc
CFLAGS = -Wall -Wextra -Werror -std=gnu99 -O3 -march=native -I.
LDFLAGS = -ldl
LEXER_SOURCES = lexer/lexer_tokenizer.c lexer/lexer_keywords.c lexer/lexer_literals.c
LEXER_OBJECTS = $(LEXER_SOURCES:.c=.o)
PARSER_SOURCES = parser/parser.c parser/parser_expressions.c parser/parser_statements.c parser/parser_declarations.c parser/parser_printer.c
PARSER_OBJECTS = $(PARSER_SOURCES:.c=.o)
TYPES_SOURCES = types/types.c
TYPES_OBJECTS = $(TYPES_SOURCES:.c=.o)
SEMANTIC_SOURCES = semantic/symbol_table.c semantic/semantic.c
SEMANTIC_OBJECTS = $(SEMANTIC_SOURCES:.c=.o)
IR_SOURCES = ir/ir.c ir/ir_gen.c
IR_OBJECTS = $(IR_SOURCES:.c=.o)
RUNTIME_SOURCES = runtime/runtime.c runtime/labeltable.c runtime/methodcache.c runtime/fastframe.c runtime/superinst.c
RUNTIME_OBJECTS = $(RUNTIME_SOURCES:.c=.o)
PHASE0_SOURCES = runtime/fastframe.c runtime/labeltable.c runtime/methodcache.c
PHASE0_OBJECTS = $(PHASE0_SOURCES:.c=.o)
TEST_LEXER_SOURCES = tests/test_lexer.c
TEST_LEXER_OBJECTS = $(TEST_LEXER_SOURCES:.c=.o)
TEST_PARSER_SOURCES = tests/test_parser.c
TEST_PARSER_OBJECTS = $(TEST_PARSER_SOURCES:.c=.o)
TEST_SEMANTIC_SOURCES = tests/test_semantic.c
TEST_SEMANTIC_OBJECTS = $(TEST_SEMANTIC_SOURCES:.c=.o)
TEST_IR_SOURCES = tests/test_ir.c
TEST_IR_OBJECTS = $(TEST_IR_SOURCES:.c=.o)
TEST_RUNTIME_SOURCES = tests/test_runtime.c
TEST_RUNTIME_OBJECTS = $(TEST_RUNTIME_SOURCES:.c=.o)
TEST_STRINGS_SOURCES = tests/test_strings.c
TEST_STRINGS_OBJECTS = $(TEST_STRINGS_SOURCES:.c=.o)
TEST_ARRAYS_SOURCES = tests/test_arrays.c
TEST_ARRAYS_OBJECTS = $(TEST_ARRAYS_SOURCES:.c=.o)
TEST_OBJECTS_SOURCES = tests/test_objects.c
TEST_OBJECTS_OBJECTS = $(TEST_OBJECTS_SOURCES:.c=.o)
TEST_INSTANCE_SOURCES = tests/test_instance_methods.c
TEST_INSTANCE_OBJECTS = $(TEST_INSTANCE_SOURCES:.c=.o)
TEST_FILEIO_SOURCES = tests/test_fileio.c
TEST_FILEIO_OBJECTS = $(TEST_FILEIO_SOURCES:.c=.o)
all: test_lexer test_parser test_semantic test_ir test_runtime test_strings test_arrays test_objects test_instance_methods test_fileio
test_lexer: $(LEXER_OBJECTS) $(TEST_LEXER_OBJECTS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
test_parser: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TEST_PARSER_OBJECTS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
test_semantic: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(TEST_SEMANTIC_OBJECTS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
test_ir: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) runtime/labeltable.o $(TEST_IR_OBJECTS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
test_runtime: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_RUNTIME_OBJECTS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
test_strings: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_STRINGS_OBJECTS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
test_arrays: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_ARRAYS_OBJECTS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
test_objects: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_OBJECTS_OBJECTS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
test_instance_methods: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_INSTANCE_OBJECTS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
test_fileio: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_FILEIO_OBJECTS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
TEST_BENCHMARK_SOURCES = tests/test_benchmark.c
TEST_BENCHMARK_OBJECTS = $(TEST_BENCHMARK_SOURCES:.c=.o)
test_benchmark: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_BENCHMARK_OBJECTS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
benchmark: test_benchmark
@echo ""
@echo "========================================"
@echo " RAVA INTERPRETER"
@echo "========================================"
@./test_benchmark
@echo ""
@echo "========================================"
@echo " PYTHON 3"
@echo "========================================"
@python3 examples/benchmark.py
@echo ""
test_nanbox: tests/test_nanbox.c runtime/nanbox.h
$(CC) $(CFLAGS) -o $@ tests/test_nanbox.c $(LDFLAGS)
test_fastframe: tests/test_fastframe.c runtime/fastframe.c runtime/nanbox.h runtime/fastframe.h
$(CC) $(CFLAGS) -o $@ tests/test_fastframe.c runtime/fastframe.c $(LDFLAGS)
test_labeltable: tests/test_labeltable.c runtime/labeltable.c $(IR_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS)
$(CC) $(CFLAGS) -o $@ tests/test_labeltable.c runtime/labeltable.c $(IR_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(LDFLAGS)
test_methodcache: tests/test_methodcache.c runtime/methodcache.c runtime/methodcache.h
$(CC) $(CFLAGS) -o $@ tests/test_methodcache.c runtime/methodcache.c $(LDFLAGS)
test_phase0: test_nanbox test_fastframe test_labeltable test_methodcache
@echo "=== Running Phase 0 Tests ==="
@./test_nanbox
@./test_fastframe
@./test_labeltable
@./test_methodcache
@echo "=== All Phase 0 Tests Passed ==="
ALL_SOURCES = $(LEXER_SOURCES) $(PARSER_SOURCES) $(TYPES_SOURCES) $(SEMANTIC_SOURCES) $(IR_SOURCES) $(RUNTIME_SOURCES) $(TEST_BENCHMARK_SOURCES)
test_benchmark_pgo_gen:
rm -f *.gcda */*.gcda
$(CC) -Wall -Wextra -std=gnu99 -O3 -march=native -I. -fprofile-generate -o test_benchmark_pgo $(ALL_SOURCES) $(LDFLAGS)
pgo_run: test_benchmark_pgo_gen
./test_benchmark_pgo
./test_benchmark_pgo
./test_benchmark_pgo
test_benchmark_pgo: pgo_run
$(CC) -Wall -Wextra -std=gnu99 -O3 -march=native -I. -fprofile-use -fprofile-correction -o test_benchmark_pgo $(ALL_SOURCES) $(LDFLAGS)
pgo: test_benchmark_pgo
@echo "=== PGO Benchmark ==="
./test_benchmark_pgo
clean:
rm -f $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) \
$(PHASE0_OBJECTS) \
$(TEST_LEXER_OBJECTS) $(TEST_PARSER_OBJECTS) $(TEST_SEMANTIC_OBJECTS) $(TEST_IR_OBJECTS) $(TEST_RUNTIME_OBJECTS) \
$(TEST_STRINGS_OBJECTS) $(TEST_ARRAYS_OBJECTS) $(TEST_OBJECTS_OBJECTS) $(TEST_INSTANCE_OBJECTS) $(TEST_FILEIO_OBJECTS) \
$(TEST_BENCHMARK_OBJECTS) \
test_lexer test_parser test_semantic test_ir test_runtime test_strings test_arrays test_objects test_instance_methods test_fileio test_benchmark \
test_nanbox test_fastframe test_labeltable test_methodcache test_benchmark_pgo *.gcda */*.gcda
.PHONY: all clean benchmark test_phase0 pgo test_benchmark_pgo_gen pgo_run test_benchmark_pgo

View File

@ -0,0 +1,23 @@
public class Fibonacci {
public static int fib(int n) {
if (n <= 1) {
return n;
}
return fib(n - 1) + fib(n - 2);
}
public static int main() {
System.out.println(fib(0));
System.out.println(fib(1));
System.out.println(fib(2));
System.out.println(fib(3));
System.out.println(fib(4));
System.out.println(fib(5));
System.out.println(fib(6));
System.out.println(fib(7));
System.out.println(fib(8));
System.out.println(fib(9));
System.out.println(fib(10));
return 0;
}
}

View File

@ -0,0 +1,31 @@
public class PrimeNumbers {
public static int isPrime(int n) {
if (n <= 1) {
return 0;
}
if (n <= 3) {
return 1;
}
int i = 2;
while (i * i <= n) {
if (n - (n / i) * i == 0) {
return 0;
}
i = i + 1;
}
return 1;
}
public static int main() {
int count = 0;
int num = 2;
while (count < 20) {
if (isPrime(num) == 1) {
System.out.println(num);
count = count + 1;
}
num = num + 1;
}
return 0;
}
}

View File

@ -0,0 +1,28 @@
public class FactorialVariations {
public static int factorialRecursive(int n) {
if (n <= 1) {
return 1;
}
return n * factorialRecursive(n - 1);
}
public static int factorialIterative(int n) {
int result = 1;
int i = 1;
while (i <= n) {
result = result * i;
i = i + 1;
}
return result;
}
public static int main() {
System.out.println(factorialRecursive(5));
System.out.println(factorialIterative(5));
System.out.println(factorialRecursive(7));
System.out.println(factorialIterative(7));
System.out.println(factorialRecursive(10));
System.out.println(factorialIterative(10));
return 0;
}
}

25
examples/04_GCD_LCM.java Normal file
View File

@ -0,0 +1,25 @@
public class GCD_LCM {
public static int gcd(int a, int b) {
while (b != 0) {
int temp = b;
b = a - (a / b) * b;
a = temp;
}
return a;
}
public static int lcm(int a, int b) {
return (a * b) / gcd(a, b);
}
public static int main() {
System.out.println(gcd(48, 18));
System.out.println(gcd(100, 75));
System.out.println(gcd(17, 19));
System.out.println(lcm(12, 18));
System.out.println(lcm(15, 25));
System.out.println(lcm(7, 13));
return 0;
}
}

View File

@ -0,0 +1,26 @@
public class PowerFunction {
public static int power(int base, int exp) {
if (exp == 0) {
return 1;
}
if (exp == 1) {
return base;
}
int half = power(base, exp / 2);
if (exp - (exp / 2) * 2 == 0) {
return half * half;
}
return base * half * half;
}
public static int main() {
System.out.println(power(2, 0));
System.out.println(power(2, 1));
System.out.println(power(2, 3));
System.out.println(power(2, 5));
System.out.println(power(2, 10));
System.out.println(power(3, 4));
System.out.println(power(5, 3));
return 0;
}
}

View File

@ -0,0 +1,55 @@
public class ArrayOperations {
public static int sumArray(int[] arr) {
int sum = 0;
int i = 0;
while (i < arr.length) {
sum = sum + arr[i];
i = i + 1;
}
return sum;
}
public static int findMax(int[] arr) {
if (arr.length == 0) {
return 0;
}
int max = arr[0];
int i = 1;
while (i < arr.length) {
if (arr[i] > max) {
max = arr[i];
}
i = i + 1;
}
return max;
}
public static int main() {
int[] numbers = new int[5];
numbers[0] = 10;
numbers[1] = 25;
numbers[2] = 15;
numbers[3] = 30;
numbers[4] = 20;
System.out.println(sumArray(numbers));
System.out.println(findMax(numbers));
int[] fibonacci = new int[10];
fibonacci[0] = 0;
fibonacci[1] = 1;
int i = 2;
while (i < 10) {
fibonacci[i] = fibonacci[i - 1] + fibonacci[i - 2];
i = i + 1;
}
i = 0;
while (i < 10) {
System.out.println(fibonacci[i]);
i = i + 1;
}
return 0;
}
}

View File

@ -0,0 +1,64 @@
public class BubbleSort {
public static int main() {
int n0 = 64;
int n1 = 34;
int n2 = 25;
int n3 = 12;
int n4 = 22;
int n5 = 11;
int n6 = 90;
int swapped = 1;
int temp = 0;
while (swapped == 1) {
swapped = 0;
if (n0 > n1) {
temp = n0;
n0 = n1;
n1 = temp;
swapped = 1;
}
if (n1 > n2) {
temp = n1;
n1 = n2;
n2 = temp;
swapped = 1;
}
if (n2 > n3) {
temp = n2;
n2 = n3;
n3 = temp;
swapped = 1;
}
if (n3 > n4) {
temp = n3;
n3 = n4;
n4 = temp;
swapped = 1;
}
if (n4 > n5) {
temp = n4;
n4 = n5;
n5 = temp;
swapped = 1;
}
if (n5 > n6) {
temp = n5;
n5 = n6;
n6 = temp;
swapped = 1;
}
}
System.out.println(n0);
System.out.println(n1);
System.out.println(n2);
System.out.println(n3);
System.out.println(n4);
System.out.println(n5);
System.out.println(n6);
return 0;
}
}

View File

@ -0,0 +1,25 @@
public class CollatzConjecture {
public static int collatzSteps(int n) {
int steps = 0;
while (n != 1) {
if (n - (n / 2) * 2 == 0) {
n = n / 2;
} else {
n = 3 * n + 1;
}
steps = steps + 1;
}
return steps;
}
public static int main() {
System.out.println(collatzSteps(1));
System.out.println(collatzSteps(2));
System.out.println(collatzSteps(3));
System.out.println(collatzSteps(10));
System.out.println(collatzSteps(15));
System.out.println(collatzSteps(27));
System.out.println(collatzSteps(100));
return 0;
}
}

View File

@ -0,0 +1,41 @@
public class PascalTriangle {
public static int binomialCoeff(int n, int k) {
if (k > n) {
return 0;
}
if (k == 0) {
return 1;
}
if (k == n) {
return 1;
}
if (k > n - k) {
k = n - k;
}
int result = 1;
int i = 0;
while (i < k) {
result = result * (n - i);
result = result / (i + 1);
i = i + 1;
}
return result;
}
public static int main() {
System.out.println(binomialCoeff(0, 0));
System.out.println(binomialCoeff(1, 0));
System.out.println(binomialCoeff(1, 1));
System.out.println(binomialCoeff(2, 0));
System.out.println(binomialCoeff(2, 1));
System.out.println(binomialCoeff(2, 2));
System.out.println(binomialCoeff(3, 0));
System.out.println(binomialCoeff(3, 1));
System.out.println(binomialCoeff(3, 2));
System.out.println(binomialCoeff(3, 3));
System.out.println(binomialCoeff(4, 2));
System.out.println(binomialCoeff(5, 2));
return 0;
}
}

View File

@ -0,0 +1,19 @@
public class TowerOfHanoi {
public static int hanoi(int n, int from, int to, int aux, int moveCount) {
if (n == 1) {
return moveCount + 1;
}
moveCount = hanoi(n - 1, from, aux, to, moveCount);
moveCount = moveCount + 1;
moveCount = hanoi(n - 1, aux, to, from, moveCount);
return moveCount;
}
public static int main() {
System.out.println(hanoi(1, 1, 3, 2, 0));
System.out.println(hanoi(2, 1, 3, 2, 0));
System.out.println(hanoi(3, 1, 3, 2, 0));
System.out.println(hanoi(4, 1, 3, 2, 0));
return 0;
}
}

View File

@ -0,0 +1,22 @@
public class AckermannFunction {
public static int ackermann(int m, int n) {
if (m == 0) {
return n + 1;
}
if (n == 0) {
return ackermann(m - 1, 1);
}
return ackermann(m - 1, ackermann(m, n - 1));
}
public static int main() {
System.out.println(ackermann(0, 0));
System.out.println(ackermann(0, 5));
System.out.println(ackermann(1, 0));
System.out.println(ackermann(1, 5));
System.out.println(ackermann(2, 0));
System.out.println(ackermann(2, 5));
System.out.println(ackermann(3, 0));
return 0;
}
}

View File

@ -0,0 +1,68 @@
public class ArrayOperations {
public static int sumArray(int[] arr, int length) {
int sum = 0;
int i = 0;
while (i < length) {
sum = sum + arr[i];
i = i + 1;
}
return sum;
}
public static int findMax(int[] arr, int length) {
int max = arr[0];
int i = 1;
while (i < length) {
if (arr[i] > max) {
max = arr[i];
}
i = i + 1;
}
return max;
}
public static int findMin(int[] arr, int length) {
int min = arr[0];
int i = 1;
while (i < length) {
if (arr[i] < min) {
min = arr[i];
}
i = i + 1;
}
return min;
}
public static int main() {
int[] numbers = new int[5];
numbers[0] = 10;
numbers[1] = 25;
numbers[2] = 5;
numbers[3] = 30;
numbers[4] = 15;
int sum = sumArray(numbers, 5);
System.out.println(sum);
int max = findMax(numbers, 5);
System.out.println(max);
int min = findMin(numbers, 5);
System.out.println(min);
int[] squares = new int[5];
int i = 0;
while (i < 5) {
squares[i] = (i + 1) * (i + 1);
i = i + 1;
}
System.out.println(squares[0]);
System.out.println(squares[1]);
System.out.println(squares[2]);
System.out.println(squares[3]);
System.out.println(squares[4]);
return 0;
}
}

View File

@ -0,0 +1,14 @@
public class SimpleArray {
public static int main() {
int[] arr = new int[3];
arr[0] = 10;
arr[1] = 20;
arr[2] = 30;
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
int sum = arr[0] + arr[1] + arr[2];
System.out.println(sum);
return 0;
}
}

View File

@ -0,0 +1,30 @@
public class TowerOfHanoiStatic {
public static int moveCount = 0;
public static int hanoi(int n, int from, int to, int aux) {
if (n == 1) {
moveCount = moveCount + 1;
return moveCount;
}
hanoi(n - 1, from, aux, to);
moveCount = moveCount + 1;
hanoi(n - 1, aux, to, from);
return moveCount;
}
public static int main() {
moveCount = 0;
System.out.println(hanoi(1, 1, 3, 2));
moveCount = 0;
System.out.println(hanoi(2, 1, 3, 2));
moveCount = 0;
System.out.println(hanoi(3, 1, 3, 2));
moveCount = 0;
System.out.println(hanoi(4, 1, 3, 2));
return 0;
}
}

View File

@ -0,0 +1,44 @@
public class StringBasics {
public static int main() {
System.out.println("Hello, World!");
System.out.println("String support in Rava!");
String greeting = "Hello";
String name = "Rava";
String message = greeting + ", " + name + "!";
System.out.println(message);
int x = 42;
System.out.println("The answer is: " + x);
String result = "Sum: " + 10 + 20;
System.out.println(result);
String test = "Hello";
int len = test.length();
System.out.println(len);
String longer = "Hello World";
System.out.println(longer.length());
String s1 = "test";
String s2 = "test";
String s3 = "other";
if (s1.equals(s2)) {
System.out.println(1);
} else {
System.out.println(0);
}
if (s1.equals(s3)) {
System.out.println(1);
} else {
System.out.println(0);
}
System.out.println("String tests completed!");
return 0;
}
}

View File

@ -0,0 +1,22 @@
public class SimpleObject {
public static int main() {
Point p = new Point();
p.x = 10;
p.y = 20;
System.out.println(p.x);
System.out.println(p.y);
int sum = p.x + p.y;
System.out.println(sum);
Point p2 = new Point();
p2.x = 5;
p2.y = 15;
int total = p.x + p2.x;
System.out.println(total);
return 0;
}
}

View File

@ -0,0 +1,23 @@
public class InstanceMethods {
int value;
InstanceMethods(int v) {
this.value = v;
}
int getValue() {
return this.value;
}
void setValue(int v) {
this.value = v;
}
public static int main() {
InstanceMethods obj = new InstanceMethods(42);
System.out.println(obj.getValue());
obj.setValue(100);
System.out.println(obj.getValue());
return 0;
}
}

32
examples/15_FileIO.java Normal file
View File

@ -0,0 +1,32 @@
public class FileIO {
public static int main() {
String content = "Hello from Rava!";
boolean written = Files.write("/tmp/rava_test.txt", content);
if (written) {
System.out.println("File written successfully");
}
boolean exists = Files.exists("/tmp/rava_test.txt");
if (exists) {
System.out.println("File exists");
}
String readContent = Files.read("/tmp/rava_test.txt");
System.out.println(readContent);
boolean deleted = Files.delete("/tmp/rava_test.txt");
if (deleted) {
System.out.println("File deleted");
}
exists = Files.exists("/tmp/rava_test.txt");
if (exists) {
System.out.println("File still exists");
} else {
System.out.println("File is gone");
}
return 0;
}
}

21
examples/16_ForLoop.java Normal file
View File

@ -0,0 +1,21 @@
public class ForLoop {
public static int main() {
int sum = 0;
for (int i = 1; i <= 5; i++) {
sum = sum + i;
}
System.out.println(sum);
int product = 1;
for (int j = 1; j <= 4; j++) {
product = product * j;
}
System.out.println(product);
for (int k = 0; k < 3; k++) {
System.out.println(k);
}
return 0;
}
}

View File

@ -0,0 +1,29 @@
public class Inheritance {
public static int main() {
Dog dog = new Dog();
dog.age = 5;
dog.speak();
dog.showAge();
return 0;
}
}
class Animal {
int age;
void speak() {
System.out.println("Animal speaks");
}
void showAge() {
System.out.println(this.age);
}
}
class Dog extends Animal {
void speak() {
System.out.println("Woof!");
}
}

28
examples/18_ElseIf.java Normal file
View File

@ -0,0 +1,28 @@
public class ElseIf {
public static int main() {
int x = 75;
if (x >= 90) {
System.out.println("A");
} else if (x >= 80) {
System.out.println("B");
} else if (x >= 70) {
System.out.println("C");
} else if (x >= 60) {
System.out.println("D");
} else {
System.out.println("F");
}
int y = 50;
if (y > 100) {
System.out.println("Over 100");
} else if (y > 50) {
System.out.println("Over 50");
} else {
System.out.println("50 or less");
}
return 0;
}
}

View File

@ -0,0 +1,42 @@
public class BreakContinue {
public static int main() {
int sum = 0;
for (int i = 1; i <= 10; i++) {
if (i == 6) {
break;
}
sum += i;
}
System.out.println(sum);
int count = 0;
for (int j = 1; j <= 10; j++) {
if (j % 2 == 0) {
continue;
}
count++;
}
System.out.println(count);
int x = 10;
x += 5;
System.out.println(x);
x -= 3;
System.out.println(x);
x *= 2;
System.out.println(x);
int k = 0;
while (k < 100) {
k++;
if (k == 5) {
break;
}
}
System.out.println(k);
return 0;
}
}

View File

@ -0,0 +1,94 @@
public class Benchmark {
public static int fibonacci(int n) {
if (n <= 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
public static int fibonacciIterative(int n) {
if (n <= 1) {
return n;
}
int a = 0;
int b = 1;
for (int i = 2; i <= n; i++) {
int temp = a + b;
a = b;
b = temp;
}
return b;
}
public static int countPrimes(int limit) {
int count = 0;
for (int n = 2; n <= limit; n++) {
boolean isPrime = true;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) {
isPrime = false;
break;
}
}
if (isPrime) {
count++;
}
}
return count;
}
public static long sumLoop(int iterations) {
long sum = 0L;
for (int i = 0; i < iterations; i++) {
sum = sum + i;
}
return sum;
}
public static int main() {
System.out.println("=== Rava Benchmark Suite ===");
long start = System.nanoTime();
int fib30 = fibonacci(30);
long end = System.nanoTime();
long fibTime = (end - start) / 1000000;
System.out.print("Fibonacci(30) recursive = ");
System.out.println(fib30);
System.out.print("Time: ");
System.out.print(fibTime);
System.out.println(" ms");
start = System.nanoTime();
int fib40iter = fibonacciIterative(40);
end = System.nanoTime();
long fibIterTime = (end - start) / 1000000;
System.out.print("Fibonacci(40) iterative = ");
System.out.println(fib40iter);
System.out.print("Time: ");
System.out.print(fibIterTime);
System.out.println(" ms");
start = System.nanoTime();
int primes = countPrimes(100000);
end = System.nanoTime();
long primeTime = (end - start) / 1000000;
System.out.print("Primes up to 100000 = ");
System.out.println(primes);
System.out.print("Time: ");
System.out.print(primeTime);
System.out.println(" ms");
start = System.nanoTime();
long sumResult = sumLoop(10000000);
end = System.nanoTime();
long sumTime = (end - start) / 1000000;
System.out.print("Sum 0..10000000 = ");
System.out.println(sumResult);
System.out.print("Time: ");
System.out.print(sumTime);
System.out.println(" ms");
System.out.println("=== Benchmark Complete ===");
return 0;
}
}

10
examples/HelloWorld.java Normal file
View File

@ -0,0 +1,10 @@
public class HelloWorld {
public static int main() {
System.out.println(42);
System.out.println(100);
int x = 10;
int y = 20;
System.out.println(x + y);
return 0;
}
}

71
examples/benchmark.py Normal file
View File

@ -0,0 +1,71 @@
#!/usr/bin/env python3
import time
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
def fibonacci_iterative(n):
if n <= 1:
return n
a, b = 0, 1
for i in range(2, n + 1):
a, b = b, a + b
return b
def count_primes(limit):
count = 0
for n in range(2, limit + 1):
is_prime = True
i = 2
while i * i <= n:
if n % i == 0:
is_prime = False
break
i += 1
if is_prime:
count += 1
return count
def sum_loop(iterations):
total = 0
for i in range(iterations):
total += i
return total
def main():
print("=== Python Benchmark Suite ===")
start = time.perf_counter_ns()
fib30 = fibonacci(30)
end = time.perf_counter_ns()
fib_time = (end - start) // 1000000
print(f"Fibonacci(30) recursive = {fib30}")
print(f"Time: {fib_time} ms")
start = time.perf_counter_ns()
fib40_iter = fibonacci_iterative(40)
end = time.perf_counter_ns()
fib_iter_time = (end - start) // 1000000
print(f"Fibonacci(40) iterative = {fib40_iter}")
print(f"Time: {fib_iter_time} ms")
start = time.perf_counter_ns()
primes = count_primes(100000)
end = time.perf_counter_ns()
prime_time = (end - start) // 1000000
print(f"Primes up to 100000 = {primes}")
print(f"Time: {prime_time} ms")
start = time.perf_counter_ns()
sum_result = sum_loop(10000000)
end = time.perf_counter_ns()
sum_time = (end - start) // 1000000
print(f"Sum 0..10000000 = {sum_result}")
print(f"Time: {sum_time} ms")
print("=== Benchmark Complete ===")
if __name__ == "__main__":
main()

200
ir/ir.c Normal file
View File

@ -0,0 +1,200 @@
#define _POSIX_C_SOURCE 200809L
#include "ir.h"
#include "../runtime/labeltable.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
RavaInstructionList_t* rava_instruction_list_create() {
RavaInstructionList_t *list = calloc(1, sizeof(RavaInstructionList_t));
list->capacity = 16;
list->instructions = malloc(sizeof(RavaInstruction_t) * list->capacity);
list->count = 0;
list->next_label_id = 1;
return list;
}
void rava_instruction_list_destroy(RavaInstructionList_t *list) {
if (!list) return;
free(list->instructions);
free(list);
}
void rava_instruction_list_add(RavaInstructionList_t *list, RavaInstruction_t instr) {
if (list->count >= list->capacity) {
list->capacity *= 2;
list->instructions = realloc(list->instructions,
sizeof(RavaInstruction_t) * list->capacity);
}
list->instructions[list->count++] = instr;
}
int rava_instruction_list_new_label(RavaInstructionList_t *list) {
return list->next_label_id++;
}
RavaMethod_t* rava_method_create(const char *name, RavaType_t *return_type) {
RavaMethod_t *method = calloc(1, sizeof(RavaMethod_t));
method->name = strdup(name);
method->return_type = return_type;
method->param_types = NULL;
method->param_count = 0;
method->local_count = 0;
method->instructions = rava_instruction_list_create();
method->label_table = NULL;
return method;
}
void rava_method_destroy(RavaMethod_t *method) {
if (!method) return;
free(method->name);
free(method->param_types);
rava_instruction_list_destroy(method->instructions);
if (method->label_table) {
rava_labeltable_destroy(method->label_table);
}
free(method);
}
RavaClass_t* rava_class_create(const char *name) {
RavaClass_t *class = calloc(1, sizeof(RavaClass_t));
class->name = strdup(name);
class->superclass = NULL;
class->methods = NULL;
class->method_count = 0;
class->method_capacity = 0;
return class;
}
void rava_class_destroy(RavaClass_t *class) {
if (!class) return;
free(class->name);
free(class->superclass);
for (size_t i = 0; i < class->method_count; i++) {
rava_method_destroy(class->methods[i]);
}
free(class->methods);
free(class);
}
void rava_class_add_method(RavaClass_t *class, RavaMethod_t *method) {
if (class->method_count >= class->method_capacity) {
size_t new_capacity = class->method_capacity == 0 ? 4 : class->method_capacity * 2;
class->methods = realloc(class->methods, sizeof(RavaMethod_t*) * new_capacity);
class->method_capacity = new_capacity;
}
class->methods[class->method_count++] = method;
}
RavaProgram_t* rava_program_create() {
RavaProgram_t *program = calloc(1, sizeof(RavaProgram_t));
program->classes = NULL;
program->class_count = 0;
program->class_capacity = 0;
return program;
}
void rava_program_destroy(RavaProgram_t *program) {
if (!program) return;
for (size_t i = 0; i < program->class_count; i++) {
rava_class_destroy(program->classes[i]);
}
free(program->classes);
free(program);
}
void rava_program_add_class(RavaProgram_t *program, RavaClass_t *class) {
if (program->class_count >= program->class_capacity) {
size_t new_capacity = program->class_capacity == 0 ? 4 : program->class_capacity * 2;
program->classes = realloc(program->classes, sizeof(RavaClass_t*) * new_capacity);
program->class_capacity = new_capacity;
}
program->classes[program->class_count++] = class;
}
static const char* _rava_opcode_name(RavaOpCode_e opcode) {
switch (opcode) {
case RAVA_OP_NOP: return "NOP";
case RAVA_OP_LOAD_CONST: return "LOAD_CONST";
case RAVA_OP_LOAD_LOCAL: return "LOAD_LOCAL";
case RAVA_OP_STORE_LOCAL: return "STORE_LOCAL";
case RAVA_OP_ADD: return "ADD";
case RAVA_OP_SUB: return "SUB";
case RAVA_OP_MUL: return "MUL";
case RAVA_OP_DIV: return "DIV";
case RAVA_OP_MOD: return "MOD";
case RAVA_OP_NEG: return "NEG";
case RAVA_OP_EQ: return "EQ";
case RAVA_OP_NE: return "NE";
case RAVA_OP_LT: return "LT";
case RAVA_OP_LE: return "LE";
case RAVA_OP_GT: return "GT";
case RAVA_OP_GE: return "GE";
case RAVA_OP_JUMP: return "JUMP";
case RAVA_OP_JUMP_IF_TRUE: return "JUMP_IF_TRUE";
case RAVA_OP_JUMP_IF_FALSE: return "JUMP_IF_FALSE";
case RAVA_OP_LABEL: return "LABEL";
case RAVA_OP_CALL: return "CALL";
case RAVA_OP_CALL_STATIC: return "CALL_STATIC";
case RAVA_OP_RETURN: return "RETURN";
case RAVA_OP_RETURN_VOID: return "RETURN_VOID";
case RAVA_OP_NEW: return "NEW";
case RAVA_OP_NEW_ARRAY: return "NEW_ARRAY";
case RAVA_OP_ARRAY_LENGTH: return "ARRAY_LENGTH";
case RAVA_OP_LOAD_ARRAY: return "LOAD_ARRAY";
case RAVA_OP_STORE_ARRAY: return "STORE_ARRAY";
case RAVA_OP_POP: return "POP";
case RAVA_OP_DUP: return "DUP";
case RAVA_OP_PRINT: return "PRINT";
case RAVA_OP_PRINTLN: return "PRINTLN";
default: return "UNKNOWN";
}
}
void rava_ir_print(RavaProgram_t *program) {
if (!program) return;
printf("IR Program (%zu classes)\n", program->class_count);
printf("================================================================================\n\n");
for (size_t i = 0; i < program->class_count; i++) {
RavaClass_t *class = program->classes[i];
printf("Class: %s\n", class->name);
for (size_t j = 0; j < class->method_count; j++) {
RavaMethod_t *method = class->methods[j];
printf(" Method: %s (locals: %d)\n", method->name, method->local_count);
for (size_t k = 0; k < method->instructions->count; k++) {
RavaInstruction_t *instr = &method->instructions->instructions[k];
printf(" %04zu %-15s", k, _rava_opcode_name(instr->opcode));
switch (instr->opcode) {
case RAVA_OP_LOAD_CONST:
printf(" %lld", (long long)instr->operand.int_value);
break;
case RAVA_OP_LOAD_LOCAL:
case RAVA_OP_STORE_LOCAL:
printf(" [%d]", instr->operand.var.index);
break;
case RAVA_OP_LABEL:
case RAVA_OP_JUMP:
case RAVA_OP_JUMP_IF_TRUE:
case RAVA_OP_JUMP_IF_FALSE:
printf(" L%d", instr->operand.label_id);
break;
case RAVA_OP_CALL_STATIC:
printf(" %s.%s",
instr->operand.call.class_name,
instr->operand.call.method_name);
break;
default:
break;
}
printf("\n");
}
printf("\n");
}
}
}

197
ir/ir.h Normal file
View File

@ -0,0 +1,197 @@
#ifndef RAVA_IR_H
#define RAVA_IR_H
#include "../types/types.h"
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
typedef enum {
RAVA_OP_NOP,
RAVA_OP_LOAD_CONST,
RAVA_OP_LOAD_LONG,
RAVA_OP_LOAD_DOUBLE,
RAVA_OP_LOAD_STRING,
RAVA_OP_LOAD_LOCAL,
RAVA_OP_LOAD_FIELD,
RAVA_OP_LOAD_STATIC,
RAVA_OP_LOAD_ARRAY,
RAVA_OP_STORE_LOCAL,
RAVA_OP_STORE_FIELD,
RAVA_OP_STORE_STATIC,
RAVA_OP_STORE_ARRAY,
RAVA_OP_ADD,
RAVA_OP_SUB,
RAVA_OP_MUL,
RAVA_OP_DIV,
RAVA_OP_MOD,
RAVA_OP_NEG,
RAVA_OP_AND,
RAVA_OP_OR,
RAVA_OP_XOR,
RAVA_OP_NOT,
RAVA_OP_SHL,
RAVA_OP_SHR,
RAVA_OP_USHR,
RAVA_OP_EQ,
RAVA_OP_NE,
RAVA_OP_LT,
RAVA_OP_LE,
RAVA_OP_GT,
RAVA_OP_GE,
RAVA_OP_JUMP,
RAVA_OP_JUMP_IF_TRUE,
RAVA_OP_JUMP_IF_FALSE,
RAVA_OP_LABEL,
RAVA_OP_CALL,
RAVA_OP_CALL_STATIC,
RAVA_OP_CALL_VIRTUAL,
RAVA_OP_CALL_NATIVE,
RAVA_OP_RETURN,
RAVA_OP_RETURN_VOID,
RAVA_OP_NEW,
RAVA_OP_NEW_ARRAY,
RAVA_OP_ARRAY_LENGTH,
RAVA_OP_GET_FIELD,
RAVA_OP_PUT_FIELD,
RAVA_OP_CAST,
RAVA_OP_INSTANCEOF,
RAVA_OP_THROW,
RAVA_OP_POP,
RAVA_OP_DUP,
RAVA_OP_PRINT,
RAVA_OP_PRINTLN,
RAVA_OP_STRING_LENGTH,
RAVA_OP_STRING_CHARAT,
RAVA_OP_STRING_SUBSTRING,
RAVA_OP_STRING_EQUALS,
RAVA_OP_STRING_COMPARETO,
RAVA_OP_LOAD_THIS,
RAVA_OP_FILE_READ,
RAVA_OP_FILE_WRITE,
RAVA_OP_FILE_EXISTS,
RAVA_OP_FILE_DELETE,
RAVA_OP_CURRENT_TIME_MILLIS,
RAVA_OP_NANO_TIME,
RAVA_OP_INC_LOCAL,
RAVA_OP_DEC_LOCAL,
RAVA_OP_LOAD_LOCAL_CONST_ADD,
RAVA_OP_LOAD_LOCAL_CONST_LT_JUMPFALSE,
RAVA_OP_LOAD_LOCAL_CONST_LE_JUMPFALSE,
RAVA_OP_LOAD_TWO_LOCALS,
RAVA_OP_ADD_LOCAL_TO_LOCAL,
RAVA_OP_LOAD_LOCAL_LT_LOCAL_JUMPFALSE
} RavaOpCode_e;
typedef union {
int64_t int_value;
double float_value;
char *string_value;
int label_id;
struct {
int index;
RavaType_t *type;
} var;
struct {
char *class_name;
char *method_name;
int arg_count;
} call;
struct {
char *class_name;
char *field_name;
} field;
struct {
int local_index;
int64_t const_value;
int label_id;
} super;
struct {
int index1;
int index2;
} two_locals;
struct {
int dest_index;
int src_index;
} add_locals;
struct {
int local1;
int local2;
int label_id;
} cmp_locals;
} RavaOperand_u;
typedef struct {
RavaOpCode_e opcode;
RavaOperand_u operand;
int line;
} RavaInstruction_t;
typedef struct {
RavaInstruction_t *instructions;
size_t count;
size_t capacity;
int next_label_id;
} RavaInstructionList_t;
struct LabelTable_s;
typedef struct {
char *name;
RavaType_t *return_type;
RavaType_t **param_types;
size_t param_count;
int local_count;
RavaInstructionList_t *instructions;
struct LabelTable_s *label_table;
} RavaMethod_t;
typedef struct {
char *name;
char *superclass;
RavaMethod_t **methods;
size_t method_count;
size_t method_capacity;
} RavaClass_t;
typedef struct {
RavaClass_t **classes;
size_t class_count;
size_t class_capacity;
} RavaProgram_t;
RavaInstructionList_t* rava_instruction_list_create();
void rava_instruction_list_destroy(RavaInstructionList_t *list);
void rava_instruction_list_add(RavaInstructionList_t *list, RavaInstruction_t instr);
int rava_instruction_list_new_label(RavaInstructionList_t *list);
RavaMethod_t* rava_method_create(const char *name, RavaType_t *return_type);
void rava_method_destroy(RavaMethod_t *method);
RavaClass_t* rava_class_create(const char *name);
void rava_class_destroy(RavaClass_t *class);
void rava_class_add_method(RavaClass_t *class, RavaMethod_t *method);
RavaProgram_t* rava_program_create();
void rava_program_destroy(RavaProgram_t *program);
void rava_program_add_class(RavaProgram_t *program, RavaClass_t *class);
void rava_ir_print(RavaProgram_t *program);
#endif

669
ir/ir_gen.c Normal file
View File

@ -0,0 +1,669 @@
#define _POSIX_C_SOURCE 200809L
#include "ir_gen.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr);
static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt);
static void _rava_ir_clear_locals(RavaIRGenerator_t *gen) {
RavaLocalVar_t *current = gen->locals;
while (current) {
RavaLocalVar_t *next = current->next;
free(current->name);
free(current);
current = next;
}
gen->locals = NULL;
}
static void _rava_ir_add_local(RavaIRGenerator_t *gen, const char *name, size_t index) {
RavaLocalVar_t *local = calloc(1, sizeof(RavaLocalVar_t));
local->name = strdup(name);
local->index = index;
local->next = gen->locals;
gen->locals = local;
}
static int _rava_ir_find_local(RavaIRGenerator_t *gen, const char *name) {
for (RavaLocalVar_t *local = gen->locals; local; local = local->next) {
if (strcmp(local->name, name) == 0) {
return (int)local->index;
}
}
return -1;
}
RavaIRGenerator_t* rava_ir_generator_create(RavaSemanticAnalyzer_t *analyzer) {
RavaIRGenerator_t *gen = calloc(1, sizeof(RavaIRGenerator_t));
gen->program = rava_program_create();
gen->current_class = NULL;
gen->current_method = NULL;
gen->analyzer = analyzer;
gen->next_local = 0;
gen->locals = NULL;
gen->loop_context = NULL;
gen->error_message = NULL;
gen->had_error = false;
return gen;
}
void rava_ir_generator_destroy(RavaIRGenerator_t *generator) {
if (!generator) return;
_rava_ir_clear_locals(generator);
free(generator->error_message);
free(generator);
}
static void _rava_ir_emit(RavaIRGenerator_t *gen, RavaInstruction_t instr) {
if (!gen->current_method) return;
rava_instruction_list_add(gen->current_method->instructions, instr);
}
static void _rava_ir_gen_binary_expr(RavaIRGenerator_t *gen, RavaASTNode_t *expr) {
_rava_ir_gen_expression(gen, expr->data.binary.left);
_rava_ir_gen_expression(gen, expr->data.binary.right);
RavaInstruction_t instr = {0};
instr.line = expr->line;
switch (expr->data.binary.op) {
case RAVA_BINOP_ADD: instr.opcode = RAVA_OP_ADD; break;
case RAVA_BINOP_SUB: instr.opcode = RAVA_OP_SUB; break;
case RAVA_BINOP_MUL: instr.opcode = RAVA_OP_MUL; break;
case RAVA_BINOP_DIV: instr.opcode = RAVA_OP_DIV; break;
case RAVA_BINOP_MOD: instr.opcode = RAVA_OP_MOD; break;
case RAVA_BINOP_EQ: instr.opcode = RAVA_OP_EQ; break;
case RAVA_BINOP_NE: instr.opcode = RAVA_OP_NE; break;
case RAVA_BINOP_LT: instr.opcode = RAVA_OP_LT; break;
case RAVA_BINOP_LE: instr.opcode = RAVA_OP_LE; break;
case RAVA_BINOP_GT: instr.opcode = RAVA_OP_GT; break;
case RAVA_BINOP_GE: instr.opcode = RAVA_OP_GE; break;
case RAVA_BINOP_AND: instr.opcode = RAVA_OP_AND; break;
case RAVA_BINOP_OR: instr.opcode = RAVA_OP_OR; break;
default: instr.opcode = RAVA_OP_NOP; break;
}
_rava_ir_emit(gen, instr);
}
static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr) {
if (!expr) return;
RavaInstruction_t instr = {0};
instr.line = expr->line;
switch (expr->type) {
case RAVA_AST_LITERAL_EXPR:
if (expr->data.literal.literal_type == RAVA_TOKEN_LITERAL_STRING) {
instr.opcode = RAVA_OP_LOAD_STRING;
instr.operand.string_value = strdup(expr->data.literal.value.string_value);
_rava_ir_emit(gen, instr);
} else if (expr->data.literal.literal_type == RAVA_TOKEN_LITERAL_LONG) {
instr.opcode = RAVA_OP_LOAD_LONG;
instr.operand.int_value = expr->data.literal.value.int_value;
_rava_ir_emit(gen, instr);
} else if (expr->data.literal.literal_type == RAVA_TOKEN_LITERAL_DOUBLE) {
instr.opcode = RAVA_OP_LOAD_DOUBLE;
instr.operand.float_value = expr->data.literal.value.float_value;
_rava_ir_emit(gen, instr);
} else {
instr.opcode = RAVA_OP_LOAD_CONST;
instr.operand.int_value = expr->data.literal.value.int_value;
_rava_ir_emit(gen, instr);
}
break;
case RAVA_AST_IDENTIFIER_EXPR: {
int local_index = _rava_ir_find_local(gen, expr->data.identifier.name);
if (local_index >= 0) {
instr.opcode = RAVA_OP_LOAD_LOCAL;
instr.operand.var.index = (size_t)local_index;
_rava_ir_emit(gen, instr);
}
break;
}
case RAVA_AST_BINARY_EXPR:
_rava_ir_gen_binary_expr(gen, expr);
break;
case RAVA_AST_UNARY_EXPR:
if (expr->data.unary.op == RAVA_UNOP_MINUS) {
_rava_ir_gen_expression(gen, expr->data.unary.operand);
instr.opcode = RAVA_OP_NEG;
_rava_ir_emit(gen, instr);
} else if (expr->data.unary.op == RAVA_UNOP_NOT) {
_rava_ir_gen_expression(gen, expr->data.unary.operand);
instr.opcode = RAVA_OP_NOT;
_rava_ir_emit(gen, instr);
} else if (expr->data.unary.op == RAVA_UNOP_PREINC || expr->data.unary.op == RAVA_UNOP_PREDEC) {
if (expr->data.unary.operand->type == RAVA_AST_IDENTIFIER_EXPR) {
int local_index = _rava_ir_find_local(gen, expr->data.unary.operand->data.identifier.name);
if (local_index >= 0) {
instr.opcode = RAVA_OP_LOAD_LOCAL;
instr.operand.var.index = (size_t)local_index;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_LOAD_CONST;
instr.operand.int_value = 1;
_rava_ir_emit(gen, instr);
instr.opcode = (expr->data.unary.op == RAVA_UNOP_PREINC) ? RAVA_OP_ADD : RAVA_OP_SUB;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_DUP;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_STORE_LOCAL;
instr.operand.var.index = (size_t)local_index;
_rava_ir_emit(gen, instr);
}
}
} else if (expr->data.unary.op == RAVA_UNOP_POSTINC || expr->data.unary.op == RAVA_UNOP_POSTDEC) {
if (expr->data.unary.operand->type == RAVA_AST_IDENTIFIER_EXPR) {
int local_index = _rava_ir_find_local(gen, expr->data.unary.operand->data.identifier.name);
if (local_index >= 0) {
instr.opcode = RAVA_OP_LOAD_LOCAL;
instr.operand.var.index = (size_t)local_index;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_LOAD_LOCAL;
instr.operand.var.index = (size_t)local_index;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_LOAD_CONST;
instr.operand.int_value = 1;
_rava_ir_emit(gen, instr);
instr.opcode = (expr->data.unary.op == RAVA_UNOP_POSTINC) ? RAVA_OP_ADD : RAVA_OP_SUB;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_STORE_LOCAL;
instr.operand.var.index = (size_t)local_index;
_rava_ir_emit(gen, instr);
}
}
} else {
_rava_ir_gen_expression(gen, expr->data.unary.operand);
}
break;
case RAVA_AST_ASSIGN_EXPR:
if (expr->data.assign.target->type == RAVA_AST_ARRAY_ACCESS_EXPR) {
_rava_ir_gen_expression(gen, expr->data.assign.target->data.array_access.array);
_rava_ir_gen_expression(gen, expr->data.assign.target->data.array_access.index);
_rava_ir_gen_expression(gen, expr->data.assign.value);
instr.opcode = RAVA_OP_STORE_ARRAY;
_rava_ir_emit(gen, instr);
} else if (expr->data.assign.target->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
_rava_ir_gen_expression(gen, expr->data.assign.target->data.member_access.object);
_rava_ir_gen_expression(gen, expr->data.assign.value);
instr.opcode = RAVA_OP_PUT_FIELD;
instr.operand.field.field_name = strdup(expr->data.assign.target->data.member_access.member);
_rava_ir_emit(gen, instr);
} else {
_rava_ir_gen_expression(gen, expr->data.assign.value);
if (expr->data.assign.target->type == RAVA_AST_IDENTIFIER_EXPR) {
int local_index = _rava_ir_find_local(gen, expr->data.assign.target->data.identifier.name);
if (local_index >= 0) {
instr.opcode = RAVA_OP_STORE_LOCAL;
instr.operand.var.index = (size_t)local_index;
_rava_ir_emit(gen, instr);
}
}
}
break;
case RAVA_AST_MEMBER_ACCESS_EXPR:
_rava_ir_gen_expression(gen, expr->data.member_access.object);
instr.opcode = RAVA_OP_GET_FIELD;
instr.operand.field.field_name = strdup(expr->data.member_access.member);
_rava_ir_emit(gen, instr);
break;
case RAVA_AST_ARRAY_ACCESS_EXPR:
_rava_ir_gen_expression(gen, expr->data.array_access.array);
_rava_ir_gen_expression(gen, expr->data.array_access.index);
instr.opcode = RAVA_OP_LOAD_ARRAY;
_rava_ir_emit(gen, instr);
break;
case RAVA_AST_NEW_EXPR:
if (expr->data.new_expr.type && expr->data.new_expr.type->data.type.is_array) {
if (expr->data.new_expr.arguments_count > 0) {
_rava_ir_gen_expression(gen, expr->data.new_expr.arguments[0]);
}
instr.opcode = RAVA_OP_NEW_ARRAY;
_rava_ir_emit(gen, instr);
} else if (expr->data.new_expr.type) {
instr.opcode = RAVA_OP_NEW;
instr.operand.call.class_name = strdup(expr->data.new_expr.type->data.type.type_name);
instr.operand.call.arg_count = expr->data.new_expr.arguments_count;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_DUP;
_rava_ir_emit(gen, instr);
for (size_t i = 0; i < expr->data.new_expr.arguments_count; i++) {
_rava_ir_gen_expression(gen, expr->data.new_expr.arguments[i]);
}
instr.opcode = RAVA_OP_CALL_VIRTUAL;
instr.operand.call.method_name = strdup("<init>");
_rava_ir_emit(gen, instr);
}
break;
case RAVA_AST_CALL_EXPR: {
bool is_println = false;
bool is_print = false;
bool is_string_length = false;
bool is_string_charat = false;
bool is_string_equals = false;
bool is_file_read = false;
bool is_file_write = false;
bool is_file_exists = false;
bool is_file_delete = false;
bool is_current_time_millis = false;
bool is_nano_time = false;
RavaASTNode_t *string_object = NULL;
if (expr->data.call.callee->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
RavaASTNode_t *member = expr->data.call.callee;
if (member->data.member_access.object->type == RAVA_AST_IDENTIFIER_EXPR &&
strcmp(member->data.member_access.object->data.identifier.name, "System") == 0) {
if (strcmp(member->data.member_access.member, "currentTimeMillis") == 0) {
is_current_time_millis = true;
} else if (strcmp(member->data.member_access.member, "nanoTime") == 0) {
is_nano_time = true;
}
}
if (member->data.member_access.object->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
RavaASTNode_t *system_out = member->data.member_access.object;
if (system_out->data.member_access.object->type == RAVA_AST_IDENTIFIER_EXPR &&
strcmp(system_out->data.member_access.object->data.identifier.name, "System") == 0 &&
strcmp(system_out->data.member_access.member, "out") == 0) {
if (strcmp(member->data.member_access.member, "println") == 0) {
is_println = true;
} else if (strcmp(member->data.member_access.member, "print") == 0) {
is_print = true;
}
}
}
if (member->data.member_access.object->type == RAVA_AST_IDENTIFIER_EXPR &&
strcmp(member->data.member_access.object->data.identifier.name, "Files") == 0) {
if (strcmp(member->data.member_access.member, "read") == 0 && expr->data.call.arguments_count == 1) {
is_file_read = true;
} else if (strcmp(member->data.member_access.member, "write") == 0 && expr->data.call.arguments_count == 2) {
is_file_write = true;
} else if (strcmp(member->data.member_access.member, "exists") == 0 && expr->data.call.arguments_count == 1) {
is_file_exists = true;
} else if (strcmp(member->data.member_access.member, "delete") == 0 && expr->data.call.arguments_count == 1) {
is_file_delete = 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;
} else if (strcmp(member->data.member_access.member, "charAt") == 0 && expr->data.call.arguments_count == 1) {
is_string_charat = true;
string_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "equals") == 0 && expr->data.call.arguments_count == 1) {
is_string_equals = true;
string_object = member->data.member_access.object;
}
}
if (is_current_time_millis) {
instr.opcode = RAVA_OP_CURRENT_TIME_MILLIS;
_rava_ir_emit(gen, instr);
} else if (is_nano_time) {
instr.opcode = RAVA_OP_NANO_TIME;
_rava_ir_emit(gen, instr);
} else if (is_file_read) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_FILE_READ;
_rava_ir_emit(gen, instr);
} else if (is_file_write) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
_rava_ir_gen_expression(gen, expr->data.call.arguments[1]);
instr.opcode = RAVA_OP_FILE_WRITE;
_rava_ir_emit(gen, instr);
} else if (is_file_exists) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_FILE_EXISTS;
_rava_ir_emit(gen, instr);
} else if (is_file_delete) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_FILE_DELETE;
_rava_ir_emit(gen, instr);
} else if (is_string_length) {
_rava_ir_gen_expression(gen, string_object);
instr.opcode = RAVA_OP_STRING_LENGTH;
_rava_ir_emit(gen, instr);
} else if (is_string_charat) {
_rava_ir_gen_expression(gen, string_object);
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_STRING_CHARAT;
_rava_ir_emit(gen, instr);
} else if (is_string_equals) {
_rava_ir_gen_expression(gen, string_object);
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_STRING_EQUALS;
_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]);
}
if (is_println) {
instr.opcode = RAVA_OP_PRINTLN;
} else {
instr.opcode = RAVA_OP_PRINT;
}
_rava_ir_emit(gen, instr);
} else if (expr->data.call.callee->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
RavaASTNode_t *member = expr->data.call.callee;
_rava_ir_gen_expression(gen, member->data.member_access.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_CALL_VIRTUAL;
instr.operand.call.class_name = strdup(gen->current_class->name);
instr.operand.call.method_name = strdup(member->data.member_access.member);
instr.operand.call.arg_count = expr->data.call.arguments_count;
_rava_ir_emit(gen, instr);
} else {
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_CALL_STATIC;
if (expr->data.call.callee->type == RAVA_AST_IDENTIFIER_EXPR) {
instr.operand.call.class_name = strdup(gen->current_class->name);
instr.operand.call.method_name = strdup(expr->data.call.callee->data.identifier.name);
instr.operand.call.arg_count = expr->data.call.arguments_count;
}
_rava_ir_emit(gen, instr);
}
break;
}
case RAVA_AST_THIS_EXPR:
instr.opcode = RAVA_OP_LOAD_THIS;
_rava_ir_emit(gen, instr);
break;
default:
break;
}
}
static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt) {
if (!stmt) return;
RavaInstruction_t instr = {0};
instr.line = stmt->line;
switch (stmt->type) {
case RAVA_AST_BLOCK_STMT:
for (size_t i = 0; i < stmt->children_count; i++) {
_rava_ir_gen_statement(gen, stmt->children[i]);
}
break;
case RAVA_AST_IF_STMT: {
_rava_ir_gen_expression(gen, stmt->data.if_stmt.condition);
int else_label = rava_instruction_list_new_label(gen->current_method->instructions);
int end_label = rava_instruction_list_new_label(gen->current_method->instructions);
instr.opcode = RAVA_OP_JUMP_IF_FALSE;
instr.operand.label_id = else_label;
_rava_ir_emit(gen, instr);
_rava_ir_gen_statement(gen, stmt->data.if_stmt.then_stmt);
instr.opcode = RAVA_OP_JUMP;
instr.operand.label_id = end_label;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_LABEL;
instr.operand.label_id = else_label;
_rava_ir_emit(gen, instr);
if (stmt->data.if_stmt.else_stmt) {
_rava_ir_gen_statement(gen, stmt->data.if_stmt.else_stmt);
}
instr.opcode = RAVA_OP_LABEL;
instr.operand.label_id = end_label;
_rava_ir_emit(gen, instr);
break;
}
case RAVA_AST_WHILE_STMT: {
int start_label = rava_instruction_list_new_label(gen->current_method->instructions);
int end_label = rava_instruction_list_new_label(gen->current_method->instructions);
RavaLoopContext_t loop_ctx = { .break_label = end_label, .continue_label = start_label, .parent = gen->loop_context };
gen->loop_context = &loop_ctx;
instr.opcode = RAVA_OP_LABEL;
instr.operand.label_id = start_label;
_rava_ir_emit(gen, instr);
_rava_ir_gen_expression(gen, stmt->data.while_stmt.condition);
instr.opcode = RAVA_OP_JUMP_IF_FALSE;
instr.operand.label_id = end_label;
_rava_ir_emit(gen, instr);
_rava_ir_gen_statement(gen, stmt->data.while_stmt.body);
instr.opcode = RAVA_OP_JUMP;
instr.operand.label_id = start_label;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_LABEL;
instr.operand.label_id = end_label;
_rava_ir_emit(gen, instr);
gen->loop_context = loop_ctx.parent;
break;
}
case RAVA_AST_FOR_STMT: {
if (stmt->data.for_stmt.init) {
if (stmt->data.for_stmt.init->type == RAVA_AST_VAR_DECL) {
_rava_ir_gen_statement(gen, stmt->data.for_stmt.init);
} else {
_rava_ir_gen_expression(gen, stmt->data.for_stmt.init);
instr.opcode = RAVA_OP_POP;
_rava_ir_emit(gen, instr);
}
}
int start_label = rava_instruction_list_new_label(gen->current_method->instructions);
int continue_label = rava_instruction_list_new_label(gen->current_method->instructions);
int end_label = rava_instruction_list_new_label(gen->current_method->instructions);
RavaLoopContext_t loop_ctx = { .break_label = end_label, .continue_label = continue_label, .parent = gen->loop_context };
gen->loop_context = &loop_ctx;
instr.opcode = RAVA_OP_LABEL;
instr.operand.label_id = start_label;
_rava_ir_emit(gen, instr);
if (stmt->data.for_stmt.condition) {
_rava_ir_gen_expression(gen, stmt->data.for_stmt.condition);
instr.opcode = RAVA_OP_JUMP_IF_FALSE;
instr.operand.label_id = end_label;
_rava_ir_emit(gen, instr);
}
_rava_ir_gen_statement(gen, stmt->data.for_stmt.body);
instr.opcode = RAVA_OP_LABEL;
instr.operand.label_id = continue_label;
_rava_ir_emit(gen, instr);
if (stmt->data.for_stmt.update) {
_rava_ir_gen_expression(gen, stmt->data.for_stmt.update);
instr.opcode = RAVA_OP_POP;
_rava_ir_emit(gen, instr);
}
instr.opcode = RAVA_OP_JUMP;
instr.operand.label_id = start_label;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_LABEL;
instr.operand.label_id = end_label;
_rava_ir_emit(gen, instr);
gen->loop_context = loop_ctx.parent;
break;
}
case RAVA_AST_RETURN_STMT:
if (stmt->data.return_stmt.value) {
_rava_ir_gen_expression(gen, stmt->data.return_stmt.value);
instr.opcode = RAVA_OP_RETURN;
} else {
instr.opcode = RAVA_OP_RETURN_VOID;
}
_rava_ir_emit(gen, instr);
break;
case RAVA_AST_EXPR_STMT:
if (stmt->children_count > 0) {
_rava_ir_gen_expression(gen, stmt->children[0]);
instr.opcode = RAVA_OP_POP;
_rava_ir_emit(gen, instr);
}
break;
case RAVA_AST_VAR_DECL: {
_rava_ir_add_local(gen, stmt->data.var_decl.name, gen->next_local);
gen->next_local++;
if (stmt->data.var_decl.initializer) {
_rava_ir_gen_expression(gen, stmt->data.var_decl.initializer);
instr.opcode = RAVA_OP_STORE_LOCAL;
instr.operand.var.index = gen->next_local - 1;
_rava_ir_emit(gen, instr);
}
break;
}
case RAVA_AST_BREAK_STMT:
if (gen->loop_context) {
instr.opcode = RAVA_OP_JUMP;
instr.operand.label_id = gen->loop_context->break_label;
_rava_ir_emit(gen, instr);
}
break;
case RAVA_AST_CONTINUE_STMT:
if (gen->loop_context) {
instr.opcode = RAVA_OP_JUMP;
instr.operand.label_id = gen->loop_context->continue_label;
_rava_ir_emit(gen, instr);
}
break;
default:
break;
}
}
static void _rava_ir_gen_method(RavaIRGenerator_t *gen, RavaASTNode_t *method_node) {
if (method_node->type != RAVA_AST_METHOD_DECL) return;
RavaType_t *return_type = rava_type_from_name(
method_node->data.method_decl.return_type->data.type.type_name);
RavaMethod_t *method = rava_method_create(method_node->data.method_decl.name, return_type);
gen->current_method = method;
gen->next_local = 0;
_rava_ir_clear_locals(gen);
rava_symbol_table_enter_scope(gen->analyzer->symbol_table, method_node->data.method_decl.name);
for (size_t i = 0; i < method_node->children_count; i++) {
RavaASTNode_t *child = method_node->children[i];
if (child->type == RAVA_AST_PARAM_DECL) {
_rava_ir_add_local(gen, child->data.var_decl.name, gen->next_local);
gen->next_local++;
} else if (child->type == RAVA_AST_BLOCK_STMT) {
_rava_ir_gen_statement(gen, child);
}
}
rava_symbol_table_exit_scope(gen->analyzer->symbol_table);
method->local_count = gen->next_local;
rava_class_add_method(gen->current_class, method);
gen->current_method = NULL;
}
static void _rava_ir_gen_constructor(RavaIRGenerator_t *gen, RavaASTNode_t *ctor_node) {
if (ctor_node->type != RAVA_AST_CONSTRUCTOR_DECL) return;
RavaType_t *void_type = rava_type_from_name("void");
RavaMethod_t *method = rava_method_create("<init>", void_type);
gen->current_method = method;
gen->next_local = 0;
_rava_ir_clear_locals(gen);
for (size_t i = 0; i < ctor_node->children_count; i++) {
RavaASTNode_t *child = ctor_node->children[i];
if (child->type == RAVA_AST_PARAM_DECL) {
_rava_ir_add_local(gen, child->data.var_decl.name, gen->next_local);
gen->next_local++;
} else if (child->type == RAVA_AST_BLOCK_STMT) {
_rava_ir_gen_statement(gen, child);
}
}
RavaInstruction_t ret_instr = {0};
ret_instr.opcode = RAVA_OP_RETURN_VOID;
_rava_ir_emit(gen, ret_instr);
method->local_count = gen->next_local;
rava_class_add_method(gen->current_class, method);
gen->current_method = NULL;
}
static void _rava_ir_gen_class(RavaIRGenerator_t *gen, RavaASTNode_t *class_node) {
if (class_node->type != RAVA_AST_CLASS_DECL) return;
RavaClass_t *class = rava_class_create(class_node->data.class_decl.name);
if (class_node->data.class_decl.superclass) {
class->superclass = strdup(class_node->data.class_decl.superclass);
}
gen->current_class = class;
rava_symbol_table_enter_scope(gen->analyzer->symbol_table, class_node->data.class_decl.name);
for (size_t i = 0; i < class_node->children_count; i++) {
RavaASTNode_t *child = class_node->children[i];
if (child->type == RAVA_AST_METHOD_DECL) {
_rava_ir_gen_method(gen, child);
} else if (child->type == RAVA_AST_CONSTRUCTOR_DECL) {
_rava_ir_gen_constructor(gen, child);
}
}
rava_symbol_table_exit_scope(gen->analyzer->symbol_table);
rava_program_add_class(gen->program, class);
gen->current_class = NULL;
}
RavaProgram_t* rava_ir_generate(RavaIRGenerator_t *generator, RavaASTNode_t *root) {
if (!generator || !root) return NULL;
if (root->type == RAVA_AST_COMPILATION_UNIT) {
for (size_t i = 0; i < root->children_count; i++) {
RavaASTNode_t *child = root->children[i];
if (child->type == RAVA_AST_CLASS_DECL) {
_rava_ir_gen_class(generator, child);
}
}
}
return generator->program;
}

37
ir/ir_gen.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef RAVA_IR_GEN_H
#define RAVA_IR_GEN_H
#include "../parser/parser.h"
#include "../semantic/semantic.h"
#include "ir.h"
typedef struct RavaLocalVar_t {
char *name;
size_t index;
struct RavaLocalVar_t *next;
} RavaLocalVar_t;
typedef struct RavaLoopContext_t {
int break_label;
int continue_label;
struct RavaLoopContext_t *parent;
} RavaLoopContext_t;
typedef struct {
RavaProgram_t *program;
RavaClass_t *current_class;
RavaMethod_t *current_method;
RavaSemanticAnalyzer_t *analyzer;
int next_local;
RavaLocalVar_t *locals;
RavaLoopContext_t *loop_context;
char *error_message;
bool had_error;
} RavaIRGenerator_t;
RavaIRGenerator_t* rava_ir_generator_create(RavaSemanticAnalyzer_t *analyzer);
void rava_ir_generator_destroy(RavaIRGenerator_t *generator);
RavaProgram_t* rava_ir_generate(RavaIRGenerator_t *generator, RavaASTNode_t *root);
#endif

160
lexer/lexer.h Normal file
View File

@ -0,0 +1,160 @@
#ifndef RAVA_LEXER_H
#define RAVA_LEXER_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
typedef enum {
RAVA_TOKEN_EOF,
RAVA_TOKEN_KEYWORD_ABSTRACT,
RAVA_TOKEN_KEYWORD_ASSERT,
RAVA_TOKEN_KEYWORD_BOOLEAN,
RAVA_TOKEN_KEYWORD_BREAK,
RAVA_TOKEN_KEYWORD_BYTE,
RAVA_TOKEN_KEYWORD_CASE,
RAVA_TOKEN_KEYWORD_CATCH,
RAVA_TOKEN_KEYWORD_CHAR,
RAVA_TOKEN_KEYWORD_CLASS,
RAVA_TOKEN_KEYWORD_CONST,
RAVA_TOKEN_KEYWORD_CONTINUE,
RAVA_TOKEN_KEYWORD_DEFAULT,
RAVA_TOKEN_KEYWORD_DO,
RAVA_TOKEN_KEYWORD_DOUBLE,
RAVA_TOKEN_KEYWORD_ELSE,
RAVA_TOKEN_KEYWORD_ENUM,
RAVA_TOKEN_KEYWORD_EXTENDS,
RAVA_TOKEN_KEYWORD_FINAL,
RAVA_TOKEN_KEYWORD_FINALLY,
RAVA_TOKEN_KEYWORD_FLOAT,
RAVA_TOKEN_KEYWORD_FOR,
RAVA_TOKEN_KEYWORD_GOTO,
RAVA_TOKEN_KEYWORD_IF,
RAVA_TOKEN_KEYWORD_IMPLEMENTS,
RAVA_TOKEN_KEYWORD_IMPORT,
RAVA_TOKEN_KEYWORD_INSTANCEOF,
RAVA_TOKEN_KEYWORD_INT,
RAVA_TOKEN_KEYWORD_INTERFACE,
RAVA_TOKEN_KEYWORD_LONG,
RAVA_TOKEN_KEYWORD_NATIVE,
RAVA_TOKEN_KEYWORD_NEW,
RAVA_TOKEN_KEYWORD_PACKAGE,
RAVA_TOKEN_KEYWORD_PRIVATE,
RAVA_TOKEN_KEYWORD_PROTECTED,
RAVA_TOKEN_KEYWORD_PUBLIC,
RAVA_TOKEN_KEYWORD_RETURN,
RAVA_TOKEN_KEYWORD_SHORT,
RAVA_TOKEN_KEYWORD_STATIC,
RAVA_TOKEN_KEYWORD_STRICTFP,
RAVA_TOKEN_KEYWORD_SUPER,
RAVA_TOKEN_KEYWORD_SWITCH,
RAVA_TOKEN_KEYWORD_SYNCHRONIZED,
RAVA_TOKEN_KEYWORD_THIS,
RAVA_TOKEN_KEYWORD_THROW,
RAVA_TOKEN_KEYWORD_THROWS,
RAVA_TOKEN_KEYWORD_TRANSIENT,
RAVA_TOKEN_KEYWORD_TRY,
RAVA_TOKEN_KEYWORD_VOID,
RAVA_TOKEN_KEYWORD_VOLATILE,
RAVA_TOKEN_KEYWORD_WHILE,
RAVA_TOKEN_LITERAL_TRUE,
RAVA_TOKEN_LITERAL_FALSE,
RAVA_TOKEN_LITERAL_NULL,
RAVA_TOKEN_LITERAL_INTEGER,
RAVA_TOKEN_LITERAL_LONG,
RAVA_TOKEN_LITERAL_FLOAT,
RAVA_TOKEN_LITERAL_DOUBLE,
RAVA_TOKEN_LITERAL_CHARACTER,
RAVA_TOKEN_LITERAL_STRING,
RAVA_TOKEN_IDENTIFIER,
RAVA_TOKEN_LPAREN,
RAVA_TOKEN_RPAREN,
RAVA_TOKEN_LBRACE,
RAVA_TOKEN_RBRACE,
RAVA_TOKEN_LBRACKET,
RAVA_TOKEN_RBRACKET,
RAVA_TOKEN_SEMICOLON,
RAVA_TOKEN_COMMA,
RAVA_TOKEN_DOT,
RAVA_TOKEN_ELLIPSIS,
RAVA_TOKEN_AT,
RAVA_TOKEN_COLONCOLON,
RAVA_TOKEN_ASSIGN,
RAVA_TOKEN_GT,
RAVA_TOKEN_LT,
RAVA_TOKEN_BANG,
RAVA_TOKEN_TILDE,
RAVA_TOKEN_QUESTION,
RAVA_TOKEN_COLON,
RAVA_TOKEN_ARROW,
RAVA_TOKEN_EQUAL,
RAVA_TOKEN_GE,
RAVA_TOKEN_LE,
RAVA_TOKEN_NE,
RAVA_TOKEN_AND,
RAVA_TOKEN_OR,
RAVA_TOKEN_INC,
RAVA_TOKEN_DEC,
RAVA_TOKEN_PLUS,
RAVA_TOKEN_MINUS,
RAVA_TOKEN_STAR,
RAVA_TOKEN_SLASH,
RAVA_TOKEN_AMP,
RAVA_TOKEN_PIPE,
RAVA_TOKEN_CARET,
RAVA_TOKEN_PERCENT,
RAVA_TOKEN_LSHIFT,
RAVA_TOKEN_RSHIFT,
RAVA_TOKEN_URSHIFT,
RAVA_TOKEN_PLUSASSIGN,
RAVA_TOKEN_MINUSASSIGN,
RAVA_TOKEN_STARASSIGN,
RAVA_TOKEN_SLASHASSIGN,
RAVA_TOKEN_ANDASSIGN,
RAVA_TOKEN_ORASSIGN,
RAVA_TOKEN_CARETASSIGN,
RAVA_TOKEN_PERCENTASSIGN,
RAVA_TOKEN_LSHIFTASSIGN,
RAVA_TOKEN_RSHIFTASSIGN,
RAVA_TOKEN_URSHIFTASSIGN,
RAVA_TOKEN_ERROR
} RavaTokenType_e;
typedef union {
int64_t int_value;
double float_value;
char *string_value;
char char_value;
} RavaLiteralValue_u;
typedef struct {
RavaTokenType_e type;
char *lexeme;
int line;
int column;
RavaLiteralValue_u value;
} RavaToken_t;
typedef struct {
const char *source;
size_t source_length;
size_t current;
size_t start;
int line;
int column;
int start_column;
char *error_message;
} RavaLexer_t;
RavaLexer_t* rava_lexer_create(const char *source);
void rava_lexer_destroy(RavaLexer_t *lexer);
RavaToken_t* rava_lexer_next_token(RavaLexer_t *lexer);
void rava_token_destroy(RavaToken_t *token);
#endif

74
lexer/lexer_keywords.c Normal file
View File

@ -0,0 +1,74 @@
#include "lexer.h"
#include <string.h>
typedef struct {
const char *keyword;
RavaTokenType_e type;
} RavaKeyword_t;
static const RavaKeyword_t KEYWORDS[] = {
{"abstract", RAVA_TOKEN_KEYWORD_ABSTRACT},
{"assert", RAVA_TOKEN_KEYWORD_ASSERT},
{"boolean", RAVA_TOKEN_KEYWORD_BOOLEAN},
{"break", RAVA_TOKEN_KEYWORD_BREAK},
{"byte", RAVA_TOKEN_KEYWORD_BYTE},
{"case", RAVA_TOKEN_KEYWORD_CASE},
{"catch", RAVA_TOKEN_KEYWORD_CATCH},
{"char", RAVA_TOKEN_KEYWORD_CHAR},
{"class", RAVA_TOKEN_KEYWORD_CLASS},
{"const", RAVA_TOKEN_KEYWORD_CONST},
{"continue", RAVA_TOKEN_KEYWORD_CONTINUE},
{"default", RAVA_TOKEN_KEYWORD_DEFAULT},
{"do", RAVA_TOKEN_KEYWORD_DO},
{"double", RAVA_TOKEN_KEYWORD_DOUBLE},
{"else", RAVA_TOKEN_KEYWORD_ELSE},
{"enum", RAVA_TOKEN_KEYWORD_ENUM},
{"extends", RAVA_TOKEN_KEYWORD_EXTENDS},
{"false", RAVA_TOKEN_LITERAL_FALSE},
{"final", RAVA_TOKEN_KEYWORD_FINAL},
{"finally", RAVA_TOKEN_KEYWORD_FINALLY},
{"float", RAVA_TOKEN_KEYWORD_FLOAT},
{"for", RAVA_TOKEN_KEYWORD_FOR},
{"goto", RAVA_TOKEN_KEYWORD_GOTO},
{"if", RAVA_TOKEN_KEYWORD_IF},
{"implements", RAVA_TOKEN_KEYWORD_IMPLEMENTS},
{"import", RAVA_TOKEN_KEYWORD_IMPORT},
{"instanceof", RAVA_TOKEN_KEYWORD_INSTANCEOF},
{"int", RAVA_TOKEN_KEYWORD_INT},
{"interface", RAVA_TOKEN_KEYWORD_INTERFACE},
{"long", RAVA_TOKEN_KEYWORD_LONG},
{"native", RAVA_TOKEN_KEYWORD_NATIVE},
{"new", RAVA_TOKEN_KEYWORD_NEW},
{"null", RAVA_TOKEN_LITERAL_NULL},
{"package", RAVA_TOKEN_KEYWORD_PACKAGE},
{"private", RAVA_TOKEN_KEYWORD_PRIVATE},
{"protected", RAVA_TOKEN_KEYWORD_PROTECTED},
{"public", RAVA_TOKEN_KEYWORD_PUBLIC},
{"return", RAVA_TOKEN_KEYWORD_RETURN},
{"short", RAVA_TOKEN_KEYWORD_SHORT},
{"static", RAVA_TOKEN_KEYWORD_STATIC},
{"strictfp", RAVA_TOKEN_KEYWORD_STRICTFP},
{"super", RAVA_TOKEN_KEYWORD_SUPER},
{"switch", RAVA_TOKEN_KEYWORD_SWITCH},
{"synchronized", RAVA_TOKEN_KEYWORD_SYNCHRONIZED},
{"this", RAVA_TOKEN_KEYWORD_THIS},
{"throw", RAVA_TOKEN_KEYWORD_THROW},
{"throws", RAVA_TOKEN_KEYWORD_THROWS},
{"transient", RAVA_TOKEN_KEYWORD_TRANSIENT},
{"true", RAVA_TOKEN_LITERAL_TRUE},
{"try", RAVA_TOKEN_KEYWORD_TRY},
{"void", RAVA_TOKEN_KEYWORD_VOID},
{"volatile", RAVA_TOKEN_KEYWORD_VOLATILE},
{"while", RAVA_TOKEN_KEYWORD_WHILE},
};
static const size_t KEYWORDS_COUNT = sizeof(KEYWORDS) / sizeof(KEYWORDS[0]);
RavaTokenType_e rava_lexer_lookup_keyword(const char *identifier) {
for (size_t i = 0; i < KEYWORDS_COUNT; i++) {
if (strcmp(identifier, KEYWORDS[i].keyword) == 0) {
return KEYWORDS[i].type;
}
}
return RAVA_TOKEN_IDENTIFIER;
}

216
lexer/lexer_literals.c Normal file
View File

@ -0,0 +1,216 @@
#define _POSIX_C_SOURCE 200809L
#include "lexer.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
extern RavaToken_t* _rava_lexer_create_token(RavaLexer_t *lexer, RavaTokenType_e type);
extern char _rava_lexer_peek(RavaLexer_t *lexer);
extern char _rava_lexer_peek_next(RavaLexer_t *lexer);
extern char _rava_lexer_advance(RavaLexer_t *lexer);
extern bool _rava_lexer_is_at_end(RavaLexer_t *lexer);
static char _rava_unescape_char(char c) {
switch (c) {
case 'n': return '\n';
case 't': return '\t';
case 'r': return '\r';
case 'b': return '\b';
case 'f': return '\f';
case '\\': return '\\';
case '\'': return '\'';
case '"': return '"';
default: return c;
}
}
RavaToken_t* rava_lexer_parse_string(RavaLexer_t *lexer) {
size_t capacity = 128;
size_t length = 0;
char *str = malloc(capacity);
while (!_rava_lexer_is_at_end(lexer) && _rava_lexer_peek(lexer) != '"') {
char c = _rava_lexer_advance(lexer);
if (c == '\\') {
if (_rava_lexer_is_at_end(lexer)) {
free(str);
lexer->error_message = strdup("Unterminated string escape");
return _rava_lexer_create_token(lexer, RAVA_TOKEN_ERROR);
}
char next = _rava_lexer_advance(lexer);
if (next == 'u') {
int codepoint = 0;
for (int i = 0; i < 4; i++) {
if (_rava_lexer_is_at_end(lexer) || !isxdigit(_rava_lexer_peek(lexer))) {
free(str);
lexer->error_message = strdup("Invalid Unicode escape");
return _rava_lexer_create_token(lexer, RAVA_TOKEN_ERROR);
}
char hex = _rava_lexer_advance(lexer);
codepoint = codepoint * 16 + (isdigit(hex) ? hex - '0' : tolower(hex) - 'a' + 10);
}
if (codepoint < 128) {
c = (char)codepoint;
} else {
c = '?';
}
} else if (next >= '0' && next <= '7') {
int octal = next - '0';
if (!_rava_lexer_is_at_end(lexer) && _rava_lexer_peek(lexer) >= '0' && _rava_lexer_peek(lexer) <= '7') {
octal = octal * 8 + (_rava_lexer_advance(lexer) - '0');
if (!_rava_lexer_is_at_end(lexer) && _rava_lexer_peek(lexer) >= '0' && _rava_lexer_peek(lexer) <= '7') {
octal = octal * 8 + (_rava_lexer_advance(lexer) - '0');
}
}
c = (char)octal;
} else {
c = _rava_unescape_char(next);
}
}
if (length + 1 >= capacity) {
capacity *= 2;
str = realloc(str, capacity);
}
str[length++] = c;
}
if (_rava_lexer_is_at_end(lexer)) {
free(str);
lexer->error_message = strdup("Unterminated string");
return _rava_lexer_create_token(lexer, RAVA_TOKEN_ERROR);
}
_rava_lexer_advance(lexer);
str[length] = '\0';
RavaToken_t *token = _rava_lexer_create_token(lexer, RAVA_TOKEN_LITERAL_STRING);
token->value.string_value = str;
return token;
}
RavaToken_t* rava_lexer_parse_character(RavaLexer_t *lexer) {
if (_rava_lexer_is_at_end(lexer)) {
lexer->error_message = strdup("Unterminated character literal");
return _rava_lexer_create_token(lexer, RAVA_TOKEN_ERROR);
}
char c = _rava_lexer_advance(lexer);
if (c == '\\') {
if (_rava_lexer_is_at_end(lexer)) {
lexer->error_message = strdup("Unterminated character escape");
return _rava_lexer_create_token(lexer, RAVA_TOKEN_ERROR);
}
char next = _rava_lexer_advance(lexer);
c = _rava_unescape_char(next);
}
if (_rava_lexer_is_at_end(lexer) || _rava_lexer_peek(lexer) != '\'') {
lexer->error_message = strdup("Unterminated character literal");
return _rava_lexer_create_token(lexer, RAVA_TOKEN_ERROR);
}
_rava_lexer_advance(lexer);
RavaToken_t *token = _rava_lexer_create_token(lexer, RAVA_TOKEN_LITERAL_CHARACTER);
token->value.char_value = c;
return token;
}
RavaToken_t* rava_lexer_parse_number(RavaLexer_t *lexer) {
bool is_hex = false;
bool is_octal = false;
bool is_binary = false;
bool is_float = false;
bool has_exponent = false;
char first_char = lexer->source[lexer->start];
if (first_char == '0' && !_rava_lexer_is_at_end(lexer)) {
char next = _rava_lexer_peek(lexer);
if (next == 'x' || next == 'X') {
is_hex = true;
_rava_lexer_advance(lexer);
_rava_lexer_advance(lexer);
} else if (next == 'b' || next == 'B') {
is_binary = true;
_rava_lexer_advance(lexer);
_rava_lexer_advance(lexer);
} else if (next >= '0' && next <= '7') {
is_octal = true;
_rava_lexer_advance(lexer);
}
}
while (!_rava_lexer_is_at_end(lexer)) {
char c = _rava_lexer_peek(lexer);
if (is_hex && isxdigit(c)) {
_rava_lexer_advance(lexer);
} else if (is_binary && (c == '0' || c == '1')) {
_rava_lexer_advance(lexer);
} else if (is_octal && c >= '0' && c <= '7') {
_rava_lexer_advance(lexer);
} else if (!is_hex && !is_binary && !is_octal && isdigit(c)) {
_rava_lexer_advance(lexer);
} else if (c == '.' && !is_float && !is_hex && !is_binary && !is_octal) {
is_float = true;
_rava_lexer_advance(lexer);
} else if ((c == 'e' || c == 'E') && !has_exponent && !is_hex && !is_binary && !is_octal) {
is_float = true;
has_exponent = true;
_rava_lexer_advance(lexer);
if (!_rava_lexer_is_at_end(lexer) && (_rava_lexer_peek(lexer) == '+' || _rava_lexer_peek(lexer) == '-')) {
_rava_lexer_advance(lexer);
}
} else if (c == '_') {
_rava_lexer_advance(lexer);
} else {
break;
}
}
RavaTokenType_e type = RAVA_TOKEN_LITERAL_INTEGER;
if (!_rava_lexer_is_at_end(lexer)) {
char suffix = _rava_lexer_peek(lexer);
if (suffix == 'L' || suffix == 'l') {
type = RAVA_TOKEN_LITERAL_LONG;
_rava_lexer_advance(lexer);
} else if (suffix == 'F' || suffix == 'f') {
is_float = true;
type = RAVA_TOKEN_LITERAL_FLOAT;
_rava_lexer_advance(lexer);
} else if (suffix == 'D' || suffix == 'd') {
is_float = true;
type = RAVA_TOKEN_LITERAL_DOUBLE;
_rava_lexer_advance(lexer);
}
}
if (is_float && type == RAVA_TOKEN_LITERAL_INTEGER) {
type = RAVA_TOKEN_LITERAL_DOUBLE;
}
RavaToken_t *token = _rava_lexer_create_token(lexer, type);
if (is_float) {
token->value.float_value = strtod(token->lexeme, NULL);
} else {
char *endptr;
if (is_hex) {
token->value.int_value = strtoll(token->lexeme, &endptr, 16);
} else if (is_octal) {
token->value.int_value = strtoll(token->lexeme, &endptr, 8);
} else if (is_binary) {
token->value.int_value = strtoll(token->lexeme + 2, &endptr, 2);
} else {
token->value.int_value = strtoll(token->lexeme, &endptr, 10);
}
}
return token;
}

319
lexer/lexer_tokenizer.c Normal file
View File

@ -0,0 +1,319 @@
#include "lexer.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
extern RavaTokenType_e rava_lexer_lookup_keyword(const char *identifier);
extern RavaToken_t* rava_lexer_parse_string(RavaLexer_t *lexer);
extern RavaToken_t* rava_lexer_parse_character(RavaLexer_t *lexer);
extern RavaToken_t* rava_lexer_parse_number(RavaLexer_t *lexer);
RavaLexer_t* rava_lexer_create(const char *source) {
RavaLexer_t *lexer = malloc(sizeof(RavaLexer_t));
lexer->source = source;
lexer->source_length = strlen(source);
lexer->current = 0;
lexer->start = 0;
lexer->line = 1;
lexer->column = 1;
lexer->start_column = 1;
lexer->error_message = NULL;
return lexer;
}
void rava_lexer_destroy(RavaLexer_t *lexer) {
if (lexer) {
if (lexer->error_message) {
free(lexer->error_message);
}
free(lexer);
}
}
void rava_token_destroy(RavaToken_t *token) {
if (token) {
if (token->lexeme) {
free(token->lexeme);
}
if (token->type == RAVA_TOKEN_LITERAL_STRING && token->value.string_value) {
free(token->value.string_value);
}
free(token);
}
}
bool _rava_lexer_is_at_end(RavaLexer_t *lexer) {
return lexer->current >= lexer->source_length;
}
char _rava_lexer_peek(RavaLexer_t *lexer) {
if (_rava_lexer_is_at_end(lexer)) return '\0';
return lexer->source[lexer->current];
}
char _rava_lexer_peek_next(RavaLexer_t *lexer) {
if (lexer->current + 1 >= lexer->source_length) return '\0';
return lexer->source[lexer->current + 1];
}
char _rava_lexer_advance(RavaLexer_t *lexer) {
if (_rava_lexer_is_at_end(lexer)) return '\0';
char c = lexer->source[lexer->current++];
if (c == '\n') {
lexer->line++;
lexer->column = 1;
} else {
lexer->column++;
}
return c;
}
bool _rava_lexer_match(RavaLexer_t *lexer, char expected) {
if (_rava_lexer_is_at_end(lexer)) return false;
if (lexer->source[lexer->current] != expected) return false;
lexer->current++;
lexer->column++;
return true;
}
void _rava_lexer_skip_whitespace(RavaLexer_t *lexer) {
while (!_rava_lexer_is_at_end(lexer)) {
char c = _rava_lexer_peek(lexer);
switch (c) {
case ' ':
case '\t':
case '\r':
case '\n':
case '\f':
_rava_lexer_advance(lexer);
break;
case '/':
if (_rava_lexer_peek_next(lexer) == '/') {
while (!_rava_lexer_is_at_end(lexer) && _rava_lexer_peek(lexer) != '\n') {
_rava_lexer_advance(lexer);
}
} else if (_rava_lexer_peek_next(lexer) == '*') {
_rava_lexer_advance(lexer);
_rava_lexer_advance(lexer);
while (!_rava_lexer_is_at_end(lexer)) {
if (_rava_lexer_peek(lexer) == '*' && _rava_lexer_peek_next(lexer) == '/') {
_rava_lexer_advance(lexer);
_rava_lexer_advance(lexer);
break;
}
_rava_lexer_advance(lexer);
}
} else {
return;
}
break;
default:
return;
}
}
}
RavaToken_t* _rava_lexer_create_token(RavaLexer_t *lexer, RavaTokenType_e type) {
RavaToken_t *token = malloc(sizeof(RavaToken_t));
token->type = type;
size_t length = lexer->current - lexer->start;
token->lexeme = malloc(length + 1);
memcpy(token->lexeme, lexer->source + lexer->start, length);
token->lexeme[length] = '\0';
token->line = lexer->line;
token->column = lexer->start_column;
token->value.int_value = 0;
return token;
}
static bool _rava_is_alpha(char c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '$';
}
static bool _rava_is_alnum(char c) {
return _rava_is_alpha(c) || (c >= '0' && c <= '9');
}
static RavaToken_t* _rava_lexer_identifier(RavaLexer_t *lexer) {
while (_rava_is_alnum(_rava_lexer_peek(lexer))) {
_rava_lexer_advance(lexer);
}
RavaToken_t *token = _rava_lexer_create_token(lexer, RAVA_TOKEN_IDENTIFIER);
RavaTokenType_e keyword_type = rava_lexer_lookup_keyword(token->lexeme);
token->type = keyword_type;
if (keyword_type == RAVA_TOKEN_LITERAL_TRUE) {
token->value.int_value = 1;
} else if (keyword_type == RAVA_TOKEN_LITERAL_FALSE) {
token->value.int_value = 0;
}
return token;
}
RavaToken_t* rava_lexer_next_token(RavaLexer_t *lexer) {
_rava_lexer_skip_whitespace(lexer);
lexer->start = lexer->current;
lexer->start_column = lexer->column;
if (_rava_lexer_is_at_end(lexer)) {
return _rava_lexer_create_token(lexer, RAVA_TOKEN_EOF);
}
char c = _rava_lexer_advance(lexer);
if (_rava_is_alpha(c)) {
return _rava_lexer_identifier(lexer);
}
if (isdigit(c)) {
return rava_lexer_parse_number(lexer);
}
switch (c) {
case '(': return _rava_lexer_create_token(lexer, RAVA_TOKEN_LPAREN);
case ')': return _rava_lexer_create_token(lexer, RAVA_TOKEN_RPAREN);
case '{': return _rava_lexer_create_token(lexer, RAVA_TOKEN_LBRACE);
case '}': return _rava_lexer_create_token(lexer, RAVA_TOKEN_RBRACE);
case '[': return _rava_lexer_create_token(lexer, RAVA_TOKEN_LBRACKET);
case ']': return _rava_lexer_create_token(lexer, RAVA_TOKEN_RBRACKET);
case ';': return _rava_lexer_create_token(lexer, RAVA_TOKEN_SEMICOLON);
case ',': return _rava_lexer_create_token(lexer, RAVA_TOKEN_COMMA);
case '~': return _rava_lexer_create_token(lexer, RAVA_TOKEN_TILDE);
case '?': return _rava_lexer_create_token(lexer, RAVA_TOKEN_QUESTION);
case '@': return _rava_lexer_create_token(lexer, RAVA_TOKEN_AT);
case '.':
if (_rava_lexer_peek(lexer) == '.' && _rava_lexer_peek_next(lexer) == '.') {
_rava_lexer_advance(lexer);
_rava_lexer_advance(lexer);
return _rava_lexer_create_token(lexer, RAVA_TOKEN_ELLIPSIS);
}
return _rava_lexer_create_token(lexer, RAVA_TOKEN_DOT);
case ':':
if (_rava_lexer_match(lexer, ':')) {
return _rava_lexer_create_token(lexer, RAVA_TOKEN_COLONCOLON);
}
return _rava_lexer_create_token(lexer, RAVA_TOKEN_COLON);
case '+':
if (_rava_lexer_match(lexer, '+')) {
return _rava_lexer_create_token(lexer, RAVA_TOKEN_INC);
}
if (_rava_lexer_match(lexer, '=')) {
return _rava_lexer_create_token(lexer, RAVA_TOKEN_PLUSASSIGN);
}
return _rava_lexer_create_token(lexer, RAVA_TOKEN_PLUS);
case '-':
if (_rava_lexer_match(lexer, '-')) {
return _rava_lexer_create_token(lexer, RAVA_TOKEN_DEC);
}
if (_rava_lexer_match(lexer, '=')) {
return _rava_lexer_create_token(lexer, RAVA_TOKEN_MINUSASSIGN);
}
if (_rava_lexer_match(lexer, '>')) {
return _rava_lexer_create_token(lexer, RAVA_TOKEN_ARROW);
}
return _rava_lexer_create_token(lexer, RAVA_TOKEN_MINUS);
case '*':
if (_rava_lexer_match(lexer, '=')) {
return _rava_lexer_create_token(lexer, RAVA_TOKEN_STARASSIGN);
}
return _rava_lexer_create_token(lexer, RAVA_TOKEN_STAR);
case '/':
if (_rava_lexer_match(lexer, '=')) {
return _rava_lexer_create_token(lexer, RAVA_TOKEN_SLASHASSIGN);
}
return _rava_lexer_create_token(lexer, RAVA_TOKEN_SLASH);
case '%':
if (_rava_lexer_match(lexer, '=')) {
return _rava_lexer_create_token(lexer, RAVA_TOKEN_PERCENTASSIGN);
}
return _rava_lexer_create_token(lexer, RAVA_TOKEN_PERCENT);
case '&':
if (_rava_lexer_match(lexer, '&')) {
return _rava_lexer_create_token(lexer, RAVA_TOKEN_AND);
}
if (_rava_lexer_match(lexer, '=')) {
return _rava_lexer_create_token(lexer, RAVA_TOKEN_ANDASSIGN);
}
return _rava_lexer_create_token(lexer, RAVA_TOKEN_AMP);
case '|':
if (_rava_lexer_match(lexer, '|')) {
return _rava_lexer_create_token(lexer, RAVA_TOKEN_OR);
}
if (_rava_lexer_match(lexer, '=')) {
return _rava_lexer_create_token(lexer, RAVA_TOKEN_ORASSIGN);
}
return _rava_lexer_create_token(lexer, RAVA_TOKEN_PIPE);
case '^':
if (_rava_lexer_match(lexer, '=')) {
return _rava_lexer_create_token(lexer, RAVA_TOKEN_CARETASSIGN);
}
return _rava_lexer_create_token(lexer, RAVA_TOKEN_CARET);
case '!':
if (_rava_lexer_match(lexer, '=')) {
return _rava_lexer_create_token(lexer, RAVA_TOKEN_NE);
}
return _rava_lexer_create_token(lexer, RAVA_TOKEN_BANG);
case '=':
if (_rava_lexer_match(lexer, '=')) {
return _rava_lexer_create_token(lexer, RAVA_TOKEN_EQUAL);
}
return _rava_lexer_create_token(lexer, RAVA_TOKEN_ASSIGN);
case '<':
if (_rava_lexer_match(lexer, '<')) {
if (_rava_lexer_match(lexer, '=')) {
return _rava_lexer_create_token(lexer, RAVA_TOKEN_LSHIFTASSIGN);
}
return _rava_lexer_create_token(lexer, RAVA_TOKEN_LSHIFT);
}
if (_rava_lexer_match(lexer, '=')) {
return _rava_lexer_create_token(lexer, RAVA_TOKEN_LE);
}
return _rava_lexer_create_token(lexer, RAVA_TOKEN_LT);
case '>':
if (_rava_lexer_match(lexer, '>')) {
if (_rava_lexer_match(lexer, '>')) {
if (_rava_lexer_match(lexer, '=')) {
return _rava_lexer_create_token(lexer, RAVA_TOKEN_URSHIFTASSIGN);
}
return _rava_lexer_create_token(lexer, RAVA_TOKEN_URSHIFT);
}
if (_rava_lexer_match(lexer, '=')) {
return _rava_lexer_create_token(lexer, RAVA_TOKEN_RSHIFTASSIGN);
}
return _rava_lexer_create_token(lexer, RAVA_TOKEN_RSHIFT);
}
if (_rava_lexer_match(lexer, '=')) {
return _rava_lexer_create_token(lexer, RAVA_TOKEN_GE);
}
return _rava_lexer_create_token(lexer, RAVA_TOKEN_GT);
case '"':
return rava_lexer_parse_string(lexer);
case '\'':
return rava_lexer_parse_character(lexer);
default:
lexer->error_message = malloc(100);
snprintf(lexer->error_message, 100, "Unexpected character '%c'", c);
return _rava_lexer_create_token(lexer, RAVA_TOKEN_ERROR);
}
}

236
parser/parser.c Normal file
View File

@ -0,0 +1,236 @@
#define _POSIX_C_SOURCE 200809L
#include "parser.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
RavaASTNode_t* rava_ast_node_create(RavaASTNodeType_e type, int line, int column) {
RavaASTNode_t *node = calloc(1, sizeof(RavaASTNode_t));
node->type = type;
node->line = line;
node->column = column;
node->parent = NULL;
node->children = NULL;
node->children_count = 0;
node->children_capacity = 0;
return node;
}
void rava_ast_node_destroy(RavaASTNode_t *node) {
if (!node) return;
for (size_t i = 0; i < node->children_count; i++) {
rava_ast_node_destroy(node->children[i]);
}
free(node->children);
switch (node->type) {
case RAVA_AST_IDENTIFIER_EXPR:
free(node->data.identifier.name);
break;
case RAVA_AST_CLASS_DECL:
free(node->data.class_decl.name);
free(node->data.class_decl.modifiers);
rava_ast_node_destroy(node->data.class_decl.type);
break;
case RAVA_AST_METHOD_DECL:
free(node->data.method_decl.name);
free(node->data.method_decl.modifiers);
rava_ast_node_destroy(node->data.method_decl.return_type);
break;
case RAVA_AST_VAR_DECL:
free(node->data.var_decl.name);
rava_ast_node_destroy(node->data.var_decl.type);
rava_ast_node_destroy(node->data.var_decl.initializer);
break;
case RAVA_AST_TYPE:
free(node->data.type.type_name);
break;
case RAVA_AST_MEMBER_ACCESS_EXPR:
free(node->data.member_access.member);
rava_ast_node_destroy(node->data.member_access.object);
break;
case RAVA_AST_CALL_EXPR:
rava_ast_node_destroy(node->data.call.callee);
for (size_t i = 0; i < node->data.call.arguments_count; i++) {
rava_ast_node_destroy(node->data.call.arguments[i]);
}
free(node->data.call.arguments);
break;
case RAVA_AST_NEW_EXPR:
rava_ast_node_destroy(node->data.new_expr.type);
for (size_t i = 0; i < node->data.new_expr.arguments_count; i++) {
rava_ast_node_destroy(node->data.new_expr.arguments[i]);
}
free(node->data.new_expr.arguments);
break;
case RAVA_AST_LITERAL_EXPR:
if (node->data.literal.literal_type == RAVA_TOKEN_LITERAL_STRING) {
free(node->data.literal.value.string_value);
}
break;
default:
break;
}
free(node);
}
void rava_ast_node_add_child(RavaASTNode_t *parent, RavaASTNode_t *child) {
if (!parent || !child) return;
if (parent->children_count >= parent->children_capacity) {
size_t new_capacity = parent->children_capacity == 0 ? 4 : parent->children_capacity * 2;
parent->children = realloc(parent->children, sizeof(RavaASTNode_t*) * new_capacity);
parent->children_capacity = new_capacity;
}
parent->children[parent->children_count++] = child;
child->parent = parent;
}
RavaParser_t* rava_parser_create(RavaLexer_t *lexer) {
RavaParser_t *parser = malloc(sizeof(RavaParser_t));
parser->lexer = lexer;
parser->current_token = rava_lexer_next_token(lexer);
parser->peek_token = rava_lexer_next_token(lexer);
parser->error_message = NULL;
parser->had_error = false;
return parser;
}
void rava_parser_destroy(RavaParser_t *parser) {
if (!parser) return;
rava_token_destroy(parser->current_token);
rava_token_destroy(parser->peek_token);
free(parser->error_message);
free(parser);
}
void _rava_parser_advance(RavaParser_t *parser) {
rava_token_destroy(parser->current_token);
parser->current_token = parser->peek_token;
parser->peek_token = rava_lexer_next_token(parser->lexer);
}
bool _rava_parser_check(RavaParser_t *parser, RavaTokenType_e type) {
return parser->current_token->type == type;
}
bool _rava_parser_match(RavaParser_t *parser, RavaTokenType_e type) {
if (_rava_parser_check(parser, type)) {
_rava_parser_advance(parser);
return true;
}
return false;
}
bool _rava_parser_expect(RavaParser_t *parser, RavaTokenType_e type, const char *message) {
if (_rava_parser_check(parser, type)) {
_rava_parser_advance(parser);
return true;
}
parser->had_error = true;
if (parser->error_message) free(parser->error_message);
parser->error_message = malloc(256);
snprintf(parser->error_message, 256, "%s at line %d, column %d",
message, parser->current_token->line, parser->current_token->column);
return false;
}
extern RavaASTNode_t* _rava_parser_parse_type(RavaParser_t *parser);
extern RavaASTNode_t* _rava_parser_parse_expression(RavaParser_t *parser);
extern RavaASTNode_t* _rava_parser_parse_statement(RavaParser_t *parser);
extern RavaASTNode_t* _rava_parser_parse_block(RavaParser_t *parser);
static RavaModifier_e _rava_token_to_modifier(RavaTokenType_e type) {
switch (type) {
case RAVA_TOKEN_KEYWORD_PUBLIC: return RAVA_MODIFIER_PUBLIC;
case RAVA_TOKEN_KEYWORD_PRIVATE: return RAVA_MODIFIER_PRIVATE;
case RAVA_TOKEN_KEYWORD_PROTECTED: return RAVA_MODIFIER_PROTECTED;
case RAVA_TOKEN_KEYWORD_STATIC: return RAVA_MODIFIER_STATIC;
case RAVA_TOKEN_KEYWORD_FINAL: return RAVA_MODIFIER_FINAL;
case RAVA_TOKEN_KEYWORD_ABSTRACT: return RAVA_MODIFIER_ABSTRACT;
case RAVA_TOKEN_KEYWORD_NATIVE: return RAVA_MODIFIER_NATIVE;
case RAVA_TOKEN_KEYWORD_SYNCHRONIZED: return RAVA_MODIFIER_SYNCHRONIZED;
case RAVA_TOKEN_KEYWORD_TRANSIENT: return RAVA_MODIFIER_TRANSIENT;
case RAVA_TOKEN_KEYWORD_VOLATILE: return RAVA_MODIFIER_VOLATILE;
case RAVA_TOKEN_KEYWORD_STRICTFP: return RAVA_MODIFIER_STRICTFP;
default: return RAVA_MODIFIER_PUBLIC;
}
}
static bool _rava_is_modifier(RavaTokenType_e type) {
return type == RAVA_TOKEN_KEYWORD_PUBLIC ||
type == RAVA_TOKEN_KEYWORD_PRIVATE ||
type == RAVA_TOKEN_KEYWORD_PROTECTED ||
type == RAVA_TOKEN_KEYWORD_STATIC ||
type == RAVA_TOKEN_KEYWORD_FINAL ||
type == RAVA_TOKEN_KEYWORD_ABSTRACT ||
type == RAVA_TOKEN_KEYWORD_NATIVE ||
type == RAVA_TOKEN_KEYWORD_SYNCHRONIZED ||
type == RAVA_TOKEN_KEYWORD_TRANSIENT ||
type == RAVA_TOKEN_KEYWORD_VOLATILE ||
type == RAVA_TOKEN_KEYWORD_STRICTFP;
}
void _rava_parser_parse_modifiers(RavaParser_t *parser, RavaModifier_e **modifiers, size_t *count) {
size_t capacity = 4;
*modifiers = malloc(sizeof(RavaModifier_e) * capacity);
*count = 0;
while (_rava_is_modifier(parser->current_token->type)) {
if (*count >= capacity) {
capacity *= 2;
*modifiers = realloc(*modifiers, sizeof(RavaModifier_e) * capacity);
}
(*modifiers)[(*count)++] = _rava_token_to_modifier(parser->current_token->type);
_rava_parser_advance(parser);
}
}
RavaASTNode_t* _rava_parser_parse_type(RavaParser_t *parser) {
RavaASTNode_t *type_node = rava_ast_node_create(RAVA_AST_TYPE,
parser->current_token->line,
parser->current_token->column);
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER) ||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_INT) ||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_BOOLEAN) ||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_CHAR) ||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_BYTE) ||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_SHORT) ||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_LONG) ||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_FLOAT) ||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_DOUBLE) ||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_VOID)) {
type_node->data.type.type_name = strdup(parser->current_token->lexeme);
type_node->data.type.is_array = false;
type_node->data.type.array_dimensions = 0;
_rava_parser_advance(parser);
while (_rava_parser_check(parser, RAVA_TOKEN_LBRACKET)) {
if (parser->peek_token && parser->peek_token->type == RAVA_TOKEN_RBRACKET) {
_rava_parser_advance(parser);
_rava_parser_advance(parser);
type_node->data.type.is_array = true;
type_node->data.type.array_dimensions++;
} else {
break;
}
}
} else {
parser->had_error = true;
if (parser->error_message) free(parser->error_message);
parser->error_message = strdup("Expected type name");
rava_ast_node_destroy(type_node);
return NULL;
}
return type_node;
}
RavaASTNode_t* rava_parser_parse(RavaParser_t *parser);

251
parser/parser.h Normal file
View File

@ -0,0 +1,251 @@
#ifndef RAVA_PARSER_H
#define RAVA_PARSER_H
#include "../lexer/lexer.h"
#include <stddef.h>
#include <stdbool.h>
typedef enum {
RAVA_AST_COMPILATION_UNIT,
RAVA_AST_PACKAGE_DECL,
RAVA_AST_IMPORT_DECL,
RAVA_AST_CLASS_DECL,
RAVA_AST_INTERFACE_DECL,
RAVA_AST_ENUM_DECL,
RAVA_AST_FIELD_DECL,
RAVA_AST_METHOD_DECL,
RAVA_AST_CONSTRUCTOR_DECL,
RAVA_AST_INITIALIZER_BLOCK,
RAVA_AST_PARAM_DECL,
RAVA_AST_VAR_DECL,
RAVA_AST_BLOCK_STMT,
RAVA_AST_IF_STMT,
RAVA_AST_WHILE_STMT,
RAVA_AST_DO_WHILE_STMT,
RAVA_AST_FOR_STMT,
RAVA_AST_ENHANCED_FOR_STMT,
RAVA_AST_SWITCH_STMT,
RAVA_AST_CASE_STMT,
RAVA_AST_TRY_STMT,
RAVA_AST_CATCH_CLAUSE,
RAVA_AST_THROW_STMT,
RAVA_AST_RETURN_STMT,
RAVA_AST_BREAK_STMT,
RAVA_AST_CONTINUE_STMT,
RAVA_AST_EXPR_STMT,
RAVA_AST_EMPTY_STMT,
RAVA_AST_SYNCHRONIZED_STMT,
RAVA_AST_ASSERT_STMT,
RAVA_AST_LITERAL_EXPR,
RAVA_AST_IDENTIFIER_EXPR,
RAVA_AST_BINARY_EXPR,
RAVA_AST_UNARY_EXPR,
RAVA_AST_TERNARY_EXPR,
RAVA_AST_ASSIGN_EXPR,
RAVA_AST_CALL_EXPR,
RAVA_AST_MEMBER_ACCESS_EXPR,
RAVA_AST_ARRAY_ACCESS_EXPR,
RAVA_AST_NEW_EXPR,
RAVA_AST_CAST_EXPR,
RAVA_AST_INSTANCEOF_EXPR,
RAVA_AST_THIS_EXPR,
RAVA_AST_SUPER_EXPR,
RAVA_AST_CLASS_LITERAL_EXPR,
RAVA_AST_ARRAY_INIT_EXPR,
RAVA_AST_TYPE,
RAVA_AST_TYPE_PARAM,
RAVA_AST_MODIFIER
} RavaASTNodeType_e;
typedef enum {
RAVA_MODIFIER_PUBLIC,
RAVA_MODIFIER_PRIVATE,
RAVA_MODIFIER_PROTECTED,
RAVA_MODIFIER_STATIC,
RAVA_MODIFIER_FINAL,
RAVA_MODIFIER_ABSTRACT,
RAVA_MODIFIER_NATIVE,
RAVA_MODIFIER_SYNCHRONIZED,
RAVA_MODIFIER_TRANSIENT,
RAVA_MODIFIER_VOLATILE,
RAVA_MODIFIER_STRICTFP
} RavaModifier_e;
typedef enum {
RAVA_BINOP_ADD,
RAVA_BINOP_SUB,
RAVA_BINOP_MUL,
RAVA_BINOP_DIV,
RAVA_BINOP_MOD,
RAVA_BINOP_EQ,
RAVA_BINOP_NE,
RAVA_BINOP_LT,
RAVA_BINOP_LE,
RAVA_BINOP_GT,
RAVA_BINOP_GE,
RAVA_BINOP_AND,
RAVA_BINOP_OR,
RAVA_BINOP_BITAND,
RAVA_BINOP_BITOR,
RAVA_BINOP_BITXOR,
RAVA_BINOP_LSHIFT,
RAVA_BINOP_RSHIFT,
RAVA_BINOP_URSHIFT
} RavaBinaryOp_e;
typedef enum {
RAVA_UNOP_PLUS,
RAVA_UNOP_MINUS,
RAVA_UNOP_NOT,
RAVA_UNOP_BITNOT,
RAVA_UNOP_PREINC,
RAVA_UNOP_PREDEC,
RAVA_UNOP_POSTINC,
RAVA_UNOP_POSTDEC
} RavaUnaryOp_e;
typedef struct RavaASTNode_t RavaASTNode_t;
struct RavaASTNode_t {
RavaASTNodeType_e type;
int line;
int column;
RavaASTNode_t *parent;
RavaASTNode_t **children;
size_t children_count;
size_t children_capacity;
union {
struct {
char *name;
} identifier;
struct {
RavaTokenType_e literal_type;
RavaLiteralValue_u value;
} literal;
struct {
RavaBinaryOp_e op;
RavaASTNode_t *left;
RavaASTNode_t *right;
} binary;
struct {
RavaUnaryOp_e op;
RavaASTNode_t *operand;
} unary;
struct {
RavaASTNode_t *condition;
RavaASTNode_t *true_expr;
RavaASTNode_t *false_expr;
} ternary;
struct {
RavaASTNode_t *target;
RavaASTNode_t *value;
} assign;
struct {
char *name;
char *superclass;
RavaASTNode_t *type;
RavaModifier_e *modifiers;
size_t modifiers_count;
} class_decl;
struct {
char *name;
RavaASTNode_t *return_type;
RavaModifier_e *modifiers;
size_t modifiers_count;
} method_decl;
struct {
char *name;
RavaASTNode_t *type;
RavaASTNode_t *initializer;
} var_decl;
struct {
RavaASTNode_t *condition;
RavaASTNode_t *then_stmt;
RavaASTNode_t *else_stmt;
} if_stmt;
struct {
RavaASTNode_t *condition;
RavaASTNode_t *body;
} while_stmt;
struct {
RavaASTNode_t *init;
RavaASTNode_t *condition;
RavaASTNode_t *update;
RavaASTNode_t *body;
} for_stmt;
struct {
RavaASTNode_t *value;
} return_stmt;
struct {
char *type_name;
bool is_array;
int array_dimensions;
} type;
struct {
RavaASTNode_t *callee;
RavaASTNode_t **arguments;
size_t arguments_count;
} call;
struct {
RavaASTNode_t *object;
char *member;
} member_access;
struct {
RavaASTNode_t *array;
RavaASTNode_t *index;
} array_access;
struct {
RavaASTNode_t *type;
RavaASTNode_t **arguments;
size_t arguments_count;
} new_expr;
struct {
RavaASTNode_t *type;
RavaASTNode_t *expression;
} cast;
} data;
};
typedef struct {
RavaLexer_t *lexer;
RavaToken_t *current_token;
RavaToken_t *peek_token;
char *error_message;
bool had_error;
} RavaParser_t;
RavaParser_t* rava_parser_create(RavaLexer_t *lexer);
void rava_parser_destroy(RavaParser_t *parser);
RavaASTNode_t* rava_parser_parse(RavaParser_t *parser);
RavaASTNode_t* rava_ast_node_create(RavaASTNodeType_e type, int line, int column);
void rava_ast_node_destroy(RavaASTNode_t *node);
void rava_ast_node_add_child(RavaASTNode_t *parent, RavaASTNode_t *child);
#endif

View File

@ -0,0 +1,196 @@
#define _POSIX_C_SOURCE 200809L
#include "parser.h"
#include <stdlib.h>
#include <string.h>
extern void _rava_parser_advance(RavaParser_t *parser);
extern bool _rava_parser_check(RavaParser_t *parser, RavaTokenType_e type);
extern bool _rava_parser_match(RavaParser_t *parser, RavaTokenType_e type);
extern bool _rava_parser_expect(RavaParser_t *parser, RavaTokenType_e type, const char *message);
extern RavaASTNode_t* _rava_parser_parse_type(RavaParser_t *parser);
extern RavaASTNode_t* _rava_parser_parse_expression(RavaParser_t *parser);
extern RavaASTNode_t* _rava_parser_parse_block(RavaParser_t *parser);
extern void _rava_parser_parse_modifiers(RavaParser_t *parser, RavaModifier_e **modifiers, size_t *count);
static RavaASTNode_t* _rava_parser_parse_method_declaration(RavaParser_t *parser,
RavaModifier_e *modifiers,
size_t modifiers_count,
RavaASTNode_t *return_type) {
RavaASTNode_t *method = rava_ast_node_create(RAVA_AST_METHOD_DECL,
parser->current_token->line,
parser->current_token->column);
method->data.method_decl.modifiers = modifiers;
method->data.method_decl.modifiers_count = modifiers_count;
method->data.method_decl.return_type = return_type;
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
method->data.method_decl.name = strdup(parser->current_token->lexeme);
_rava_parser_advance(parser);
}
_rava_parser_expect(parser, RAVA_TOKEN_LPAREN, "Expected '(' after method name");
while (!_rava_parser_check(parser, RAVA_TOKEN_RPAREN) &&
!_rava_parser_check(parser, RAVA_TOKEN_EOF)) {
RavaASTNode_t *param_type = _rava_parser_parse_type(parser);
RavaASTNode_t *param = rava_ast_node_create(RAVA_AST_PARAM_DECL,
parser->current_token->line,
parser->current_token->column);
param->data.var_decl.type = param_type;
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
param->data.var_decl.name = strdup(parser->current_token->lexeme);
_rava_parser_advance(parser);
}
rava_ast_node_add_child(method, param);
if (!_rava_parser_match(parser, RAVA_TOKEN_COMMA)) {
break;
}
}
_rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after parameters");
if (_rava_parser_check(parser, RAVA_TOKEN_LBRACE)) {
RavaASTNode_t *body = _rava_parser_parse_block(parser);
rava_ast_node_add_child(method, body);
} else {
_rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' or '{' after method declaration");
}
return method;
}
RavaASTNode_t* _rava_parser_parse_class_declaration(RavaParser_t *parser) {
RavaModifier_e *modifiers = NULL;
size_t modifiers_count = 0;
_rava_parser_parse_modifiers(parser, &modifiers, &modifiers_count);
_rava_parser_expect(parser, RAVA_TOKEN_KEYWORD_CLASS, "Expected 'class' keyword");
RavaASTNode_t *class_decl = rava_ast_node_create(RAVA_AST_CLASS_DECL,
parser->current_token->line,
parser->current_token->column);
class_decl->data.class_decl.modifiers = modifiers;
class_decl->data.class_decl.modifiers_count = modifiers_count;
class_decl->data.class_decl.superclass = NULL;
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
class_decl->data.class_decl.name = strdup(parser->current_token->lexeme);
_rava_parser_advance(parser);
}
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_EXTENDS)) {
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
class_decl->data.class_decl.superclass = strdup(parser->current_token->lexeme);
_rava_parser_advance(parser);
}
}
_rava_parser_expect(parser, RAVA_TOKEN_LBRACE, "Expected '{' after class name");
while (!_rava_parser_check(parser, RAVA_TOKEN_RBRACE) &&
!_rava_parser_check(parser, RAVA_TOKEN_EOF)) {
RavaModifier_e *member_modifiers = NULL;
size_t member_modifiers_count = 0;
_rava_parser_parse_modifiers(parser, &member_modifiers, &member_modifiers_count);
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER) &&
strcmp(parser->current_token->lexeme, class_decl->data.class_decl.name) == 0) {
RavaASTNode_t *constructor = rava_ast_node_create(RAVA_AST_CONSTRUCTOR_DECL,
parser->current_token->line,
parser->current_token->column);
_rava_parser_advance(parser);
_rava_parser_expect(parser, RAVA_TOKEN_LPAREN, "Expected '(' after constructor name");
while (!_rava_parser_check(parser, RAVA_TOKEN_RPAREN) &&
!_rava_parser_check(parser, RAVA_TOKEN_EOF)) {
RavaASTNode_t *param_type = _rava_parser_parse_type(parser);
RavaASTNode_t *param = rava_ast_node_create(RAVA_AST_PARAM_DECL,
parser->current_token->line,
parser->current_token->column);
param->data.var_decl.type = param_type;
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
param->data.var_decl.name = strdup(parser->current_token->lexeme);
_rava_parser_advance(parser);
}
rava_ast_node_add_child(constructor, param);
if (!_rava_parser_match(parser, RAVA_TOKEN_COMMA)) {
break;
}
}
_rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after constructor parameters");
if (_rava_parser_check(parser, RAVA_TOKEN_LBRACE)) {
RavaASTNode_t *body = _rava_parser_parse_block(parser);
rava_ast_node_add_child(constructor, body);
}
rava_ast_node_add_child(class_decl, constructor);
free(member_modifiers);
continue;
}
RavaASTNode_t *member_type = _rava_parser_parse_type(parser);
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
char *name = strdup(parser->current_token->lexeme);
_rava_parser_advance(parser);
if (_rava_parser_check(parser, RAVA_TOKEN_LPAREN)) {
RavaASTNode_t *method = _rava_parser_parse_method_declaration(parser,
member_modifiers,
member_modifiers_count,
member_type);
method->data.method_decl.name = name;
rava_ast_node_add_child(class_decl, method);
} else {
RavaASTNode_t *field = rava_ast_node_create(RAVA_AST_FIELD_DECL,
parser->current_token->line,
parser->current_token->column);
field->data.var_decl.type = member_type;
field->data.var_decl.name = name;
if (_rava_parser_match(parser, RAVA_TOKEN_ASSIGN)) {
field->data.var_decl.initializer = _rava_parser_parse_expression(parser);
} else {
field->data.var_decl.initializer = NULL;
}
_rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after field declaration");
rava_ast_node_add_child(class_decl, field);
}
}
}
_rava_parser_expect(parser, RAVA_TOKEN_RBRACE, "Expected '}' after class body");
return class_decl;
}
RavaASTNode_t* rava_parser_parse(RavaParser_t *parser) {
RavaASTNode_t *root = rava_ast_node_create(RAVA_AST_COMPILATION_UNIT, 1, 1);
while (!_rava_parser_check(parser, RAVA_TOKEN_EOF)) {
if (parser->had_error) {
break;
}
RavaASTNode_t *decl = _rava_parser_parse_class_declaration(parser);
if (decl) {
rava_ast_node_add_child(root, decl);
}
}
return root;
}

433
parser/parser_expressions.c Normal file
View File

@ -0,0 +1,433 @@
#define _POSIX_C_SOURCE 200809L
#include "parser.h"
#include <stdlib.h>
#include <string.h>
extern void _rava_parser_advance(RavaParser_t *parser);
extern bool _rava_parser_check(RavaParser_t *parser, RavaTokenType_e type);
extern bool _rava_parser_match(RavaParser_t *parser, RavaTokenType_e type);
extern bool _rava_parser_expect(RavaParser_t *parser, RavaTokenType_e type, const char *message);
extern RavaASTNode_t* _rava_parser_parse_type(RavaParser_t *parser);
RavaASTNode_t* _rava_parser_parse_expression(RavaParser_t *parser);
static RavaASTNode_t* _rava_parser_parse_primary(RavaParser_t *parser) {
RavaASTNode_t *node = NULL;
if (_rava_parser_check(parser, RAVA_TOKEN_LITERAL_INTEGER) ||
_rava_parser_check(parser, RAVA_TOKEN_LITERAL_LONG) ||
_rava_parser_check(parser, RAVA_TOKEN_LITERAL_FLOAT) ||
_rava_parser_check(parser, RAVA_TOKEN_LITERAL_DOUBLE) ||
_rava_parser_check(parser, RAVA_TOKEN_LITERAL_STRING) ||
_rava_parser_check(parser, RAVA_TOKEN_LITERAL_CHARACTER) ||
_rava_parser_check(parser, RAVA_TOKEN_LITERAL_TRUE) ||
_rava_parser_check(parser, RAVA_TOKEN_LITERAL_FALSE) ||
_rava_parser_check(parser, RAVA_TOKEN_LITERAL_NULL)) {
node = rava_ast_node_create(RAVA_AST_LITERAL_EXPR,
parser->current_token->line,
parser->current_token->column);
node->data.literal.literal_type = parser->current_token->type;
node->data.literal.value = parser->current_token->value;
if (parser->current_token->type == RAVA_TOKEN_LITERAL_STRING) {
node->data.literal.value.string_value = strdup(parser->current_token->value.string_value);
}
_rava_parser_advance(parser);
return node;
}
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
node = rava_ast_node_create(RAVA_AST_IDENTIFIER_EXPR,
parser->current_token->line,
parser->current_token->column);
node->data.identifier.name = strdup(parser->current_token->lexeme);
_rava_parser_advance(parser);
return node;
}
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_THIS)) {
return rava_ast_node_create(RAVA_AST_THIS_EXPR,
parser->current_token->line,
parser->current_token->column);
}
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_SUPER)) {
return rava_ast_node_create(RAVA_AST_SUPER_EXPR,
parser->current_token->line,
parser->current_token->column);
}
if (_rava_parser_match(parser, RAVA_TOKEN_LPAREN)) {
RavaASTNode_t *expr = _rava_parser_parse_expression(parser);
_rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after expression");
return expr;
}
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_NEW)) {
node = rava_ast_node_create(RAVA_AST_NEW_EXPR,
parser->current_token->line,
parser->current_token->column);
node->data.new_expr.type = _rava_parser_parse_type(parser);
if (_rava_parser_match(parser, RAVA_TOKEN_LBRACKET)) {
size_t args_capacity = 4;
node->data.new_expr.arguments = malloc(sizeof(RavaASTNode_t*) * args_capacity);
node->data.new_expr.arguments_count = 0;
node->data.new_expr.arguments[node->data.new_expr.arguments_count++] =
_rava_parser_parse_expression(parser);
_rava_parser_expect(parser, RAVA_TOKEN_RBRACKET, "Expected ']' after array size");
while (_rava_parser_match(parser, RAVA_TOKEN_LBRACKET)) {
if (node->data.new_expr.arguments_count >= args_capacity) {
args_capacity *= 2;
node->data.new_expr.arguments = realloc(node->data.new_expr.arguments,
sizeof(RavaASTNode_t*) * args_capacity);
}
if (!_rava_parser_check(parser, RAVA_TOKEN_RBRACKET)) {
node->data.new_expr.arguments[node->data.new_expr.arguments_count++] =
_rava_parser_parse_expression(parser);
}
_rava_parser_expect(parser, RAVA_TOKEN_RBRACKET, "Expected ']'");
}
if (node->data.new_expr.type) {
node->data.new_expr.type->data.type.is_array = true;
node->data.new_expr.type->data.type.array_dimensions = (int)node->data.new_expr.arguments_count;
}
return node;
}
_rava_parser_expect(parser, RAVA_TOKEN_LPAREN, "Expected '(' or '[' after type in new expression");
size_t args_capacity = 4;
node->data.new_expr.arguments = malloc(sizeof(RavaASTNode_t*) * args_capacity);
node->data.new_expr.arguments_count = 0;
if (!_rava_parser_check(parser, RAVA_TOKEN_RPAREN)) {
do {
if (node->data.new_expr.arguments_count >= args_capacity) {
args_capacity *= 2;
node->data.new_expr.arguments = realloc(node->data.new_expr.arguments,
sizeof(RavaASTNode_t*) * args_capacity);
}
node->data.new_expr.arguments[node->data.new_expr.arguments_count++] =
_rava_parser_parse_expression(parser);
} while (_rava_parser_match(parser, RAVA_TOKEN_COMMA));
}
_rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after arguments");
return node;
}
parser->had_error = true;
return NULL;
}
static RavaASTNode_t* _rava_parser_parse_postfix(RavaParser_t *parser) {
RavaASTNode_t *expr = _rava_parser_parse_primary(parser);
while (true) {
if (_rava_parser_match(parser, RAVA_TOKEN_DOT)) {
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
RavaASTNode_t *member_access = rava_ast_node_create(RAVA_AST_MEMBER_ACCESS_EXPR,
parser->current_token->line,
parser->current_token->column);
member_access->data.member_access.object = expr;
member_access->data.member_access.member = strdup(parser->current_token->lexeme);
_rava_parser_advance(parser);
expr = member_access;
}
} else if (_rava_parser_match(parser, RAVA_TOKEN_LPAREN)) {
RavaASTNode_t *call = rava_ast_node_create(RAVA_AST_CALL_EXPR,
parser->current_token->line,
parser->current_token->column);
call->data.call.callee = expr;
size_t args_capacity = 4;
call->data.call.arguments = malloc(sizeof(RavaASTNode_t*) * args_capacity);
call->data.call.arguments_count = 0;
if (!_rava_parser_check(parser, RAVA_TOKEN_RPAREN)) {
do {
if (call->data.call.arguments_count >= args_capacity) {
args_capacity *= 2;
call->data.call.arguments = realloc(call->data.call.arguments,
sizeof(RavaASTNode_t*) * args_capacity);
}
call->data.call.arguments[call->data.call.arguments_count++] =
_rava_parser_parse_expression(parser);
} while (_rava_parser_match(parser, RAVA_TOKEN_COMMA));
}
_rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after arguments");
expr = call;
} else if (_rava_parser_match(parser, RAVA_TOKEN_LBRACKET)) {
RavaASTNode_t *array_access = rava_ast_node_create(RAVA_AST_ARRAY_ACCESS_EXPR,
parser->current_token->line,
parser->current_token->column);
array_access->data.array_access.array = expr;
array_access->data.array_access.index = _rava_parser_parse_expression(parser);
_rava_parser_expect(parser, RAVA_TOKEN_RBRACKET, "Expected ']' after array index");
expr = array_access;
} else if (_rava_parser_match(parser, RAVA_TOKEN_INC)) {
RavaASTNode_t *unary = rava_ast_node_create(RAVA_AST_UNARY_EXPR,
parser->current_token->line,
parser->current_token->column);
unary->data.unary.op = RAVA_UNOP_POSTINC;
unary->data.unary.operand = expr;
expr = unary;
} else if (_rava_parser_match(parser, RAVA_TOKEN_DEC)) {
RavaASTNode_t *unary = rava_ast_node_create(RAVA_AST_UNARY_EXPR,
parser->current_token->line,
parser->current_token->column);
unary->data.unary.op = RAVA_UNOP_POSTDEC;
unary->data.unary.operand = expr;
expr = unary;
} else {
break;
}
}
return expr;
}
static RavaASTNode_t* _rava_parser_parse_unary(RavaParser_t *parser) {
if (_rava_parser_match(parser, RAVA_TOKEN_PLUS)) {
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_UNARY_EXPR,
parser->current_token->line,
parser->current_token->column);
node->data.unary.op = RAVA_UNOP_PLUS;
node->data.unary.operand = _rava_parser_parse_unary(parser);
return node;
}
if (_rava_parser_match(parser, RAVA_TOKEN_MINUS)) {
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_UNARY_EXPR,
parser->current_token->line,
parser->current_token->column);
node->data.unary.op = RAVA_UNOP_MINUS;
node->data.unary.operand = _rava_parser_parse_unary(parser);
return node;
}
if (_rava_parser_match(parser, RAVA_TOKEN_BANG)) {
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_UNARY_EXPR,
parser->current_token->line,
parser->current_token->column);
node->data.unary.op = RAVA_UNOP_NOT;
node->data.unary.operand = _rava_parser_parse_unary(parser);
return node;
}
if (_rava_parser_match(parser, RAVA_TOKEN_TILDE)) {
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_UNARY_EXPR,
parser->current_token->line,
parser->current_token->column);
node->data.unary.op = RAVA_UNOP_BITNOT;
node->data.unary.operand = _rava_parser_parse_unary(parser);
return node;
}
if (_rava_parser_match(parser, RAVA_TOKEN_INC)) {
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_UNARY_EXPR,
parser->current_token->line,
parser->current_token->column);
node->data.unary.op = RAVA_UNOP_PREINC;
node->data.unary.operand = _rava_parser_parse_unary(parser);
return node;
}
if (_rava_parser_match(parser, RAVA_TOKEN_DEC)) {
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_UNARY_EXPR,
parser->current_token->line,
parser->current_token->column);
node->data.unary.op = RAVA_UNOP_PREDEC;
node->data.unary.operand = _rava_parser_parse_unary(parser);
return node;
}
return _rava_parser_parse_postfix(parser);
}
static RavaASTNode_t* _rava_parser_parse_multiplicative(RavaParser_t *parser) {
RavaASTNode_t *left = _rava_parser_parse_unary(parser);
while (_rava_parser_check(parser, RAVA_TOKEN_STAR) ||
_rava_parser_check(parser, RAVA_TOKEN_SLASH) ||
_rava_parser_check(parser, RAVA_TOKEN_PERCENT)) {
RavaBinaryOp_e op;
if (_rava_parser_match(parser, RAVA_TOKEN_STAR)) {
op = RAVA_BINOP_MUL;
} else if (_rava_parser_match(parser, RAVA_TOKEN_SLASH)) {
op = RAVA_BINOP_DIV;
} else {
_rava_parser_advance(parser);
op = RAVA_BINOP_MOD;
}
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_BINARY_EXPR,
parser->current_token->line,
parser->current_token->column);
node->data.binary.op = op;
node->data.binary.left = left;
node->data.binary.right = _rava_parser_parse_unary(parser);
left = node;
}
return left;
}
static RavaASTNode_t* _rava_parser_parse_additive(RavaParser_t *parser) {
RavaASTNode_t *left = _rava_parser_parse_multiplicative(parser);
while (_rava_parser_check(parser, RAVA_TOKEN_PLUS) ||
_rava_parser_check(parser, RAVA_TOKEN_MINUS)) {
RavaBinaryOp_e op = _rava_parser_match(parser, RAVA_TOKEN_PLUS) ?
RAVA_BINOP_ADD : RAVA_BINOP_SUB;
if (op == RAVA_BINOP_SUB) _rava_parser_advance(parser);
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_BINARY_EXPR,
parser->current_token->line,
parser->current_token->column);
node->data.binary.op = op;
node->data.binary.left = left;
node->data.binary.right = _rava_parser_parse_multiplicative(parser);
left = node;
}
return left;
}
static RavaASTNode_t* _rava_parser_parse_relational(RavaParser_t *parser) {
RavaASTNode_t *left = _rava_parser_parse_additive(parser);
while (_rava_parser_check(parser, RAVA_TOKEN_LT) ||
_rava_parser_check(parser, RAVA_TOKEN_GT) ||
_rava_parser_check(parser, RAVA_TOKEN_LE) ||
_rava_parser_check(parser, RAVA_TOKEN_GE)) {
RavaBinaryOp_e op;
if (_rava_parser_match(parser, RAVA_TOKEN_LT)) op = RAVA_BINOP_LT;
else if (_rava_parser_match(parser, RAVA_TOKEN_GT)) op = RAVA_BINOP_GT;
else if (_rava_parser_match(parser, RAVA_TOKEN_LE)) op = RAVA_BINOP_LE;
else { _rava_parser_advance(parser); op = RAVA_BINOP_GE; }
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_BINARY_EXPR,
parser->current_token->line,
parser->current_token->column);
node->data.binary.op = op;
node->data.binary.left = left;
node->data.binary.right = _rava_parser_parse_additive(parser);
left = node;
}
return left;
}
static RavaASTNode_t* _rava_parser_parse_equality(RavaParser_t *parser) {
RavaASTNode_t *left = _rava_parser_parse_relational(parser);
while (_rava_parser_check(parser, RAVA_TOKEN_EQUAL) ||
_rava_parser_check(parser, RAVA_TOKEN_NE)) {
RavaBinaryOp_e op = _rava_parser_match(parser, RAVA_TOKEN_EQUAL) ?
RAVA_BINOP_EQ : RAVA_BINOP_NE;
if (op == RAVA_BINOP_NE) _rava_parser_advance(parser);
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_BINARY_EXPR,
parser->current_token->line,
parser->current_token->column);
node->data.binary.op = op;
node->data.binary.left = left;
node->data.binary.right = _rava_parser_parse_relational(parser);
left = node;
}
return left;
}
static RavaASTNode_t* _rava_parser_parse_logical_and(RavaParser_t *parser) {
RavaASTNode_t *left = _rava_parser_parse_equality(parser);
while (_rava_parser_match(parser, RAVA_TOKEN_AND)) {
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_BINARY_EXPR,
parser->current_token->line,
parser->current_token->column);
node->data.binary.op = RAVA_BINOP_AND;
node->data.binary.left = left;
node->data.binary.right = _rava_parser_parse_equality(parser);
left = node;
}
return left;
}
static RavaASTNode_t* _rava_parser_parse_logical_or(RavaParser_t *parser) {
RavaASTNode_t *left = _rava_parser_parse_logical_and(parser);
while (_rava_parser_match(parser, RAVA_TOKEN_OR)) {
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_BINARY_EXPR,
parser->current_token->line,
parser->current_token->column);
node->data.binary.op = RAVA_BINOP_OR;
node->data.binary.left = left;
node->data.binary.right = _rava_parser_parse_logical_and(parser);
left = node;
}
return left;
}
static RavaASTNode_t* _rava_parser_parse_assignment(RavaParser_t *parser) {
RavaASTNode_t *left = _rava_parser_parse_logical_or(parser);
if (_rava_parser_match(parser, RAVA_TOKEN_ASSIGN)) {
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_ASSIGN_EXPR,
parser->current_token->line,
parser->current_token->column);
node->data.assign.target = left;
node->data.assign.value = _rava_parser_parse_assignment(parser);
return node;
}
RavaBinaryOp_e compound_op = -1;
if (_rava_parser_match(parser, RAVA_TOKEN_PLUSASSIGN)) {
compound_op = RAVA_BINOP_ADD;
} else if (_rava_parser_match(parser, RAVA_TOKEN_MINUSASSIGN)) {
compound_op = RAVA_BINOP_SUB;
} else if (_rava_parser_match(parser, RAVA_TOKEN_STARASSIGN)) {
compound_op = RAVA_BINOP_MUL;
} else if (_rava_parser_match(parser, RAVA_TOKEN_SLASHASSIGN)) {
compound_op = RAVA_BINOP_DIV;
} else if (_rava_parser_match(parser, RAVA_TOKEN_PERCENTASSIGN)) {
compound_op = RAVA_BINOP_MOD;
}
if (compound_op != (RavaBinaryOp_e)-1) {
RavaASTNode_t *binary = rava_ast_node_create(RAVA_AST_BINARY_EXPR,
parser->current_token->line,
parser->current_token->column);
binary->data.binary.op = compound_op;
binary->data.binary.left = left;
binary->data.binary.right = _rava_parser_parse_assignment(parser);
RavaASTNode_t *assign = rava_ast_node_create(RAVA_AST_ASSIGN_EXPR,
parser->current_token->line,
parser->current_token->column);
assign->data.assign.target = left;
assign->data.assign.value = binary;
return assign;
}
return left;
}
RavaASTNode_t* _rava_parser_parse_expression(RavaParser_t *parser) {
return _rava_parser_parse_assignment(parser);
}

216
parser/parser_printer.c Normal file
View File

@ -0,0 +1,216 @@
#include "parser.h"
#include <stdio.h>
#include <string.h>
static void _rava_print_indent(int depth) {
for (int i = 0; i < depth; i++) {
printf(" ");
}
}
static const char* _rava_ast_node_type_name(RavaASTNodeType_e type) {
switch (type) {
case RAVA_AST_COMPILATION_UNIT: return "CompilationUnit";
case RAVA_AST_CLASS_DECL: return "ClassDecl";
case RAVA_AST_METHOD_DECL: return "MethodDecl";
case RAVA_AST_FIELD_DECL: return "FieldDecl";
case RAVA_AST_CONSTRUCTOR_DECL: return "ConstructorDecl";
case RAVA_AST_VAR_DECL: return "VarDecl";
case RAVA_AST_PARAM_DECL: return "ParamDecl";
case RAVA_AST_BLOCK_STMT: return "BlockStmt";
case RAVA_AST_IF_STMT: return "IfStmt";
case RAVA_AST_WHILE_STMT: return "WhileStmt";
case RAVA_AST_FOR_STMT: return "ForStmt";
case RAVA_AST_RETURN_STMT: return "ReturnStmt";
case RAVA_AST_BREAK_STMT: return "BreakStmt";
case RAVA_AST_CONTINUE_STMT: return "ContinueStmt";
case RAVA_AST_EXPR_STMT: return "ExprStmt";
case RAVA_AST_LITERAL_EXPR: return "LiteralExpr";
case RAVA_AST_IDENTIFIER_EXPR: return "IdentifierExpr";
case RAVA_AST_BINARY_EXPR: return "BinaryExpr";
case RAVA_AST_UNARY_EXPR: return "UnaryExpr";
case RAVA_AST_ASSIGN_EXPR: return "AssignExpr";
case RAVA_AST_CALL_EXPR: return "CallExpr";
case RAVA_AST_MEMBER_ACCESS_EXPR: return "MemberAccessExpr";
case RAVA_AST_ARRAY_ACCESS_EXPR: return "ArrayAccessExpr";
case RAVA_AST_NEW_EXPR: return "NewExpr";
case RAVA_AST_TYPE: return "Type";
default: return "Unknown";
}
}
void rava_ast_print(RavaASTNode_t *node, int depth) {
if (!node) {
_rava_print_indent(depth);
printf("<null>\n");
return;
}
_rava_print_indent(depth);
printf("%s", _rava_ast_node_type_name(node->type));
switch (node->type) {
case RAVA_AST_CLASS_DECL:
printf(": %s\n", node->data.class_decl.name);
break;
case RAVA_AST_METHOD_DECL:
printf(": %s\n", node->data.method_decl.name);
break;
case RAVA_AST_FIELD_DECL:
case RAVA_AST_VAR_DECL:
case RAVA_AST_PARAM_DECL:
printf(": %s\n", node->data.var_decl.name ? node->data.var_decl.name : "<unnamed>");
break;
case RAVA_AST_IDENTIFIER_EXPR:
printf(": %s\n", node->data.identifier.name);
break;
case RAVA_AST_LITERAL_EXPR:
printf(": ");
if (node->data.literal.literal_type == RAVA_TOKEN_LITERAL_INTEGER ||
node->data.literal.literal_type == RAVA_TOKEN_LITERAL_LONG) {
printf("%lld\n", (long long)node->data.literal.value.int_value);
} else if (node->data.literal.literal_type == RAVA_TOKEN_LITERAL_FLOAT ||
node->data.literal.literal_type == RAVA_TOKEN_LITERAL_DOUBLE) {
printf("%f\n", node->data.literal.value.float_value);
} else if (node->data.literal.literal_type == RAVA_TOKEN_LITERAL_STRING) {
printf("\"%s\"\n", node->data.literal.value.string_value);
} else if (node->data.literal.literal_type == RAVA_TOKEN_LITERAL_TRUE) {
printf("true\n");
} else if (node->data.literal.literal_type == RAVA_TOKEN_LITERAL_FALSE) {
printf("false\n");
} else if (node->data.literal.literal_type == RAVA_TOKEN_LITERAL_NULL) {
printf("null\n");
} else {
printf("?\n");
}
break;
case RAVA_AST_TYPE:
printf(": %s%s\n", node->data.type.type_name,
node->data.type.is_array ? "[]" : "");
break;
case RAVA_AST_MEMBER_ACCESS_EXPR:
printf(": .%s\n", node->data.member_access.member);
break;
default:
printf("\n");
break;
}
if (node->type == RAVA_AST_BINARY_EXPR) {
_rava_print_indent(depth + 1);
printf("Left:\n");
rava_ast_print(node->data.binary.left, depth + 2);
_rava_print_indent(depth + 1);
printf("Right:\n");
rava_ast_print(node->data.binary.right, depth + 2);
} else if (node->type == RAVA_AST_UNARY_EXPR) {
_rava_print_indent(depth + 1);
printf("Operand:\n");
rava_ast_print(node->data.unary.operand, depth + 2);
} else if (node->type == RAVA_AST_ASSIGN_EXPR) {
_rava_print_indent(depth + 1);
printf("Target:\n");
rava_ast_print(node->data.assign.target, depth + 2);
_rava_print_indent(depth + 1);
printf("Value:\n");
rava_ast_print(node->data.assign.value, depth + 2);
} else if (node->type == RAVA_AST_IF_STMT) {
_rava_print_indent(depth + 1);
printf("Condition:\n");
rava_ast_print(node->data.if_stmt.condition, depth + 2);
_rava_print_indent(depth + 1);
printf("Then:\n");
rava_ast_print(node->data.if_stmt.then_stmt, depth + 2);
if (node->data.if_stmt.else_stmt) {
_rava_print_indent(depth + 1);
printf("Else:\n");
rava_ast_print(node->data.if_stmt.else_stmt, depth + 2);
}
} else if (node->type == RAVA_AST_WHILE_STMT) {
_rava_print_indent(depth + 1);
printf("Condition:\n");
rava_ast_print(node->data.while_stmt.condition, depth + 2);
_rava_print_indent(depth + 1);
printf("Body:\n");
rava_ast_print(node->data.while_stmt.body, depth + 2);
} else if (node->type == RAVA_AST_FOR_STMT) {
if (node->data.for_stmt.init) {
_rava_print_indent(depth + 1);
printf("Init:\n");
rava_ast_print(node->data.for_stmt.init, depth + 2);
}
if (node->data.for_stmt.condition) {
_rava_print_indent(depth + 1);
printf("Condition:\n");
rava_ast_print(node->data.for_stmt.condition, depth + 2);
}
if (node->data.for_stmt.update) {
_rava_print_indent(depth + 1);
printf("Update:\n");
rava_ast_print(node->data.for_stmt.update, depth + 2);
}
_rava_print_indent(depth + 1);
printf("Body:\n");
rava_ast_print(node->data.for_stmt.body, depth + 2);
} else if (node->type == RAVA_AST_RETURN_STMT) {
if (node->data.return_stmt.value) {
_rava_print_indent(depth + 1);
printf("Value:\n");
rava_ast_print(node->data.return_stmt.value, depth + 2);
}
} else if (node->type == RAVA_AST_VAR_DECL || node->type == RAVA_AST_FIELD_DECL || node->type == RAVA_AST_PARAM_DECL) {
if (node->data.var_decl.type) {
_rava_print_indent(depth + 1);
printf("Type:\n");
rava_ast_print(node->data.var_decl.type, depth + 2);
}
if (node->data.var_decl.initializer) {
_rava_print_indent(depth + 1);
printf("Initializer:\n");
rava_ast_print(node->data.var_decl.initializer, depth + 2);
}
} else if (node->type == RAVA_AST_METHOD_DECL) {
if (node->data.method_decl.return_type) {
_rava_print_indent(depth + 1);
printf("Return Type:\n");
rava_ast_print(node->data.method_decl.return_type, depth + 2);
}
} else if (node->type == RAVA_AST_CALL_EXPR) {
_rava_print_indent(depth + 1);
printf("Callee:\n");
rava_ast_print(node->data.call.callee, depth + 2);
if (node->data.call.arguments_count > 0) {
_rava_print_indent(depth + 1);
printf("Arguments:\n");
for (size_t i = 0; i < node->data.call.arguments_count; i++) {
rava_ast_print(node->data.call.arguments[i], depth + 2);
}
}
} else if (node->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
_rava_print_indent(depth + 1);
printf("Object:\n");
rava_ast_print(node->data.member_access.object, depth + 2);
} else if (node->type == RAVA_AST_ARRAY_ACCESS_EXPR) {
_rava_print_indent(depth + 1);
printf("Array:\n");
rava_ast_print(node->data.array_access.array, depth + 2);
_rava_print_indent(depth + 1);
printf("Index:\n");
rava_ast_print(node->data.array_access.index, depth + 2);
} else if (node->type == RAVA_AST_NEW_EXPR) {
_rava_print_indent(depth + 1);
printf("Type:\n");
rava_ast_print(node->data.new_expr.type, depth + 2);
if (node->data.new_expr.arguments_count > 0) {
_rava_print_indent(depth + 1);
printf("Arguments:\n");
for (size_t i = 0; i < node->data.new_expr.arguments_count; i++) {
rava_ast_print(node->data.new_expr.arguments[i], depth + 2);
}
}
}
for (size_t i = 0; i < node->children_count; i++) {
rava_ast_print(node->children[i], depth + 1);
}
}

216
parser/parser_statements.c Normal file
View File

@ -0,0 +1,216 @@
#define _POSIX_C_SOURCE 200809L
#include "parser.h"
#include <stdlib.h>
#include <string.h>
extern void _rava_parser_advance(RavaParser_t *parser);
extern bool _rava_parser_check(RavaParser_t *parser, RavaTokenType_e type);
extern bool _rava_parser_match(RavaParser_t *parser, RavaTokenType_e type);
extern bool _rava_parser_expect(RavaParser_t *parser, RavaTokenType_e type, const char *message);
extern RavaASTNode_t* _rava_parser_parse_expression(RavaParser_t *parser);
extern RavaASTNode_t* _rava_parser_parse_type(RavaParser_t *parser);
RavaASTNode_t* _rava_parser_parse_statement(RavaParser_t *parser);
RavaASTNode_t* _rava_parser_parse_block(RavaParser_t *parser);
RavaASTNode_t* _rava_parser_parse_block(RavaParser_t *parser) {
RavaASTNode_t *block = rava_ast_node_create(RAVA_AST_BLOCK_STMT,
parser->current_token->line,
parser->current_token->column);
_rava_parser_expect(parser, RAVA_TOKEN_LBRACE, "Expected '{' at start of block");
while (!_rava_parser_check(parser, RAVA_TOKEN_RBRACE) &&
!_rava_parser_check(parser, RAVA_TOKEN_EOF)) {
RavaASTNode_t *stmt = _rava_parser_parse_statement(parser);
if (stmt) {
rava_ast_node_add_child(block, stmt);
}
}
_rava_parser_expect(parser, RAVA_TOKEN_RBRACE, "Expected '}' at end of block");
return block;
}
RavaASTNode_t* _rava_parser_parse_statement(RavaParser_t *parser) {
if (_rava_parser_check(parser, RAVA_TOKEN_LBRACE)) {
return _rava_parser_parse_block(parser);
}
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_IF)) {
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_IF_STMT,
parser->current_token->line,
parser->current_token->column);
_rava_parser_expect(parser, RAVA_TOKEN_LPAREN, "Expected '(' after 'if'");
node->data.if_stmt.condition = _rava_parser_parse_expression(parser);
_rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after if condition");
node->data.if_stmt.then_stmt = _rava_parser_parse_statement(parser);
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_ELSE)) {
node->data.if_stmt.else_stmt = _rava_parser_parse_statement(parser);
} else {
node->data.if_stmt.else_stmt = NULL;
}
return node;
}
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_WHILE)) {
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_WHILE_STMT,
parser->current_token->line,
parser->current_token->column);
_rava_parser_expect(parser, RAVA_TOKEN_LPAREN, "Expected '(' after 'while'");
node->data.while_stmt.condition = _rava_parser_parse_expression(parser);
_rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after while condition");
node->data.while_stmt.body = _rava_parser_parse_statement(parser);
return node;
}
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_FOR)) {
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_FOR_STMT,
parser->current_token->line,
parser->current_token->column);
_rava_parser_expect(parser, RAVA_TOKEN_LPAREN, "Expected '(' after 'for'");
if (!_rava_parser_check(parser, RAVA_TOKEN_SEMICOLON)) {
bool is_type_decl = false;
if (_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_INT) ||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_LONG) ||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_DOUBLE) ||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_BOOLEAN) ||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_CHAR)) {
is_type_decl = true;
} else if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
if (parser->peek_token && parser->peek_token->type == RAVA_TOKEN_IDENTIFIER) {
is_type_decl = true;
}
}
if (is_type_decl) {
RavaASTNode_t *type = _rava_parser_parse_type(parser);
RavaASTNode_t *var_decl = rava_ast_node_create(RAVA_AST_VAR_DECL,
parser->current_token->line,
parser->current_token->column);
var_decl->data.var_decl.type = type;
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
var_decl->data.var_decl.name = strdup(parser->current_token->lexeme);
_rava_parser_advance(parser);
}
if (_rava_parser_match(parser, RAVA_TOKEN_ASSIGN)) {
var_decl->data.var_decl.initializer = _rava_parser_parse_expression(parser);
}
node->data.for_stmt.init = var_decl;
} else {
node->data.for_stmt.init = _rava_parser_parse_expression(parser);
}
} else {
node->data.for_stmt.init = NULL;
}
_rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after for init");
if (!_rava_parser_check(parser, RAVA_TOKEN_SEMICOLON)) {
node->data.for_stmt.condition = _rava_parser_parse_expression(parser);
} else {
node->data.for_stmt.condition = NULL;
}
_rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after for condition");
if (!_rava_parser_check(parser, RAVA_TOKEN_RPAREN)) {
node->data.for_stmt.update = _rava_parser_parse_expression(parser);
} else {
node->data.for_stmt.update = NULL;
}
_rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after for update");
node->data.for_stmt.body = _rava_parser_parse_statement(parser);
return node;
}
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_RETURN)) {
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_RETURN_STMT,
parser->current_token->line,
parser->current_token->column);
if (!_rava_parser_check(parser, RAVA_TOKEN_SEMICOLON)) {
node->data.return_stmt.value = _rava_parser_parse_expression(parser);
} else {
node->data.return_stmt.value = NULL;
}
_rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after return statement");
return node;
}
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_BREAK)) {
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_BREAK_STMT,
parser->current_token->line,
parser->current_token->column);
_rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after break");
return node;
}
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_CONTINUE)) {
RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_CONTINUE_STMT,
parser->current_token->line,
parser->current_token->column);
_rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after continue");
return node;
}
bool is_type_decl = false;
if (_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_INT) ||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_BOOLEAN) ||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_CHAR) ||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_BYTE) ||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_SHORT) ||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_LONG) ||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_FLOAT) ||
_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_DOUBLE)) {
is_type_decl = true;
} else if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
if (parser->peek_token && parser->peek_token->type == RAVA_TOKEN_IDENTIFIER) {
is_type_decl = true;
}
}
if (is_type_decl) {
RavaASTNode_t *type = _rava_parser_parse_type(parser);
RavaASTNode_t *var_decl = rava_ast_node_create(RAVA_AST_VAR_DECL,
parser->current_token->line,
parser->current_token->column);
var_decl->data.var_decl.type = type;
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
var_decl->data.var_decl.name = strdup(parser->current_token->lexeme);
_rava_parser_advance(parser);
}
if (_rava_parser_match(parser, RAVA_TOKEN_ASSIGN)) {
var_decl->data.var_decl.initializer = _rava_parser_parse_expression(parser);
} else {
var_decl->data.var_decl.initializer = NULL;
}
_rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after variable declaration");
return var_decl;
}
RavaASTNode_t *expr = _rava_parser_parse_expression(parser);
_rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after expression");
RavaASTNode_t *stmt = rava_ast_node_create(RAVA_AST_EXPR_STMT,
parser->current_token->line,
parser->current_token->column);
rava_ast_node_add_child(stmt, expr);
return stmt;
}

48
runtime/fastframe.c Normal file
View File

@ -0,0 +1,48 @@
#include "fastframe.h"
#include <string.h>
FastFrame_t rava_frame_pool[RAVA_MAX_CALL_DEPTH];
size_t rava_frame_depth = 0;
void rava_fastframe_init(void) {
rava_frame_depth = 0;
memset(rava_frame_pool, 0, sizeof(rava_frame_pool));
}
FastFrame_t* rava_fastframe_push(RavaMethod_t* method, int local_count) {
if (rava_frame_depth >= RAVA_MAX_CALL_DEPTH) {
return NULL;
}
FastFrame_t* frame = &rava_frame_pool[rava_frame_depth++];
frame->method = method;
frame->stack_top = 0;
frame->pc = 0;
frame->has_this = false;
frame->this_ref = rava_nanbox_null();
if (local_count > 0 && local_count <= RAVA_MAX_LOCALS_FIXED) {
memset(frame->locals, 0, (size_t)local_count * sizeof(RavaNanboxValue_t));
}
return frame;
}
void rava_fastframe_pop(void) {
if (rava_frame_depth > 0) {
rava_frame_depth--;
}
}
FastFrame_t* rava_fastframe_current(void) {
if (rava_frame_depth == 0) return NULL;
return &rava_frame_pool[rava_frame_depth - 1];
}
size_t rava_fastframe_get_depth(void) {
return rava_frame_depth;
}
void rava_fastframe_reset(void) {
rava_frame_depth = 0;
}

63
runtime/fastframe.h Normal file
View File

@ -0,0 +1,63 @@
#ifndef RAVA_FASTFRAME_H
#define RAVA_FASTFRAME_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "nanbox.h"
#include "../ir/ir.h"
#define RAVA_MAX_CALL_DEPTH 1024
#define RAVA_MAX_LOCALS_FIXED 64
#define RAVA_MAX_STACK_FIXED 512
typedef struct {
RavaMethod_t* method;
RavaNanboxValue_t locals[RAVA_MAX_LOCALS_FIXED];
RavaNanboxValue_t stack[RAVA_MAX_STACK_FIXED];
size_t stack_top;
size_t pc;
bool has_this;
RavaNanboxValue_t this_ref;
} FastFrame_t;
extern FastFrame_t rava_frame_pool[RAVA_MAX_CALL_DEPTH];
extern size_t rava_frame_depth;
void rava_fastframe_init(void);
FastFrame_t* rava_fastframe_push(RavaMethod_t* method, int local_count);
void rava_fastframe_pop(void);
FastFrame_t* rava_fastframe_current(void);
size_t rava_fastframe_get_depth(void);
void rava_fastframe_reset(void);
static inline void rava_fastframe_stack_push(FastFrame_t* frame, RavaNanboxValue_t v) {
if (frame->stack_top < RAVA_MAX_STACK_FIXED) {
frame->stack[frame->stack_top++] = v;
}
}
static inline RavaNanboxValue_t rava_fastframe_stack_pop(FastFrame_t* frame) {
if (frame->stack_top > 0) {
return frame->stack[--frame->stack_top];
}
return rava_nanbox_null();
}
static inline RavaNanboxValue_t rava_fastframe_stack_peek(FastFrame_t* frame) {
if (frame->stack_top > 0) {
return frame->stack[frame->stack_top - 1];
}
return rava_nanbox_null();
}
static inline void rava_fastframe_stack_clear(FastFrame_t* frame) {
frame->stack_top = 0;
}
static inline bool rava_fastframe_stack_is_empty(FastFrame_t* frame) {
return frame->stack_top == 0;
}
#endif

52
runtime/labeltable.c Normal file
View File

@ -0,0 +1,52 @@
#include "labeltable.h"
#include <stdlib.h>
#include <string.h>
LabelTable_t* rava_labeltable_create(RavaInstructionList_t* instructions) {
if (!instructions) return NULL;
LabelTable_t* table = malloc(sizeof(LabelTable_t));
if (!table) return NULL;
int max_label = 0;
for (size_t i = 0; i < instructions->count; i++) {
if (instructions->instructions[i].opcode == RAVA_OP_LABEL) {
int lid = instructions->instructions[i].operand.label_id;
if (lid > max_label) max_label = lid;
}
}
table->max_label_id = (size_t)max_label;
table->label_to_pc = calloc((size_t)(max_label + 1), sizeof(int));
if (!table->label_to_pc) {
free(table);
return NULL;
}
for (int i = 0; i <= max_label; i++) {
table->label_to_pc[i] = -1;
}
for (size_t i = 0; i < instructions->count; i++) {
if (instructions->instructions[i].opcode == RAVA_OP_LABEL) {
int lid = instructions->instructions[i].operand.label_id;
table->label_to_pc[lid] = (int)(i + 1);
}
}
return table;
}
void rava_labeltable_destroy(LabelTable_t* table) {
if (!table) return;
free(table->label_to_pc);
free(table);
}
size_t rava_labeltable_lookup(LabelTable_t* table, int label_id) {
if (!table || label_id < 0 || (size_t)label_id > table->max_label_id) {
return 0;
}
int pc = table->label_to_pc[label_id];
return (pc >= 0) ? (size_t)pc : 0;
}

17
runtime/labeltable.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef RAVA_LABELTABLE_H
#define RAVA_LABELTABLE_H
#include <stddef.h>
#include <stdint.h>
#include "../ir/ir.h"
typedef struct LabelTable_s {
int* label_to_pc;
size_t max_label_id;
} LabelTable_t;
LabelTable_t* rava_labeltable_create(RavaInstructionList_t* instructions);
void rava_labeltable_destroy(LabelTable_t* table);
size_t rava_labeltable_lookup(LabelTable_t* table, int label_id);
#endif

57
runtime/methodcache.c Normal file
View File

@ -0,0 +1,57 @@
#include "methodcache.h"
#include <stdlib.h>
#include <string.h>
MethodCache_t* rava_methodcache_create(void) {
MethodCache_t* cache = malloc(sizeof(MethodCache_t));
if (cache) {
memset(cache, 0, sizeof(MethodCache_t));
}
return cache;
}
void rava_methodcache_destroy(MethodCache_t* cache) {
if (cache) free(cache);
}
RavaMethod_t* rava_methodcache_lookup(MethodCache_t* cache,
const char* classname,
const char* methodname) {
if (!cache || !classname || !methodname) return NULL;
uint32_t class_hash = rava_methodcache_hash(classname);
uint32_t method_hash = rava_methodcache_hash(methodname);
uint32_t idx = (class_hash ^ method_hash) & RAVA_METHOD_CACHE_MASK;
MethodCacheEntry_t* entry = &cache->entries[idx];
if (entry->class_hash == class_hash &&
entry->method_hash == method_hash &&
entry->method != NULL) {
return entry->method;
}
return NULL;
}
void rava_methodcache_insert(MethodCache_t* cache,
const char* classname,
const char* methodname,
RavaMethod_t* method) {
if (!cache || !classname || !methodname) return;
uint32_t class_hash = rava_methodcache_hash(classname);
uint32_t method_hash = rava_methodcache_hash(methodname);
uint32_t idx = (class_hash ^ method_hash) & RAVA_METHOD_CACHE_MASK;
MethodCacheEntry_t* entry = &cache->entries[idx];
entry->class_hash = class_hash;
entry->method_hash = method_hash;
entry->method = method;
}
void rava_methodcache_clear(MethodCache_t* cache) {
if (cache) {
memset(cache->entries, 0, sizeof(cache->entries));
}
}

41
runtime/methodcache.h Normal file
View File

@ -0,0 +1,41 @@
#ifndef RAVA_METHODCACHE_H
#define RAVA_METHODCACHE_H
#include <stddef.h>
#include <stdint.h>
#include "../ir/ir.h"
#define RAVA_METHOD_CACHE_SIZE 256
#define RAVA_METHOD_CACHE_MASK (RAVA_METHOD_CACHE_SIZE - 1)
typedef struct {
uint32_t class_hash;
uint32_t method_hash;
RavaMethod_t* method;
} MethodCacheEntry_t;
typedef struct MethodCache_s {
MethodCacheEntry_t entries[RAVA_METHOD_CACHE_SIZE];
} MethodCache_t;
static inline uint32_t rava_methodcache_hash(const char* str) {
uint32_t hash = 5381;
while (*str) {
hash = ((hash << 5) + hash) ^ (uint32_t)*str;
str++;
}
return hash;
}
MethodCache_t* rava_methodcache_create(void);
void rava_methodcache_destroy(MethodCache_t* cache);
RavaMethod_t* rava_methodcache_lookup(MethodCache_t* cache,
const char* classname,
const char* methodname);
void rava_methodcache_insert(MethodCache_t* cache,
const char* classname,
const char* methodname,
RavaMethod_t* method);
void rava_methodcache_clear(MethodCache_t* cache);
#endif

156
runtime/nanbox.h Normal file
View File

@ -0,0 +1,156 @@
#ifndef RAVA_NANBOX_H
#define RAVA_NANBOX_H
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>
typedef uint64_t RavaNanboxValue_t;
#define RAVA_SIGN_BIT 0x8000000000000000ULL
#define RAVA_EXPONENT_MASK 0x7FF0000000000000ULL
#define RAVA_QNAN 0x7FF8000000000000ULL
#define RAVA_TAG_MASK 0xFFFF000000000000ULL
#define RAVA_PAYLOAD_MASK 0x0000FFFFFFFFFFFFULL
#define RAVA_TAG_INT (RAVA_QNAN | 0x0001000000000000ULL)
#define RAVA_TAG_LONG (RAVA_QNAN | 0x0002000000000000ULL)
#define RAVA_TAG_BOOL (RAVA_QNAN | 0x0003000000000000ULL)
#define RAVA_TAG_NULL (RAVA_QNAN | 0x0004000000000000ULL)
#define RAVA_TAG_OBJECT (RAVA_QNAN | 0x0005000000000000ULL)
#define RAVA_TAG_STRING (RAVA_QNAN | 0x0006000000000000ULL)
#define RAVA_TAG_ARRAY (RAVA_QNAN | 0x0007000000000000ULL)
static inline RavaNanboxValue_t rava_nanbox_int(int32_t v) {
return RAVA_TAG_INT | (uint64_t)(uint32_t)v;
}
static inline RavaNanboxValue_t rava_nanbox_long(int64_t v) {
return RAVA_TAG_LONG | ((uint64_t)v & RAVA_PAYLOAD_MASK);
}
static inline RavaNanboxValue_t rava_nanbox_bool(bool v) {
return RAVA_TAG_BOOL | (v ? 1ULL : 0ULL);
}
static inline RavaNanboxValue_t rava_nanbox_null(void) {
return RAVA_TAG_NULL;
}
static inline RavaNanboxValue_t rava_nanbox_double(double v) {
union { double d; uint64_t u; } u = {.d = v};
return u.u;
}
static inline RavaNanboxValue_t rava_nanbox_object(void* ptr) {
return RAVA_TAG_OBJECT | ((uint64_t)(uintptr_t)ptr & RAVA_PAYLOAD_MASK);
}
static inline RavaNanboxValue_t rava_nanbox_string(const char* ptr) {
return RAVA_TAG_STRING | ((uint64_t)(uintptr_t)ptr & RAVA_PAYLOAD_MASK);
}
static inline RavaNanboxValue_t rava_nanbox_array(void* ptr) {
return RAVA_TAG_ARRAY | ((uint64_t)(uintptr_t)ptr & RAVA_PAYLOAD_MASK);
}
static inline bool rava_nanbox_is_int(RavaNanboxValue_t v) {
return (v & RAVA_TAG_MASK) == RAVA_TAG_INT;
}
static inline bool rava_nanbox_is_long(RavaNanboxValue_t v) {
return (v & RAVA_TAG_MASK) == RAVA_TAG_LONG;
}
static inline bool rava_nanbox_is_bool(RavaNanboxValue_t v) {
return (v & RAVA_TAG_MASK) == RAVA_TAG_BOOL;
}
static inline bool rava_nanbox_is_null(RavaNanboxValue_t v) {
return v == RAVA_TAG_NULL;
}
static inline bool rava_nanbox_is_object(RavaNanboxValue_t v) {
return (v & RAVA_TAG_MASK) == RAVA_TAG_OBJECT;
}
static inline bool rava_nanbox_is_string(RavaNanboxValue_t v) {
return (v & RAVA_TAG_MASK) == RAVA_TAG_STRING;
}
static inline bool rava_nanbox_is_array(RavaNanboxValue_t v) {
return (v & RAVA_TAG_MASK) == RAVA_TAG_ARRAY;
}
static inline bool rava_nanbox_is_double(RavaNanboxValue_t v) {
return (v & RAVA_QNAN) != RAVA_QNAN;
}
static inline int32_t rava_nanbox_as_int(RavaNanboxValue_t v) {
return (int32_t)(v & 0xFFFFFFFF);
}
static inline int64_t rava_nanbox_as_long(RavaNanboxValue_t v) {
int64_t payload = (int64_t)(v & RAVA_PAYLOAD_MASK);
if (payload & 0x800000000000ULL) {
payload |= (int64_t)0xFFFF000000000000ULL;
}
return payload;
}
static inline bool rava_nanbox_as_bool(RavaNanboxValue_t v) {
return (v & 1) != 0;
}
static inline double rava_nanbox_as_double(RavaNanboxValue_t v) {
union { double d; uint64_t u; } u = {.u = v};
return u.d;
}
static inline void* rava_nanbox_as_object(RavaNanboxValue_t v) {
return (void*)(uintptr_t)(v & RAVA_PAYLOAD_MASK);
}
static inline const char* rava_nanbox_as_string(RavaNanboxValue_t v) {
return (const char*)(uintptr_t)(v & RAVA_PAYLOAD_MASK);
}
static inline void* rava_nanbox_as_array(RavaNanboxValue_t v) {
return (void*)(uintptr_t)(v & RAVA_PAYLOAD_MASK);
}
static inline int32_t rava_nanbox_to_int(RavaNanboxValue_t v) {
if (rava_nanbox_is_int(v)) return rava_nanbox_as_int(v);
if (rava_nanbox_is_long(v)) return (int32_t)rava_nanbox_as_long(v);
if (rava_nanbox_is_bool(v)) return rava_nanbox_as_bool(v) ? 1 : 0;
if (rava_nanbox_is_double(v)) return (int32_t)rava_nanbox_as_double(v);
return 0;
}
static inline int64_t rava_nanbox_to_long(RavaNanboxValue_t v) {
if (rava_nanbox_is_int(v)) return (int64_t)rava_nanbox_as_int(v);
if (rava_nanbox_is_long(v)) return rava_nanbox_as_long(v);
if (rava_nanbox_is_bool(v)) return rava_nanbox_as_bool(v) ? 1 : 0;
if (rava_nanbox_is_double(v)) return (int64_t)rava_nanbox_as_double(v);
return 0;
}
static inline double rava_nanbox_to_double(RavaNanboxValue_t v) {
if (rava_nanbox_is_double(v)) return rava_nanbox_as_double(v);
if (rava_nanbox_is_int(v)) return (double)rava_nanbox_as_int(v);
if (rava_nanbox_is_long(v)) return (double)rava_nanbox_as_long(v);
if (rava_nanbox_is_bool(v)) return rava_nanbox_as_bool(v) ? 1.0 : 0.0;
return 0.0;
}
static inline bool rava_nanbox_to_bool(RavaNanboxValue_t v) {
if (rava_nanbox_is_null(v)) return false;
if (rava_nanbox_is_bool(v)) return rava_nanbox_as_bool(v);
if (rava_nanbox_is_int(v)) return rava_nanbox_as_int(v) != 0;
if (rava_nanbox_is_long(v)) return rava_nanbox_as_long(v) != 0;
if (rava_nanbox_is_double(v)) return rava_nanbox_as_double(v) != 0.0;
return true;
}
#endif

2810
runtime/runtime.c Normal file

File diff suppressed because it is too large Load Diff

149
runtime/runtime.h Normal file
View File

@ -0,0 +1,149 @@
#ifndef RAVA_RUNTIME_H
#define RAVA_RUNTIME_H
#include "../ir/ir.h"
#include "../types/types.h"
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
typedef enum {
RAVA_VAL_INT,
RAVA_VAL_LONG,
RAVA_VAL_FLOAT,
RAVA_VAL_DOUBLE,
RAVA_VAL_BOOLEAN,
RAVA_VAL_CHAR,
RAVA_VAL_NULL,
RAVA_VAL_OBJECT,
RAVA_VAL_ARRAY,
RAVA_VAL_STRING
} RavaValueType_e;
typedef struct {
RavaValueType_e element_type;
size_t length;
void *data;
} RavaArray_t;
typedef struct RavaObject_t RavaObject_t;
typedef struct RavaValue_t RavaValue_t;
struct RavaObject_t {
char *class_name;
char **field_names;
RavaValue_t *field_values;
size_t field_count;
size_t field_capacity;
};
struct RavaValue_t {
RavaValueType_e type;
union {
int32_t int_val;
int64_t long_val;
float float_val;
double double_val;
bool bool_val;
char char_val;
RavaObject_t *object_val;
RavaArray_t *array_val;
char *string_val;
} data;
};
typedef struct {
RavaValue_t *values;
size_t capacity;
size_t top;
} RavaStack_t;
typedef struct {
RavaMethod_t *method;
RavaValue_t *locals;
size_t local_count;
size_t pc;
RavaStack_t *operand_stack;
RavaValue_t this_ref;
bool has_this;
} RavaCallFrame_t;
typedef struct {
RavaCallFrame_t **frames;
size_t capacity;
size_t count;
} RavaCallStack_t;
typedef struct {
char *class_name;
char *field_name;
RavaValue_t value;
} RavaStaticField_t;
typedef struct {
RavaStaticField_t *fields;
size_t count;
size_t capacity;
} RavaStaticFieldTable_t;
struct MethodCache_s;
typedef struct {
RavaProgram_t *program;
RavaCallStack_t *call_stack;
RavaStaticFieldTable_t *static_fields;
struct MethodCache_s *method_cache;
char *error_message;
bool had_error;
} RavaVM_t;
RavaValue_t rava_value_int(int32_t value);
RavaValue_t rava_value_long(int64_t value);
RavaValue_t rava_value_float(float value);
RavaValue_t rava_value_double(double value);
RavaValue_t rava_value_boolean(bool value);
RavaValue_t rava_value_null();
RavaValue_t rava_value_array(RavaArray_t *array);
RavaValue_t rava_value_string(const char *str);
int32_t rava_value_as_int(RavaValue_t value);
int64_t rava_value_as_long(RavaValue_t value);
double rava_value_as_double(RavaValue_t value);
bool rava_value_as_boolean(RavaValue_t value);
const char* rava_value_as_string(RavaValue_t value);
RavaArray_t* rava_array_create(RavaValueType_e element_type, size_t length);
void rava_array_destroy(RavaArray_t *array);
void rava_array_set_int(RavaArray_t *array, size_t index, int32_t value);
int32_t rava_array_get_int(RavaArray_t *array, size_t index);
size_t rava_array_length(RavaArray_t *array);
RavaObject_t* rava_object_create(const char *class_name);
void rava_object_destroy(RavaObject_t *obj);
void rava_object_set_field(RavaObject_t *obj, const char *name, RavaValue_t value);
RavaValue_t rava_object_get_field(RavaObject_t *obj, const char *name);
RavaValue_t rava_value_object(RavaObject_t *obj);
RavaStack_t* rava_stack_create(size_t capacity);
void rava_stack_destroy(RavaStack_t *stack);
void rava_stack_push(RavaStack_t *stack, RavaValue_t value);
RavaValue_t rava_stack_pop(RavaStack_t *stack);
RavaValue_t rava_stack_peek(RavaStack_t *stack);
bool rava_stack_is_empty(RavaStack_t *stack);
RavaCallFrame_t* rava_call_frame_create(RavaMethod_t *method);
void rava_call_frame_destroy(RavaCallFrame_t *frame);
RavaCallStack_t* rava_call_stack_create();
void rava_call_stack_destroy(RavaCallStack_t *stack);
void rava_call_stack_push(RavaCallStack_t *stack, RavaCallFrame_t *frame);
RavaCallFrame_t* rava_call_stack_pop(RavaCallStack_t *stack);
RavaCallFrame_t* rava_call_stack_current(RavaCallStack_t *stack);
RavaVM_t* rava_vm_create(RavaProgram_t *program);
void rava_vm_destroy(RavaVM_t *vm);
bool rava_vm_execute(RavaVM_t *vm, const char *class_name, const char *method_name);
RavaValue_t rava_vm_get_result(RavaVM_t *vm);
#endif

149
runtime/superinst.c Normal file
View File

@ -0,0 +1,149 @@
#include "superinst.h"
#include <string.h>
static void optimize_inc_dec_local(RavaInstruction_t *instrs, size_t count) {
for (size_t i = 0; i + 3 < count; i++) {
if (instrs[i].opcode == RAVA_OP_LOAD_LOCAL &&
instrs[i+1].opcode == RAVA_OP_LOAD_CONST &&
instrs[i+1].operand.int_value == 1 &&
instrs[i+2].opcode == RAVA_OP_ADD &&
instrs[i+3].opcode == RAVA_OP_STORE_LOCAL &&
instrs[i].operand.var.index == instrs[i+3].operand.var.index) {
instrs[i].opcode = RAVA_OP_INC_LOCAL;
instrs[i+1].opcode = RAVA_OP_NOP;
instrs[i+2].opcode = RAVA_OP_NOP;
instrs[i+3].opcode = RAVA_OP_NOP;
}
if (instrs[i].opcode == RAVA_OP_LOAD_LOCAL &&
instrs[i+1].opcode == RAVA_OP_LOAD_CONST &&
instrs[i+1].operand.int_value == 1 &&
instrs[i+2].opcode == RAVA_OP_SUB &&
instrs[i+3].opcode == RAVA_OP_STORE_LOCAL &&
instrs[i].operand.var.index == instrs[i+3].operand.var.index) {
instrs[i].opcode = RAVA_OP_DEC_LOCAL;
instrs[i+1].opcode = RAVA_OP_NOP;
instrs[i+2].opcode = RAVA_OP_NOP;
instrs[i+3].opcode = RAVA_OP_NOP;
}
}
}
static void optimize_loop_comparison(RavaInstruction_t *instrs, size_t count) {
for (size_t i = 0; i + 3 < count; i++) {
if (instrs[i].opcode == RAVA_OP_LOAD_LOCAL &&
instrs[i+1].opcode == RAVA_OP_LOAD_CONST &&
instrs[i+2].opcode == RAVA_OP_LT &&
instrs[i+3].opcode == RAVA_OP_JUMP_IF_FALSE) {
int local_idx = instrs[i].operand.var.index;
int64_t const_val = instrs[i+1].operand.int_value;
int label = instrs[i+3].operand.label_id;
instrs[i].opcode = RAVA_OP_LOAD_LOCAL_CONST_LT_JUMPFALSE;
instrs[i].operand.super.local_index = local_idx;
instrs[i].operand.super.const_value = const_val;
instrs[i].operand.super.label_id = label;
instrs[i+1].opcode = RAVA_OP_NOP;
instrs[i+2].opcode = RAVA_OP_NOP;
instrs[i+3].opcode = RAVA_OP_NOP;
}
if (instrs[i].opcode == RAVA_OP_LOAD_LOCAL &&
instrs[i+1].opcode == RAVA_OP_LOAD_CONST &&
instrs[i+2].opcode == RAVA_OP_LE &&
instrs[i+3].opcode == RAVA_OP_JUMP_IF_FALSE) {
int local_idx = instrs[i].operand.var.index;
int64_t const_val = instrs[i+1].operand.int_value;
int label = instrs[i+3].operand.label_id;
instrs[i].opcode = RAVA_OP_LOAD_LOCAL_CONST_LE_JUMPFALSE;
instrs[i].operand.super.local_index = local_idx;
instrs[i].operand.super.const_value = const_val;
instrs[i].operand.super.label_id = label;
instrs[i+1].opcode = RAVA_OP_NOP;
instrs[i+2].opcode = RAVA_OP_NOP;
instrs[i+3].opcode = RAVA_OP_NOP;
}
}
}
static void optimize_two_locals(RavaInstruction_t *instrs, size_t count) {
for (size_t i = 0; i + 1 < count; i++) {
if (instrs[i].opcode == RAVA_OP_LOAD_LOCAL &&
instrs[i+1].opcode == RAVA_OP_LOAD_LOCAL) {
int idx1 = instrs[i].operand.var.index;
int idx2 = instrs[i+1].operand.var.index;
instrs[i].opcode = RAVA_OP_LOAD_TWO_LOCALS;
instrs[i].operand.two_locals.index1 = idx1;
instrs[i].operand.two_locals.index2 = idx2;
instrs[i+1].opcode = RAVA_OP_NOP;
}
}
}
static void optimize_add_local_to_local(RavaInstruction_t *instrs, size_t count) {
for (size_t i = 0; i + 3 < count; i++) {
if (instrs[i].opcode == RAVA_OP_LOAD_LOCAL &&
instrs[i+1].opcode == RAVA_OP_LOAD_LOCAL &&
instrs[i+2].opcode == RAVA_OP_ADD &&
instrs[i+3].opcode == RAVA_OP_STORE_LOCAL &&
instrs[i].operand.var.index == instrs[i+3].operand.var.index) {
int dest_idx = instrs[i].operand.var.index;
int src_idx = instrs[i+1].operand.var.index;
instrs[i].opcode = RAVA_OP_ADD_LOCAL_TO_LOCAL;
instrs[i].operand.add_locals.dest_index = dest_idx;
instrs[i].operand.add_locals.src_index = src_idx;
instrs[i+1].opcode = RAVA_OP_NOP;
instrs[i+2].opcode = RAVA_OP_NOP;
instrs[i+3].opcode = RAVA_OP_NOP;
}
}
}
static void optimize_local_lt_local_jump(RavaInstruction_t *instrs, size_t count) {
for (size_t i = 0; i + 3 < count; i++) {
if (instrs[i].opcode == RAVA_OP_LOAD_LOCAL &&
instrs[i+1].opcode == RAVA_OP_LOAD_LOCAL &&
instrs[i+2].opcode == RAVA_OP_LT &&
instrs[i+3].opcode == RAVA_OP_JUMP_IF_FALSE) {
int local1 = instrs[i].operand.var.index;
int local2 = instrs[i+1].operand.var.index;
int label = instrs[i+3].operand.label_id;
instrs[i].opcode = RAVA_OP_LOAD_LOCAL_LT_LOCAL_JUMPFALSE;
instrs[i].operand.cmp_locals.local1 = local1;
instrs[i].operand.cmp_locals.local2 = local2;
instrs[i].operand.cmp_locals.label_id = label;
instrs[i+1].opcode = RAVA_OP_NOP;
instrs[i+2].opcode = RAVA_OP_NOP;
instrs[i+3].opcode = RAVA_OP_NOP;
}
}
}
void rava_optimize_superinstructions(RavaMethod_t* method) {
if (!method || !method->instructions) return;
RavaInstruction_t *instrs = method->instructions->instructions;
size_t count = method->instructions->count;
optimize_add_local_to_local(instrs, count);
optimize_local_lt_local_jump(instrs, count);
optimize_inc_dec_local(instrs, count);
optimize_loop_comparison(instrs, count);
optimize_two_locals(instrs, count);
}

8
runtime/superinst.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef RAVA_SUPERINST_H
#define RAVA_SUPERINST_H
#include "../ir/ir.h"
void rava_optimize_superinstructions(RavaMethod_t* method);
#endif

462
semantic/semantic.c Normal file
View File

@ -0,0 +1,462 @@
#define _POSIX_C_SOURCE 200809L
#include "semantic.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
static void _rava_semantic_error(RavaSemanticAnalyzer_t *analyzer, const char *message, int line, int col);
static bool _rava_semantic_analyze_node(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *node);
static RavaType_t* _rava_semantic_check_expression(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *expr);
RavaSemanticAnalyzer_t* rava_semantic_analyzer_create() {
RavaSemanticAnalyzer_t *analyzer = calloc(1, sizeof(RavaSemanticAnalyzer_t));
analyzer->symbol_table = rava_symbol_table_create();
analyzer->error_message = NULL;
analyzer->had_error = false;
analyzer->error_count = 0;
return analyzer;
}
void rava_semantic_analyzer_destroy(RavaSemanticAnalyzer_t *analyzer) {
if (!analyzer) return;
rava_symbol_table_destroy(analyzer->symbol_table);
free(analyzer->error_message);
free(analyzer);
}
static void _rava_semantic_error(RavaSemanticAnalyzer_t *analyzer, const char *message, int line, int col) {
analyzer->had_error = true;
analyzer->error_count++;
if (analyzer->error_message) free(analyzer->error_message);
analyzer->error_message = malloc(512);
snprintf(analyzer->error_message, 512, "Semantic error at line %d, column %d: %s",
line, col, message);
}
static RavaType_t* _rava_semantic_resolve_type(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *type_node) {
(void)analyzer;
if (!type_node || type_node->type != RAVA_AST_TYPE) return NULL;
RavaType_t *base_type = rava_type_from_name(type_node->data.type.type_name);
if (type_node->data.type.is_array) {
return rava_type_create_array(base_type, type_node->data.type.array_dimensions);
}
return base_type;
}
static bool _rava_semantic_analyze_class(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *class_node) {
if (class_node->type != RAVA_AST_CLASS_DECL) return false;
char *class_name = class_node->data.class_decl.name;
RavaType_t *class_type = rava_type_create_class(class_name);
RavaSymbol_t *class_symbol = rava_symbol_create(RAVA_SYMBOL_CLASS, class_name, class_type);
class_symbol->modifiers = class_node->data.class_decl.modifiers;
class_symbol->modifiers_count = class_node->data.class_decl.modifiers_count;
class_symbol->declaration = class_node;
if (!rava_symbol_table_define(analyzer->symbol_table, class_symbol)) {
_rava_semantic_error(analyzer, "Class already defined", class_node->line, class_node->column);
rava_symbol_destroy(class_symbol);
return false;
}
rava_symbol_table_enter_scope(analyzer->symbol_table, class_name);
for (size_t i = 0; i < class_node->children_count; i++) {
_rava_semantic_analyze_node(analyzer, class_node->children[i]);
}
rava_symbol_table_exit_scope(analyzer->symbol_table);
return !analyzer->had_error;
}
static bool _rava_semantic_analyze_method(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *method_node) {
if (method_node->type != RAVA_AST_METHOD_DECL) return false;
char *method_name = method_node->data.method_decl.name;
RavaType_t *return_type = _rava_semantic_resolve_type(analyzer, method_node->data.method_decl.return_type);
RavaSymbol_t *method_symbol = rava_symbol_create(RAVA_SYMBOL_METHOD, method_name, return_type);
method_symbol->modifiers = method_node->data.method_decl.modifiers;
method_symbol->modifiers_count = method_node->data.method_decl.modifiers_count;
method_symbol->declaration = method_node;
if (!rava_symbol_table_define(analyzer->symbol_table, method_symbol)) {
char error_msg[256];
snprintf(error_msg, sizeof(error_msg), "Method '%s' already defined", method_name);
_rava_semantic_error(analyzer, error_msg, method_node->line, method_node->column);
rava_symbol_destroy(method_symbol);
return false;
}
rava_symbol_table_enter_scope(analyzer->symbol_table, method_name);
for (size_t i = 0; i < method_node->children_count; i++) {
RavaASTNode_t *child = method_node->children[i];
if (child->type == RAVA_AST_PARAM_DECL) {
char *param_name = child->data.var_decl.name;
RavaType_t *param_type = _rava_semantic_resolve_type(analyzer, child->data.var_decl.type);
RavaSymbol_t *param_symbol = rava_symbol_create(RAVA_SYMBOL_PARAMETER, param_name, param_type);
param_symbol->declaration = child;
if (!rava_symbol_table_define(analyzer->symbol_table, param_symbol)) {
char error_msg[256];
snprintf(error_msg, sizeof(error_msg), "Parameter '%s' already defined", param_name);
_rava_semantic_error(analyzer, error_msg, child->line, child->column);
rava_symbol_destroy(param_symbol);
}
} else if (child->type == RAVA_AST_BLOCK_STMT) {
_rava_semantic_analyze_node(analyzer, child);
}
}
rava_symbol_table_exit_scope(analyzer->symbol_table);
return !analyzer->had_error;
}
static bool _rava_semantic_analyze_field(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *field_node) {
if (field_node->type != RAVA_AST_FIELD_DECL) return false;
char *field_name = field_node->data.var_decl.name;
RavaType_t *field_type = _rava_semantic_resolve_type(analyzer, field_node->data.var_decl.type);
RavaSymbol_t *field_symbol = rava_symbol_create(RAVA_SYMBOL_FIELD, field_name, field_type);
field_symbol->declaration = field_node;
if (!rava_symbol_table_define(analyzer->symbol_table, field_symbol)) {
char error_msg[256];
snprintf(error_msg, sizeof(error_msg), "Field '%s' already defined", field_name);
_rava_semantic_error(analyzer, error_msg, field_node->line, field_node->column);
rava_symbol_destroy(field_symbol);
return false;
}
if (field_node->data.var_decl.initializer) {
RavaType_t *init_type = _rava_semantic_check_expression(analyzer, field_node->data.var_decl.initializer);
if (init_type && !rava_type_is_assignable_to(init_type, field_type)) {
char error_msg[256];
snprintf(error_msg, sizeof(error_msg),
"Cannot assign '%s' to field of type '%s'",
rava_type_to_string(init_type),
rava_type_to_string(field_type));
_rava_semantic_error(analyzer, error_msg, field_node->line, field_node->column);
}
}
return !analyzer->had_error;
}
static bool _rava_semantic_analyze_var_decl(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *var_node) {
if (var_node->type != RAVA_AST_VAR_DECL) return false;
char *var_name = var_node->data.var_decl.name;
RavaType_t *var_type = _rava_semantic_resolve_type(analyzer, var_node->data.var_decl.type);
RavaSymbol_t *var_symbol = rava_symbol_create(RAVA_SYMBOL_VARIABLE, var_name, var_type);
var_symbol->declaration = var_node;
if (!rava_symbol_table_define(analyzer->symbol_table, var_symbol)) {
char error_msg[256];
snprintf(error_msg, sizeof(error_msg), "Variable '%s' already defined", var_name);
_rava_semantic_error(analyzer, error_msg, var_node->line, var_node->column);
rava_symbol_destroy(var_symbol);
return false;
}
if (var_node->data.var_decl.initializer) {
RavaType_t *init_type = _rava_semantic_check_expression(analyzer, var_node->data.var_decl.initializer);
if (init_type && !rava_type_is_assignable_to(init_type, var_type)) {
char error_msg[256];
snprintf(error_msg, sizeof(error_msg),
"Cannot assign '%s' to variable of type '%s'",
rava_type_to_string(init_type),
rava_type_to_string(var_type));
_rava_semantic_error(analyzer, error_msg, var_node->line, var_node->column);
}
}
return !analyzer->had_error;
}
static RavaType_t* _rava_semantic_check_expression(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *expr) {
if (!expr) return NULL;
switch (expr->type) {
case RAVA_AST_LITERAL_EXPR: {
switch (expr->data.literal.literal_type) {
case RAVA_TOKEN_LITERAL_INTEGER:
return rava_type_create_primitive(RAVA_TYPE_INT);
case RAVA_TOKEN_LITERAL_LONG:
return rava_type_create_primitive(RAVA_TYPE_LONG);
case RAVA_TOKEN_LITERAL_FLOAT:
return rava_type_create_primitive(RAVA_TYPE_FLOAT);
case RAVA_TOKEN_LITERAL_DOUBLE:
return rava_type_create_primitive(RAVA_TYPE_DOUBLE);
case RAVA_TOKEN_LITERAL_STRING:
return rava_type_create_class("String");
case RAVA_TOKEN_LITERAL_CHARACTER:
return rava_type_create_primitive(RAVA_TYPE_CHAR);
case RAVA_TOKEN_LITERAL_TRUE:
case RAVA_TOKEN_LITERAL_FALSE:
return rava_type_create_primitive(RAVA_TYPE_BOOLEAN);
case RAVA_TOKEN_LITERAL_NULL:
return rava_type_create_primitive(RAVA_TYPE_NULL);
default:
return NULL;
}
}
case RAVA_AST_IDENTIFIER_EXPR: {
char *name = expr->data.identifier.name;
if (strcmp(name, "System") == 0) {
return rava_type_from_name("System");
}
if (strcmp(name, "Files") == 0) {
return rava_type_from_name("Files");
}
RavaSymbol_t *symbol = rava_symbol_table_resolve(analyzer->symbol_table, name);
if (!symbol) {
char error_msg[256];
snprintf(error_msg, sizeof(error_msg), "Undefined identifier '%s'", name);
_rava_semantic_error(analyzer, error_msg, expr->line, expr->column);
return NULL;
}
return symbol->type;
}
case RAVA_AST_BINARY_EXPR: {
RavaType_t *left_type = _rava_semantic_check_expression(analyzer, expr->data.binary.left);
RavaType_t *right_type = _rava_semantic_check_expression(analyzer, expr->data.binary.right);
if (!left_type || !right_type) return NULL;
if (expr->data.binary.op >= RAVA_BINOP_EQ && expr->data.binary.op <= RAVA_BINOP_GE) {
return rava_type_create_primitive(RAVA_TYPE_BOOLEAN);
}
if (expr->data.binary.op == RAVA_BINOP_AND || expr->data.binary.op == RAVA_BINOP_OR) {
if (left_type->kind != RAVA_TYPE_BOOLEAN || right_type->kind != RAVA_TYPE_BOOLEAN) {
_rava_semantic_error(analyzer, "Logical operators require boolean operands",
expr->line, expr->column);
return NULL;
}
return rava_type_create_primitive(RAVA_TYPE_BOOLEAN);
}
return rava_type_binary_result(left_type, right_type);
}
case RAVA_AST_UNARY_EXPR: {
return _rava_semantic_check_expression(analyzer, expr->data.unary.operand);
}
case RAVA_AST_ASSIGN_EXPR: {
RavaType_t *target_type = _rava_semantic_check_expression(analyzer, expr->data.assign.target);
RavaType_t *value_type = _rava_semantic_check_expression(analyzer, expr->data.assign.value);
if (target_type && value_type && !rava_type_is_assignable_to(value_type, target_type)) {
char error_msg[256];
snprintf(error_msg, sizeof(error_msg),
"Cannot assign '%s' to '%s'",
rava_type_to_string(value_type),
rava_type_to_string(target_type));
_rava_semantic_error(analyzer, error_msg, expr->line, expr->column);
}
return target_type;
}
case RAVA_AST_CALL_EXPR: {
_rava_semantic_check_expression(analyzer, expr->data.call.callee);
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_MEMBER_ACCESS_EXPR) {
RavaASTNode_t *member = expr->data.call.callee;
const char *method = member->data.member_access.member;
if (member->data.member_access.object->type == RAVA_AST_IDENTIFIER_EXPR &&
strcmp(member->data.member_access.object->data.identifier.name, "Files") == 0) {
if (strcmp(method, "read") == 0) {
return rava_type_create_class("String");
} else if (strcmp(method, "write") == 0 || strcmp(method, "exists") == 0 ||
strcmp(method, "delete") == 0) {
return rava_type_create_primitive(RAVA_TYPE_BOOLEAN);
}
}
if (member->data.member_access.object->type == RAVA_AST_IDENTIFIER_EXPR &&
strcmp(member->data.member_access.object->data.identifier.name, "System") == 0) {
if (strcmp(method, "currentTimeMillis") == 0 || strcmp(method, "nanoTime") == 0) {
return rava_type_create_primitive(RAVA_TYPE_LONG);
}
}
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) {
return rava_type_create_primitive(RAVA_TYPE_BOOLEAN);
} else if (strcmp(method, "compareTo") == 0) {
return rava_type_create_primitive(RAVA_TYPE_INT);
}
}
return rava_type_create_primitive(RAVA_TYPE_INT);
}
case RAVA_AST_MEMBER_ACCESS_EXPR: {
_rava_semantic_check_expression(analyzer, expr->data.member_access.object);
return rava_type_create_primitive(RAVA_TYPE_INT);
}
case RAVA_AST_ARRAY_ACCESS_EXPR: {
RavaType_t *array_type = _rava_semantic_check_expression(analyzer, expr->data.array_access.array);
RavaType_t *index_type = _rava_semantic_check_expression(analyzer, expr->data.array_access.index);
if (index_type && index_type->kind != RAVA_TYPE_INT && index_type->kind != RAVA_TYPE_LONG) {
_rava_semantic_error(analyzer, "Array index must be an integer", expr->line, expr->column);
}
if (array_type && array_type->kind == RAVA_TYPE_ARRAY) {
return array_type->data.array.element_type;
}
return rava_type_create_primitive(RAVA_TYPE_INT);
}
case RAVA_AST_NEW_EXPR: {
RavaType_t *type = _rava_semantic_resolve_type(analyzer, expr->data.new_expr.type);
for (size_t i = 0; i < expr->data.new_expr.arguments_count; i++) {
RavaType_t *arg_type = _rava_semantic_check_expression(analyzer, expr->data.new_expr.arguments[i]);
if (type && type->kind == RAVA_TYPE_ARRAY && arg_type) {
if (arg_type->kind != RAVA_TYPE_INT && arg_type->kind != RAVA_TYPE_LONG) {
_rava_semantic_error(analyzer, "Array size must be an integer", expr->line, expr->column);
}
}
}
return type;
}
default:
return NULL;
}
}
static bool _rava_semantic_analyze_statement(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *stmt) {
if (!stmt) return true;
switch (stmt->type) {
case RAVA_AST_BLOCK_STMT:
for (size_t i = 0; i < stmt->children_count; i++) {
_rava_semantic_analyze_node(analyzer, stmt->children[i]);
}
return true;
case RAVA_AST_IF_STMT: {
RavaType_t *cond_type = _rava_semantic_check_expression(analyzer, stmt->data.if_stmt.condition);
if (cond_type && cond_type->kind != RAVA_TYPE_BOOLEAN) {
_rava_semantic_error(analyzer, "If condition must be boolean", stmt->line, stmt->column);
}
_rava_semantic_analyze_node(analyzer, stmt->data.if_stmt.then_stmt);
if (stmt->data.if_stmt.else_stmt) {
_rava_semantic_analyze_node(analyzer, stmt->data.if_stmt.else_stmt);
}
return true;
}
case RAVA_AST_WHILE_STMT: {
RavaType_t *cond_type = _rava_semantic_check_expression(analyzer, stmt->data.while_stmt.condition);
if (cond_type && cond_type->kind != RAVA_TYPE_BOOLEAN) {
_rava_semantic_error(analyzer, "While condition must be boolean", stmt->line, stmt->column);
}
_rava_semantic_analyze_node(analyzer, stmt->data.while_stmt.body);
return true;
}
case RAVA_AST_FOR_STMT:
if (stmt->data.for_stmt.init) {
if (stmt->data.for_stmt.init->type == RAVA_AST_VAR_DECL) {
_rava_semantic_analyze_node(analyzer, stmt->data.for_stmt.init);
} else {
_rava_semantic_check_expression(analyzer, stmt->data.for_stmt.init);
}
}
if (stmt->data.for_stmt.condition) {
RavaType_t *cond_type = _rava_semantic_check_expression(analyzer, stmt->data.for_stmt.condition);
if (cond_type && cond_type->kind != RAVA_TYPE_BOOLEAN) {
_rava_semantic_error(analyzer, "For condition must be boolean", stmt->line, stmt->column);
}
}
if (stmt->data.for_stmt.update) {
_rava_semantic_check_expression(analyzer, stmt->data.for_stmt.update);
}
_rava_semantic_analyze_node(analyzer, stmt->data.for_stmt.body);
return true;
case RAVA_AST_RETURN_STMT:
if (stmt->data.return_stmt.value) {
_rava_semantic_check_expression(analyzer, stmt->data.return_stmt.value);
}
return true;
case RAVA_AST_EXPR_STMT:
if (stmt->children_count > 0) {
_rava_semantic_check_expression(analyzer, stmt->children[0]);
}
return true;
case RAVA_AST_VAR_DECL:
return _rava_semantic_analyze_var_decl(analyzer, stmt);
default:
return true;
}
}
static bool _rava_semantic_analyze_node(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *node) {
if (!node) return true;
switch (node->type) {
case RAVA_AST_COMPILATION_UNIT:
for (size_t i = 0; i < node->children_count; i++) {
_rava_semantic_analyze_node(analyzer, node->children[i]);
}
return true;
case RAVA_AST_CLASS_DECL:
return _rava_semantic_analyze_class(analyzer, node);
case RAVA_AST_METHOD_DECL:
return _rava_semantic_analyze_method(analyzer, node);
case RAVA_AST_FIELD_DECL:
return _rava_semantic_analyze_field(analyzer, node);
case RAVA_AST_CONSTRUCTOR_DECL:
return true;
default:
return _rava_semantic_analyze_statement(analyzer, node);
}
}
bool rava_semantic_analyze(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *root) {
if (!analyzer || !root) return false;
_rava_semantic_analyze_node(analyzer, root);
return !analyzer->had_error;
}
RavaType_t* rava_semantic_get_expression_type(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *expr) {
return _rava_semantic_check_expression(analyzer, expr);
}

23
semantic/semantic.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef RAVA_SEMANTIC_H
#define RAVA_SEMANTIC_H
#include "../parser/parser.h"
#include "../types/types.h"
#include "symbol_table.h"
#include <stdbool.h>
typedef struct {
RavaSymbolTable_t *symbol_table;
char *error_message;
bool had_error;
int error_count;
} RavaSemanticAnalyzer_t;
RavaSemanticAnalyzer_t* rava_semantic_analyzer_create();
void rava_semantic_analyzer_destroy(RavaSemanticAnalyzer_t *analyzer);
bool rava_semantic_analyze(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *root);
RavaType_t* rava_semantic_get_expression_type(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *expr);
#endif

139
semantic/symbol_table.c Normal file
View File

@ -0,0 +1,139 @@
#define _POSIX_C_SOURCE 200809L
#include "symbol_table.h"
#include <stdlib.h>
#include <string.h>
RavaSymbolTable_t* rava_symbol_table_create() {
RavaSymbolTable_t *table = malloc(sizeof(RavaSymbolTable_t));
table->global_scope = rava_scope_create("global", NULL);
table->current_scope = table->global_scope;
return table;
}
void rava_symbol_table_destroy(RavaSymbolTable_t *table) {
if (!table) return;
rava_scope_destroy(table->global_scope);
free(table);
}
RavaScope_t* rava_scope_create(const char *name, RavaScope_t *parent) {
RavaScope_t *scope = calloc(1, sizeof(RavaScope_t));
scope->name = strdup(name);
scope->symbols = NULL;
scope->parent = parent;
scope->children = NULL;
scope->children_count = 0;
scope->children_capacity = 0;
return scope;
}
void rava_scope_destroy(RavaScope_t *scope) {
if (!scope) return;
free(scope->name);
RavaSymbol_t *symbol = scope->symbols;
while (symbol) {
RavaSymbol_t *next = symbol->next;
rava_symbol_destroy(symbol);
symbol = next;
}
for (size_t i = 0; i < scope->children_count; i++) {
rava_scope_destroy(scope->children[i]);
}
free(scope->children);
free(scope);
}
void rava_symbol_table_enter_scope(RavaSymbolTable_t *table, const char *scope_name) {
RavaScope_t *new_scope = rava_scope_create(scope_name, table->current_scope);
if (table->current_scope->children_count >= table->current_scope->children_capacity) {
size_t new_capacity = table->current_scope->children_capacity == 0 ? 4 :
table->current_scope->children_capacity * 2;
table->current_scope->children = realloc(table->current_scope->children,
sizeof(RavaScope_t*) * new_capacity);
table->current_scope->children_capacity = new_capacity;
}
table->current_scope->children[table->current_scope->children_count++] = new_scope;
table->current_scope = new_scope;
}
void rava_symbol_table_exit_scope(RavaSymbolTable_t *table) {
if (table->current_scope->parent) {
table->current_scope = table->current_scope->parent;
}
}
RavaSymbol_t* rava_symbol_create(RavaSymbolKind_e kind, const char *name, RavaType_t *type) {
RavaSymbol_t *symbol = calloc(1, sizeof(RavaSymbol_t));
symbol->kind = kind;
symbol->name = strdup(name);
symbol->type = type;
symbol->modifiers = NULL;
symbol->modifiers_count = 0;
symbol->declaration = NULL;
symbol->next = NULL;
return symbol;
}
void rava_symbol_destroy(RavaSymbol_t *symbol) {
if (!symbol) return;
free(symbol->name);
rava_type_destroy(symbol->type);
free(symbol);
}
bool rava_symbol_table_define(RavaSymbolTable_t *table, RavaSymbol_t *symbol) {
if (!table || !symbol) return false;
if (rava_symbol_table_resolve_in_scope(table->current_scope, symbol->name)) {
return false;
}
symbol->next = table->current_scope->symbols;
table->current_scope->symbols = symbol;
return true;
}
RavaSymbol_t* rava_symbol_table_resolve(RavaSymbolTable_t *table, const char *name) {
if (!table || !name) return NULL;
RavaScope_t *scope = table->current_scope;
while (scope) {
RavaSymbol_t *symbol = rava_symbol_table_resolve_in_scope(scope, name);
if (symbol) return symbol;
scope = scope->parent;
}
return NULL;
}
RavaSymbol_t* rava_symbol_table_resolve_in_scope(RavaScope_t *scope, const char *name) {
if (!scope || !name) return NULL;
RavaSymbol_t *symbol = scope->symbols;
while (symbol) {
if (strcmp(symbol->name, name) == 0) {
return symbol;
}
symbol = symbol->next;
}
return NULL;
}
bool rava_symbol_has_modifier(RavaSymbol_t *symbol, RavaModifier_e modifier) {
if (!symbol) return false;
for (size_t i = 0; i < symbol->modifiers_count; i++) {
if (symbol->modifiers[i] == modifier) {
return true;
}
}
return false;
}

61
semantic/symbol_table.h Normal file
View File

@ -0,0 +1,61 @@
#ifndef RAVA_SYMBOL_TABLE_H
#define RAVA_SYMBOL_TABLE_H
#include "../types/types.h"
#include "../parser/parser.h"
#include <stddef.h>
#include <stdbool.h>
typedef enum {
RAVA_SYMBOL_CLASS,
RAVA_SYMBOL_METHOD,
RAVA_SYMBOL_FIELD,
RAVA_SYMBOL_VARIABLE,
RAVA_SYMBOL_PARAMETER
} RavaSymbolKind_e;
typedef struct RavaSymbol_t {
RavaSymbolKind_e kind;
char *name;
RavaType_t *type;
RavaModifier_e *modifiers;
size_t modifiers_count;
RavaASTNode_t *declaration;
size_t local_index;
struct RavaSymbol_t *next;
} RavaSymbol_t;
typedef struct RavaScope_t {
char *name;
RavaSymbol_t *symbols;
struct RavaScope_t *parent;
struct RavaScope_t **children;
size_t children_count;
size_t children_capacity;
} RavaScope_t;
typedef struct {
RavaScope_t *global_scope;
RavaScope_t *current_scope;
} RavaSymbolTable_t;
RavaSymbolTable_t* rava_symbol_table_create();
void rava_symbol_table_destroy(RavaSymbolTable_t *table);
RavaScope_t* rava_scope_create(const char *name, RavaScope_t *parent);
void rava_scope_destroy(RavaScope_t *scope);
void rava_symbol_table_enter_scope(RavaSymbolTable_t *table, const char *scope_name);
void rava_symbol_table_exit_scope(RavaSymbolTable_t *table);
RavaSymbol_t* rava_symbol_create(RavaSymbolKind_e kind, const char *name, RavaType_t *type);
void rava_symbol_destroy(RavaSymbol_t *symbol);
bool rava_symbol_table_define(RavaSymbolTable_t *table, RavaSymbol_t *symbol);
RavaSymbol_t* rava_symbol_table_resolve(RavaSymbolTable_t *table, const char *name);
RavaSymbol_t* rava_symbol_table_resolve_in_scope(RavaScope_t *scope, const char *name);
bool rava_symbol_has_modifier(RavaSymbol_t *symbol, RavaModifier_e modifier);
#endif

130
tests/run_examples.c Normal file
View File

@ -0,0 +1,130 @@
#include "../lexer/lexer.h"
#include "../parser/parser.h"
#include "../semantic/semantic.h"
#include "../ir/ir.h"
#include "../ir/ir_gen.h"
#include "../runtime/runtime.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static char* read_file(const char *filename) {
FILE *file = fopen(filename, "r");
if (!file) {
printf("Error: Could not open file %s\n", filename);
return NULL;
}
fseek(file, 0, SEEK_END);
long size = ftell(file);
fseek(file, 0, SEEK_SET);
char *content = malloc(size + 1);
size_t read_bytes = fread(content, 1, size, file); (void)read_bytes;
content[size] = '\0';
fclose(file);
return content;
}
static bool run_example(const char *filename, const char *class_name) {
printf("\n");
printf("================================================================================\n");
printf("Running: %s\n", filename);
printf("================================================================================\n");
char *source = read_file(filename);
if (!source) return false;
RavaLexer_t *lexer = rava_lexer_create(source);
RavaParser_t *parser = rava_parser_create(lexer);
RavaASTNode_t *ast = rava_parser_parse(parser);
if (parser->had_error) {
printf("❌ Parse error: %s\n", parser->error_message);
free(source);
return false;
}
RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create();
if (!rava_semantic_analyze(analyzer, ast)) {
printf("❌ Semantic error: %s\n", analyzer->error_message);
free(source);
return false;
}
RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer);
RavaProgram_t *program = rava_ir_generate(ir_gen, ast);
if (!program) {
printf("❌ IR generation failed\n");
free(source);
return false;
}
RavaVM_t *vm = rava_vm_create(program);
printf("\nOutput:\n");
if (!rava_vm_execute(vm, class_name, "main")) {
printf("\n❌ Runtime error: %s\n", vm->error_message);
rava_vm_destroy(vm);
free(source);
return false;
}
printf("\n✅ Execution completed successfully!\n");
rava_vm_destroy(vm);
rava_program_destroy(program);
rava_ir_generator_destroy(ir_gen);
rava_semantic_analyzer_destroy(analyzer);
rava_ast_node_destroy(ast);
rava_parser_destroy(parser);
rava_lexer_destroy(lexer);
free(source);
return true;
}
int main() {
printf("================================================================================\n");
printf("RAVA JAVA INTERPRETER - UNIVERSITY-LEVEL DEMONSTRATION SUITE\n");
printf("================================================================================\n");
int passed = 0;
int total = 0;
const char *examples[][2] = {
{"examples/01_Fibonacci.java", "Fibonacci"},
{"examples/02_PrimeNumbers.java", "PrimeNumbers"},
{"examples/03_FactorialVariations.java", "FactorialVariations"},
{"examples/04_GCD_LCM.java", "GCD_LCM"},
{"examples/05_PowerFunction.java", "PowerFunction"},
{"examples/06_BubbleSort.java", "BubbleSort"},
{"examples/07_CollatzConjecture.java", "CollatzConjecture"},
{"examples/08_PascalTriangle.java", "PascalTriangle"},
{"examples/09_TowerOfHanoi.java", "TowerOfHanoi"},
{"examples/10_AckermannFunction.java", "AckermannFunction"},
};
for (size_t i = 0; i < 10; i++) {
total++;
if (run_example(examples[i][0], examples[i][1])) {
passed++;
}
}
printf("\n");
printf("================================================================================\n");
printf("DEMONSTRATION SUMMARY\n");
printf("================================================================================\n");
printf("Passed: %d/%d\n", passed, total);
printf("Failed: %d/%d\n", total - passed, total);
if (passed == total) {
printf("\n🎉 ALL DEMONSTRATIONS PASSED!\n");
printf("The Rava interpreter successfully executed university-level Java programs!\n");
}
return (passed == total) ? 0 : 1;
}

200
types/types.c Normal file
View File

@ -0,0 +1,200 @@
#define _POSIX_C_SOURCE 200809L
#include "types.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
RavaType_t* rava_type_create_primitive(RavaTypeKind_e kind) {
RavaType_t *type = calloc(1, sizeof(RavaType_t));
type->kind = kind;
switch (kind) {
case RAVA_TYPE_VOID: type->name = strdup("void"); break;
case RAVA_TYPE_BOOLEAN: type->name = strdup("boolean"); break;
case RAVA_TYPE_BYTE: type->name = strdup("byte"); break;
case RAVA_TYPE_SHORT: type->name = strdup("short"); break;
case RAVA_TYPE_INT: type->name = strdup("int"); break;
case RAVA_TYPE_LONG: type->name = strdup("long"); break;
case RAVA_TYPE_CHAR: type->name = strdup("char"); break;
case RAVA_TYPE_FLOAT: type->name = strdup("float"); break;
case RAVA_TYPE_DOUBLE: type->name = strdup("double"); break;
default: type->name = strdup("unknown"); break;
}
return type;
}
RavaType_t* rava_type_create_class(const char *class_name) {
RavaType_t *type = calloc(1, sizeof(RavaType_t));
type->kind = RAVA_TYPE_CLASS;
type->name = strdup(class_name);
type->data.class_type.class_name = strdup(class_name);
return type;
}
RavaType_t* rava_type_create_array(RavaType_t *element_type, int dimensions) {
RavaType_t *type = calloc(1, sizeof(RavaType_t));
type->kind = RAVA_TYPE_ARRAY;
type->data.array.element_type = element_type;
type->data.array.dimensions = dimensions;
char buffer[256];
snprintf(buffer, sizeof(buffer), "%s", rava_type_to_string(element_type));
for (int i = 0; i < dimensions; i++) {
strcat(buffer, "[]");
}
type->name = strdup(buffer);
return type;
}
void rava_type_destroy(RavaType_t *type) {
if (!type) return;
free(type->name);
if (type->kind == RAVA_TYPE_ARRAY) {
rava_type_destroy(type->data.array.element_type);
} else if (type->kind == RAVA_TYPE_CLASS) {
free(type->data.class_type.class_name);
}
free(type);
}
RavaType_t* rava_type_from_name(const char *type_name) {
if (strcmp(type_name, "void") == 0) return rava_type_create_primitive(RAVA_TYPE_VOID);
if (strcmp(type_name, "boolean") == 0) return rava_type_create_primitive(RAVA_TYPE_BOOLEAN);
if (strcmp(type_name, "byte") == 0) return rava_type_create_primitive(RAVA_TYPE_BYTE);
if (strcmp(type_name, "short") == 0) return rava_type_create_primitive(RAVA_TYPE_SHORT);
if (strcmp(type_name, "int") == 0) return rava_type_create_primitive(RAVA_TYPE_INT);
if (strcmp(type_name, "long") == 0) return rava_type_create_primitive(RAVA_TYPE_LONG);
if (strcmp(type_name, "char") == 0) return rava_type_create_primitive(RAVA_TYPE_CHAR);
if (strcmp(type_name, "float") == 0) return rava_type_create_primitive(RAVA_TYPE_FLOAT);
if (strcmp(type_name, "double") == 0) return rava_type_create_primitive(RAVA_TYPE_DOUBLE);
return rava_type_create_class(type_name);
}
bool rava_type_is_primitive(RavaType_t *type) {
return type->kind >= RAVA_TYPE_VOID && type->kind <= RAVA_TYPE_DOUBLE;
}
bool rava_type_is_numeric(RavaType_t *type) {
return type->kind >= RAVA_TYPE_BYTE && type->kind <= RAVA_TYPE_DOUBLE;
}
bool rava_type_is_integral(RavaType_t *type) {
return type->kind >= RAVA_TYPE_BYTE && type->kind <= RAVA_TYPE_CHAR;
}
bool rava_type_is_floating(RavaType_t *type) {
return type->kind == RAVA_TYPE_FLOAT || type->kind == RAVA_TYPE_DOUBLE;
}
bool rava_type_is_reference(RavaType_t *type) {
return type->kind == RAVA_TYPE_CLASS ||
type->kind == RAVA_TYPE_ARRAY ||
type->kind == RAVA_TYPE_NULL;
}
bool rava_type_equals(RavaType_t *a, RavaType_t *b) {
if (!a || !b) return false;
if (a->kind != b->kind) return false;
if (a->kind == RAVA_TYPE_ARRAY) {
return a->data.array.dimensions == b->data.array.dimensions &&
rava_type_equals(a->data.array.element_type, b->data.array.element_type);
}
if (a->kind == RAVA_TYPE_CLASS) {
return strcmp(a->data.class_type.class_name, b->data.class_type.class_name) == 0;
}
return true;
}
bool rava_type_is_assignable_to(RavaType_t *from, RavaType_t *to) {
if (!from || !to) return false;
if (rava_type_equals(from, to)) return true;
if (from->kind == RAVA_TYPE_NULL && rava_type_is_reference(to)) {
return true;
}
if (rava_type_is_numeric(from) && rava_type_is_numeric(to)) {
int from_rank = from->kind - RAVA_TYPE_BYTE;
int to_rank = to->kind - RAVA_TYPE_BYTE;
return from_rank <= to_rank;
}
return false;
}
bool rava_type_is_castable_to(RavaType_t *from, RavaType_t *to) {
if (rava_type_is_assignable_to(from, to)) return true;
if (rava_type_is_numeric(from) && rava_type_is_numeric(to)) {
return true;
}
if (rava_type_is_reference(from) && rava_type_is_reference(to)) {
return true;
}
return false;
}
static bool _is_string_type(RavaType_t *type) {
return type->kind == RAVA_TYPE_CLASS &&
type->data.class_type.class_name &&
strcmp(type->data.class_type.class_name, "String") == 0;
}
RavaType_t* rava_type_binary_result(RavaType_t *left, RavaType_t *right) {
if (!left || !right) return NULL;
if (_is_string_type(left) || _is_string_type(right)) {
return rava_type_create_class("String");
}
if (!rava_type_is_numeric(left) || !rava_type_is_numeric(right)) {
return NULL;
}
if (left->kind == RAVA_TYPE_DOUBLE || right->kind == RAVA_TYPE_DOUBLE) {
return rava_type_create_primitive(RAVA_TYPE_DOUBLE);
}
if (left->kind == RAVA_TYPE_FLOAT || right->kind == RAVA_TYPE_FLOAT) {
return rava_type_create_primitive(RAVA_TYPE_FLOAT);
}
if (left->kind == RAVA_TYPE_LONG || right->kind == RAVA_TYPE_LONG) {
return rava_type_create_primitive(RAVA_TYPE_LONG);
}
return rava_type_create_primitive(RAVA_TYPE_INT);
}
RavaType_t* rava_type_unary_result(RavaType_t *operand) {
if (!operand) return NULL;
if (!rava_type_is_numeric(operand)) {
return NULL;
}
if (operand->kind == RAVA_TYPE_BYTE ||
operand->kind == RAVA_TYPE_SHORT ||
operand->kind == RAVA_TYPE_CHAR) {
return rava_type_create_primitive(RAVA_TYPE_INT);
}
return rava_type_create_primitive(operand->kind);
}
const char* rava_type_to_string(RavaType_t *type) {
if (!type) return "null";
return type->name;
}

63
types/types.h Normal file
View File

@ -0,0 +1,63 @@
#ifndef RAVA_TYPES_H
#define RAVA_TYPES_H
#include <stddef.h>
#include <stdbool.h>
typedef enum {
RAVA_TYPE_VOID,
RAVA_TYPE_BOOLEAN,
RAVA_TYPE_BYTE,
RAVA_TYPE_SHORT,
RAVA_TYPE_INT,
RAVA_TYPE_LONG,
RAVA_TYPE_CHAR,
RAVA_TYPE_FLOAT,
RAVA_TYPE_DOUBLE,
RAVA_TYPE_CLASS,
RAVA_TYPE_INTERFACE,
RAVA_TYPE_ARRAY,
RAVA_TYPE_NULL,
RAVA_TYPE_UNKNOWN
} RavaTypeKind_e;
typedef struct RavaType_t RavaType_t;
struct RavaType_t {
RavaTypeKind_e kind;
char *name;
union {
struct {
RavaType_t *element_type;
int dimensions;
} array;
struct {
char *class_name;
} class_type;
} data;
};
RavaType_t* rava_type_create_primitive(RavaTypeKind_e kind);
RavaType_t* rava_type_create_class(const char *class_name);
RavaType_t* rava_type_create_array(RavaType_t *element_type, int dimensions);
void rava_type_destroy(RavaType_t *type);
RavaType_t* rava_type_from_name(const char *type_name);
bool rava_type_is_primitive(RavaType_t *type);
bool rava_type_is_numeric(RavaType_t *type);
bool rava_type_is_integral(RavaType_t *type);
bool rava_type_is_floating(RavaType_t *type);
bool rava_type_is_reference(RavaType_t *type);
bool rava_type_equals(RavaType_t *a, RavaType_t *b);
bool rava_type_is_assignable_to(RavaType_t *from, RavaType_t *to);
bool rava_type_is_castable_to(RavaType_t *from, RavaType_t *to);
RavaType_t* rava_type_binary_result(RavaType_t *left, RavaType_t *right);
RavaType_t* rava_type_unary_result(RavaType_t *operand);
const char* rava_type_to_string(RavaType_t *type);
#endif