Added function support!
Now you can make function calls, get stuff as return and use local variables!
It generates a really small 150 line file to say “HI”
Added function support!
Now you can make function calls, get stuff as return and use local variables!
It generates a really small 150 line file to say “HI”
Created the project!
This is a compiler for crawssembly.
I did a basic AST that can compile to crawssembbly, i have support local variables and printing to the screen
I have AST nodes for functions but they are not implemented in the compiler yet
Added background blurring for modules
What I do is take a texture, copy the game’s framebuffer onto the texture, then downscale it to 180p and blur it.
Then when modules are rendering I use that image as the background instead of just using a tint
Note: Half of this time is figuring out how to get this working on opengl, I still wasn’t able to do it, so this is vulkan only
I added vulkanmod support for all supported versions above 1.21.4, it uses the same backend as the 26.2 vulkan renderer but has some extra handling for vulkanmod
Added Vulkan support!
This was pretty hard because skiko does not come with vulkan support by default.
However, there is a pull request that adds vulkan support.
So I created git submodules for skia and skiko, made a setup script that automatically applies the vulkan patches, builds and publishes to maven local.
Then I had to fight with a lot of issues(some of them I couldn’t even debug because it was happening in native code), but I got it working ![]()
Added support for 26.2, only for the OpenGL renderer.
This is because skiko(backend of jetpack compose) does not support vulkan.
Updated gradle and dependencies.
Added support for 1.21.11 and 26.1.2
Did some cleanup for the mixins
Added generics support, which allows the user to define generic functions/structs that apply with every type, for example:
warp <T> void forEach(T[] a, (T) -> void action) {
for(T t in a) {
action(t);
}
}
Depending on what type you used to call this, a new version of forEach gets generated, if you called it with an integer:
warp void forEach@int(int[] a, (int) -> void action) {
for(int t in a) {
action(t);
}
}
Of course I also allow this on structs:
struct Triangle<Num>(Num x1, Num y1, Num x2, Num y2, Num x3, Num y3);
Also did some small changes:
More abstractions please!
Added dynamic function dispatch which allows for functions to take in
other functions as arguments, of course, this isn’t possible at all in
normal scratch, so actually FunctionLiteral gets turned into an
integer and a custom dispatch function gets created for every function
literal’s signature which allows for a binary search to call the actual
function
Also made HeapConversion reuse stack slots instead of allocating one
for every variable(mostly by AI)
Refactored the entire type system to use a sealed interface instead of an unsafe single class
Nothing much to say, this doesn’t affect the input code or the output project, I did just cleanup
Did more syntax improvements
Added ++ and – support:
index++;
Added type inference support:
auto a = Triangle(5, 15, 60, -120, 240, 67); //type automatically becomes Triangle
auto a = func(); //type automatically becomes the return type of func
Scratcher is at 100 commits! (Now 104 cause all of these refactors are different commits)
Completely refactored all translation steps to use the ASTVisitor.
Also did type resolving cleanup.
Function Reachability: Went from 117 to 32 lines
Function expression lowering: Went from 439 to 293 lines
Re Parse Local Variables: Went from 34 to 27 lines
Remove Empty Allocations: Went from 97 to 79 lines
ConvertToHeapAccess: Biggest refactor of this whole devlog, went from 500 lines to 418, split into 5 files
Fixed a lot of bugs with when expressions, also got deepseek to fix some of them
Added If expressions, which allow using if statements inside other expressions, for example, here is some previously invalid code that is now valid:
int max = if (a > b) a else b;
str message = if (score >= 90) {
looks::say("something");
"You win!"
} else {
looks::say("something");
"You lose :("
}
triangles[15] = Triangle(
utils::random(-240, 240),
utils::random(-180, 180),
utils::random(-240, 240),
utils::random(-180, 180),
utils::random(-240, 240),
if(mode == TriangleRenderMode.OFF) {
5
} else {
triangles[14].y3
}
);
These still get lowered properly and just look like normal if statements in the final scratch code
Added more syntax improvements!
Else if: Added support for else if, which replaces big blocks
//Before:
if(triangles[14].y1 >= 15) {
looks::say(">=15");
} else {
if(triangles[14].y2 >= 155) {
looks::say("<=15");
} else {
looks::say("Both false!");
}
}
//After:
if(triangles[14].y1 >= 15) {
looks::say(">=15");
} else if(triangles[14].y2 >= 155) {
looks::say("<=15");
} else {
looks::say("Both false!");
}
Compound assignment: Added support for compound assignment
//Before:
triangles[15].y3 = triangles[15].y3 + 5;
//After:
triangles[15].y3 += 5;
Enums: Added support for enums, which are just fancy integer wrappers
enum TriangleRenderMode(OFF, RENDER, ITHINK);
TriangleRenderMode mode = TriangleRenderMode.OFF;
When: Added support for when expressions/statements that allow for matching a subject:
//Before:
if(answer == "off") {
mode = TriangleRenderMode.OFF;
} else if(answer == "render") {
mode = TriangleRenderMode.RENDER;
} else {
mode = TriangleRenderMode.ITHINK;
looks::say("If thinking is your power, what are you without it?");
return;
}
//After:
TriangleRenderMode mode = when(answer) {
"off" -> TriangleRenderMode.OFF
"render" -> TriangleRenderMode.RENDER
else -> {
looks::say("If thinking is your power, what are you without it?");
TriangleRenderMode.ITHINK;
}
};
Tried to do turbowarp only return optimization, wasn’t able to make it very good… reverted it
Improved the structure of CompilationConstants
Added string::split and string::substring
Made some of the list functions inlined (itemAt, clear, length)
Made the garbage collector treat top level variables as roots, this prevents top level variables from getting freed
I added 2 modes to this
Added a mark and sweep garbage collector to my language, it walks the roots, marks every used object, then frees all unused objects!
Most impressive part of this(in my opinion) is that most of the garbage collector is actually written in my language
Added a name parameter to alloc which acts as runtime type metadata, soon to be used.
Added more compiler sugar for lists:
list[index] replaces list::itemAt(list, index)
list[index] = ...; replaces list::replace(list, item, index)
for(type name in list) {} replaces
int len = list::length(list);
int i = 0;
while (i < len) {
type name = list::itemAt(list, i);
i = i + 1;
}
(i am not proud of the shitcode that was used to get for(type name in list) working)
Added list support! A very barebones implementation that allows the user to create, add to, read from and delete items from lists!