Compare commits

...

10 Commits

Author SHA1 Message Date
Krzosa Karol
ced67bbb96 Remove MacOS Github runner
Some checks failed
/ run-and-compile-ubuntu (push) Has been cancelled
/ run-and-compile-windows (push) Has been cancelled
2024-06-14 11:33:46 +02:00
Krzosa Karol
827e838550 Remove sandbox example 2024-06-14 10:41:08 +02:00
Krzosa Karol
62b15a1077 Update README 2024-06-14 09:07:55 +02:00
Krzosa Karol
42ec3f7a18 Text editor: Remove prototype. Update README 2024-06-14 09:06:10 +02:00
Krzosa Karol
ff612d00ef Fix field resolution not resolving constant value properly 2024-06-10 08:45:58 +02:00
Krzosa Karol
f8cf91ed2a Fix compiler bugs and text_editor 2024-06-10 06:56:53 +02:00
Krzosa Karol
39cb9cb4b4 Fix improperly prompting about unused local in another modules, fix full recompile, Text editor: restructure 2024-06-09 12:04:38 +02:00
Krzosa Karol
b08c7c9ce6 Small mouse fix 2024-06-08 15:58:18 +02:00
Krzosa Karol
2ec4a2a28d Text editor: prototype based setup 2024-06-08 15:26:38 +02:00
Krzosa Karol
27b197840b Add line numbers and unfocused overlay 2024-06-07 11:36:49 +02:00
40 changed files with 817 additions and 687 deletions

View File

@@ -7,12 +7,6 @@ jobs:
- run: sudo apt install g++
- run: sudo apt install clang
- run: g++ -o bld src/build_tool/main.cpp -g -lm && ./bld
run-and-compile-mac:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- run: brew install llvm
- run: clang++ src/build_tool/main.cpp -std=c++11 -o bld && ./bld
run-and-compile-windows:
runs-on: windows-latest
steps:
@@ -22,4 +16,10 @@ jobs:
arch: x64
- uses: actions/checkout@v4
- run: cl.exe src/build_tool/main.cpp /Fe:bld.exe && bld.exe
shell: cmd
shell: cmd
# run-and-compile-mac:
# runs-on: macos-latest
# steps:
# - uses: actions/checkout@v4
# - run: brew install llvm
# - run: clang++ src/build_tool/main.cpp -std=c++11 -o bld && ./bld --threads 1

View File

@@ -1,6 +1,6 @@
# Compiler front-end in a single-header-file C library
I have no illusions here, this is not the next big language. What I propose is very simple - a return to C. Not to the language as it was, but a return to the ideal of 'C'. A return to something in it - that is more then it. A small language supplemented with modern ideas - distributed as a dependency free, easy to use single-header-file library.
.. for a very simple statically typed language. I mostly designed it for personal use, it's small but complete - you can actually program in it and so on. It compiles to C with all the debug info so debuggers work. Currently I find that it's pretty good for metaprogramming and code generation, particularly when you have a workflow "metaprogram -> program". The library provides functions for traversing, printing the AST and other niceties:
- **User has full control over compilation!**
- **No dependencies, permissive license, single file that compile both in C and C++!**
@@ -81,12 +81,6 @@ clang++ src/build_tool/main.cpp -o bld.exe
You only need to compile the build tool once. Afterwards just call `./bld.exe`. There are multiple testing options so checkout: `./bld.exe --help`.
## Further plans
- **My priority is to improve the C user API, harden the compiler, accommodate things that I didn't foresee and stuff like that.**
- I want to implement a bytecode backend (in the future) so that the language can be used like Lua.
- New features are of second priority unless they important. I'm considering the addition of overloaded procedures because it would greatly aid in writing macros.
# Language overview
The language is strictly procedural, I have taken most of the inspiration from C, Golang, Ion, Jai and Odin. There are no classes, methods etc. only procedures and data types.

View File

@@ -8,4 +8,4 @@ if not exist build\bld.exe (
)
rem ubuntu run ./build.sh
build\bld.exe --tests text_editor
build\bld.exe

View File

@@ -45,7 +45,6 @@ S8_String RaylibDLL;
#include "examples/add_dynamic_array_macro/build.cpp"
#include "examples/text_editor/build.cpp"
#include "examples/hello_world/build.cpp"
#include "examples/sandbox/build.cpp"
#include "examples/create_raylib_window/build.cpp"
#include "examples/add_instrumentation/build.cpp"
#include "examples/use_as_data_format_with_typechecking/build.cpp"
@@ -53,12 +52,10 @@ S8_String RaylibDLL;
int main(int argc, char **argv) {
MA_InitScratch();
MA_Scratch scratch;
UseColoredIO = OS_EnableTerminalColors();
{
CmdParser p = MakeCmdParser(scratch, argc, argv, "I'm a build tool for this codebase, by default I build the entire test suite");
CmdParser p = MakeCmdParser(Perm, argc, argv, "I'm a build tool for this codebase, by default I build the entire test suite");
AddBool(&p, &BuildX64Sandbox, "build-x64-sandbox", "build the x64 sandbox program using msvc");
AddBool(&p, &QuickRun, "quick", "build tests using tcc compiler only");
AddBool(&p, &BreakpointOnError, "breakpoint", "breakpoint if a compiler error is thrown");
@@ -110,7 +107,7 @@ int main(int argc, char **argv) {
PushDir("x64_sandbox");
S8_String cc = "cl";
Array<S8_String> flags = {MA_GetAllocator(scratch)};
Array<S8_String> flags = {MA_GetAllocator(Perm)};
flags += "/MP /Zi -D_CRT_SECURE_NO_WARNINGS";
flags += "/FC /WX /W3 /wd4200 /diagnostics:column /nologo";
flags += "/GF /Gm- /Oi";
@@ -166,12 +163,6 @@ int main(int argc, char **argv) {
else IO_Printf("%-50s - ERROR\n", "hello_world");
}
if (ShouldRun("sandbox")) {
bool result = sandbox();
if (result) IO_Printf("%-50s - OK\n", "sandbox");
else IO_Printf("%-50s - ERROR\n", "sandbox");
}
if (ShouldRun("create_raylib_window")) {
bool result = create_raylib_window();
if (result) IO_Printf("%-50s - OK\n", "create_raylib_window");
@@ -184,27 +175,28 @@ int main(int argc, char **argv) {
else IO_Printf("%-50s - ERROR\n", "add_instrumentation");
}
if (ShouldRun("wasm_playground") && UseClang) {
bool build_wasm = false;
if (build_wasm && ShouldRun("wasm_playground") && UseClang) {
OS_MakeDir("wasm_playground");
int result = Run("clang --target=wasm32 -mbulk-memory -Oz -Wno-writable-strings --no-standard-libraries -Wl,--strip-all -Wl,--import-memory -Wl,--no-entry -o wasm_playground/playground.wasm ../src/wasm_playground/wasm_main.c -DOS_WASM=1");
S8_String index = OS_ReadFile(scratch, "../src/wasm_playground/index.html");
S8_String index = OS_ReadFile(Perm, "../src/wasm_playground/index.html");
S8_List programs = S8_MakeEmptyList();
OS_SetWorkingDir("wasm_playground"); // so that RegisterDir("../../pkgs") works
for (OS_FileIter it = OS_IterateFiles(scratch, "../../src/wasm_playground/"); OS_IsValid(it); OS_Advance(&it)) {
for (OS_FileIter it = OS_IterateFiles(Perm, "../../src/wasm_playground/"); OS_IsValid(it); OS_Advance(&it)) {
if (S8_EndsWith(it.filename, ".lc", false)) {
RunTestFile({TestKind_File, it.absolute_path, it.filename, "not_needed", true});
S8_String file = OS_ReadFile(scratch, it.absolute_path);
file = S8_ReplaceAll(scratch, file, S8_Lit("\\"), S8_Lit("\\\\"), true);
S8_AddF(scratch, &programs, "`%.*s`,\n", S8_Expand(file));
S8_String file = OS_ReadFile(Perm, it.absolute_path);
file = S8_ReplaceAll(Perm, file, S8_Lit("\\"), S8_Lit("\\\\"), true);
S8_AddF(Perm, &programs, "`%.*s`,\n", S8_Expand(file));
}
}
OS_SetWorkingDir("..");
S8_String programs_string = S8_Merge(scratch, programs);
S8_String new_index = S8_ReplaceAll(scratch, index, "<InsertPrograms>", programs_string, false);
S8_String programs_string = S8_Merge(Perm, programs);
S8_String new_index = S8_ReplaceAll(Perm, index, "<InsertPrograms>", programs_string, false);
OS_WriteFile("wasm_playground/playground.html", new_index);
OS_CopyFile("../src/wasm_playground/run_server.bat", "wasm_playground/run_server.bat", true);
@@ -225,13 +217,13 @@ int main(int argc, char **argv) {
else IO_Printf("%-50s - ERROR\n", "add_source_location_macro");
}
Array<Process> processes = {MA_GetAllocator(scratch)};
Array<Process> processes = {MA_GetAllocator(Perm)};
if (ShouldRun("compilation")) {
//
// Test if things compile in C and C++ mode on all available compilers
//
S8_String working_dir = PushDir("targets");
Array<S8_String> files = {MA_GetAllocator(scratch)};
Array<S8_String> files = {MA_GetAllocator(Perm)};
files.add("../../../tests/compilation/test_compile_packed.c");
files.add("../../../tests/compilation/test_compile_packed_cpp.c");
@@ -249,12 +241,12 @@ int main(int argc, char **argv) {
if (UseCL) {
S8_String cc = "cl";
Array<S8_String> flags = {MA_GetAllocator(scratch)};
Array<S8_String> flags = {MA_GetAllocator(Perm)};
flags += "/Zi -D_CRT_SECURE_NO_WARNINGS";
flags += "/FC /WX /W3 /wd4200 /diagnostics:column /nologo";
flags += Fmt("/Fe:%.*s /Fd:%.*s.pdb", S8_Expand(exe), S8_Expand(name_no_ext));
Array<S8_String> link = {MA_GetAllocator(scratch)};
Array<S8_String> link = {MA_GetAllocator(Perm)};
link += "/link /incremental:no";
S8_String dir = Fmt("%.*s_cl_debug_" OS_NAME, S8_Expand(name_no_ext));
@@ -265,7 +257,7 @@ int main(int argc, char **argv) {
if (UseClang) {
S8_String cc = "clang";
Array<S8_String> flags = {MA_GetAllocator(scratch)};
Array<S8_String> flags = {MA_GetAllocator(Perm)};
flags += "-g -Wno-write-strings";
flags += "-fdiagnostics-absolute-paths";
flags += "-fsanitize=address";
@@ -281,7 +273,7 @@ int main(int argc, char **argv) {
if (UseGCC) {
S8_String cc = "gcc";
Array<S8_String> flags = {MA_GetAllocator(scratch)};
Array<S8_String> flags = {MA_GetAllocator(Perm)};
flags += "-g -Wno-write-strings";
flags += "-fsanitize=address";
if (is_cpp) flags += "-std=c++11";

View File

@@ -37,12 +37,12 @@ bool add_instrumentation() {
}
LC_String code = LC_GenerateUnityBuild();
LC_LangEnd(lang);
S8_String path = "examples/add_instrumentation/add_instrumentation.c";
OS_MakeDir("examples");
OS_MakeDir("examples/add_instrumentation");
OS_WriteFile(path, code);
LC_LangEnd(lang);
if (!UseCL) return true;
S8_String cmd = Fmt("cl %.*s -Zi -std:c11 -nologo -FC -Fd:examples/add_instrumentation/a.pdb -Fe:examples/add_instrumentation/add_instrumentation.exe %.*s", S8_Expand(path), S8_Expand(RaylibLIB));

View File

@@ -34,10 +34,9 @@ bool add_source_location_macro() {
}
LC_String code = LC_GenerateUnityBuild();
LC_LangEnd(lang);
OS_MakeDir("examples/add_source_location_macro");
OS_WriteFile("examples/add_source_location_macro/add_source_location_macro.c", code);
LC_LangEnd(lang);
return true;
}

View File

@@ -16,10 +16,10 @@ bool hello_world() {
OS_MakeDir("examples/hello_world");
LC_ParseAndResolve(name);
LC_String code = LC_GenerateUnityBuild();
LC_LangEnd(lang);
S8_String path = "examples/hello_world/hello_world.c";
OS_WriteFile(path, code);
LC_LangEnd(lang);
if (UseCL) {
S8_String cmd = Fmt("cl %.*s -nologo -FC -Fd:examples/hello_world/hello_world.pdb -Fe:examples/hello_world/hello_world.exe", S8_Expand(path));
if (Run(cmd) != 0) return false;

View File

@@ -1,68 +0,0 @@
import "std_types";
import libc "libc";
PAGE_SIZE :: 4096;
Arena :: struct {
data: *u8;
len: usize;
commit: usize;
reserve: usize;
alignment: usize;
}
GetAlignOffset :: proc(size: usize, align: usize): usize {
mask: usize = align - 1;
val: usize = size & mask;
if val {
val = align - val;
}
return val;
}
AlignUp :: proc(size: usize, align: usize): usize {
result := size + GetAlignOffset(size, align);
return result;
}
InitArena :: proc(arena: *Arena, reserve: usize) {
aligned_reserve := AlignUp(reserve, PAGE_SIZE);
data := VReserve(aligned_reserve);
libc.assert(data != nil);
if data {
arena.data = data;
arena.reserve = aligned_reserve;
arena.alignment = 8;
}
}
PushSize :: proc(arena: *Arena, size: usize): *void {
libc.assert(arena.data != nil);
pointer := :usize(arena.data) + arena.len + size;
align := GetAlignOffset(pointer, arena.alignment);
aligned_size := size + align;
a := arena.len + aligned_size;
if a > arena.commit {
diff := a - arena.commit;
commit_size := AlignUp(diff, PAGE_SIZE*4);
libc.assert(commit_size + arena.commit <= arena.reserve);
if VCommit(&arena.data[arena.commit], commit_size) {
arena.commit += commit_size;
} else {
libc.assert(false && "commit failed"[0]);
}
}
arena.len += align;
result: *void = &arena.data[arena.len];
arena.len += size;
return result;
}
TestArena :: proc() {
arena: Arena;
}

View File

@@ -1,28 +0,0 @@
#build_if(LC_OS == OS_WINDOWS);
DWORD :: typedef u32;
SIZE_T :: typedef uintptr;
BOOL :: typedef int;
MEM_RESERVE :: 0x00002000;
MEM_COMMIT :: 0x00001000;
PAGE_READWRITE :: 0x04;
VirtualAlloc :: proc(lpAddress: *void, dwSize: SIZE_T, flAllocationType: DWORD, flProtect: DWORD): *void; @api
MEM_RELEASE :: 0x00008000;
MEM_DECOMMIT :: 0x00004000;
VirtualFree :: proc(lpAddress: *void, dwSize: SIZE_T, dwFreeType: DWORD): BOOL; @api
VReserve :: proc(size: usize): *void {
result := VirtualAlloc(nil, :SIZE_T(size), MEM_RESERVE, PAGE_READWRITE);
return result;
}
VCommit :: proc(p: *void, size: usize): bool {
result := VirtualAlloc(p, :SIZE_T(size), MEM_COMMIT, PAGE_READWRITE) != 0;
return result;
}
VRelease :: proc(p: *void) {
VirtualFree(p, 0, MEM_RELEASE);
}

View File

@@ -1,122 +0,0 @@
namespace Sandbox {
Array<LC_Intern> TypesToGen;
void RegisterMarkedTypes(LC_AST *n) {
if (n->kind == LC_ASTKind_TypespecIdent) {
S8_String name = S8_MakeFromChar((char *)n->eident.name);
S8_String array_of = "ArrayOf";
if (S8_StartsWith(name, array_of)) {
if (name == "ArrayOfName") return;
name = S8_Skip(name, array_of.len);
LC_Intern intern = LC_InternStrLen(name.str, (int)name.len);
bool exists = false;
For(TypesToGen) {
if (intern == it) {
exists = true;
break;
}
}
if (!exists) {
TypesToGen.add(intern);
}
}
}
}
void WalkAndRename(LC_ASTWalker *ctx, LC_AST *n) {
LC_Intern *p = NULL;
if (n->kind == LC_ASTKind_TypespecIdent || n->kind == LC_ASTKind_ExprIdent) {
p = &n->eident.name;
}
if (LC_IsDecl(n)) {
p = &n->dbase.name;
}
if (p) {
LC_Intern user = *(LC_Intern *)ctx->user_data;
S8_String p8 = S8_MakeFromChar((char *)*p);
if (S8_Seek(p8, "Name")) {
S8_String new_name = S8_ReplaceAll(L->arena, p8, "Name", S8_MakeFromChar((char *)user));
*p = LC_InternStrLen(new_name.str, (int)new_name.len);
}
}
}
void BeforeCallArgsResolved(LC_AST *n, LC_Type *type) {
}
} // namespace Sandbox
bool sandbox() {
using namespace Sandbox;
LC_Lang *lang = LC_LangAlloc();
lang->use_colored_terminal_output = UseColoredIO;
lang->breakpoint_on_error = BreakpointOnError;
lang->on_typespec_parsed = RegisterMarkedTypes;
lang->before_call_args_resolved = BeforeCallArgsResolved;
LC_LangBegin(lang);
LC_RegisterPackageDir("../pkgs");
LC_RegisterPackageDir("../examples");
LC_Intern name = LC_ILit("sandbox");
LC_ParsePackagesPass(name);
LC_BuildIfPass();
if (L->errors) {
LC_LangEnd(lang);
return false;
}
TypesToGen.allocator = MA_GetAllocator(lang->arena);
//
// Remove dynamic array file
//
LC_AST *package = LC_GetPackageByName(name);
LC_AST *dynamic_array_file = NULL;
LC_ASTFor(it, package->apackage.ffile) {
S8_String path = S8_MakeFromChar((char *)it->afile.x->file);
if (S8_EndsWith(path, "dynamic_array.lc")) {
dynamic_array_file = it;
DLL_QUEUE_REMOVE(package->apackage.ffile, package->apackage.lfile, it);
break;
}
}
// Generate copies
LC_ASTWalker walker = LC_GetDefaultWalker(L->arena, WalkAndRename);
For(TypesToGen) {
LC_AST *new_array_file = LC_CopyAST(L->arena, dynamic_array_file);
walker.user_data = (void *)&it;
LC_WalkAST(&walker, new_array_file);
LC_DLLAdd(package->apackage.ffile, package->apackage.lfile, new_array_file);
}
LC_OrderAndResolveTopLevelPass(name);
LC_ResolveProcBodiesPass();
if (L->errors) {
LC_LangEnd(lang);
return false;
}
LC_String code = LC_GenerateUnityBuild();
S8_String path = "examples/sandbox/sandbox.c";
OS_MakeDir("examples/sandbox");
OS_WriteFile(path, code);
LC_LangEnd(lang);
if (UseCL) {
OS_CopyFile(RaylibDLL, "examples/sandbox/raylib.dll", true);
S8_String cmd = Fmt("cl %.*s -Zi -std:c11 -nologo -FC -Fd:examples/sandbox/a.pdb -Fe:examples/sandbox/sandbox.exe %.*s", S8_Expand(path), S8_Expand(RaylibLIB));
int errcode = Run(cmd);
if (errcode != 0) return false;
}
return true;
}

View File

@@ -1,96 +0,0 @@
FloatMin :: proc(a: float, b: float): float {
if (a > b) return b;
return a;
}
FloatMax :: proc(a: float, b: float): float {
if (a > b) return a;
return a;
}
FloatClamp :: proc(val: float, min: float, max: float): float {
if (val > max) return max;
if (val < min) return min;
return val;
}
IntMin :: proc(a: int, b: int): int {
if (a > b) return b;
return a;
}
IntMax :: proc(a: int, b: int): int {
if (a > b) return a;
return a;
}
IntClamp :: proc(val: int, min: int, max: int): int {
if (val > max) return max;
if (val < min) return min;
return val;
}
Rect2 :: struct {
min: Vector2;
max: Vector2;
}
CutLeft :: proc(r: *Rect2, value: float): Rect2 {
minx := r.min.x;
r.min.x = FloatMin(r.max.x, r.min.x + value);
return :Rect2{
{ minx, r.min.y},
{r.min.x, r.max.y},
};
}
CutRight :: proc(r: *Rect2, value: float): Rect2 {
maxx := r.max.x;
r.max.x = FloatMax(r.max.x - value, r.min.x);
return :Rect2{
{r.max.x, r.min.y},
{ maxx, r.max.y},
};
}
CutBottom :: proc(r: *Rect2, value: float): Rect2 { // Y is down
maxy := r.max.y;
r.max.y = FloatMax(r.min.y, r.max.y - value);
return :Rect2{
{r.min.x, r.max.y},
{r.max.x, maxy},
};
}
CutTop :: proc(r: *Rect2, value: float): Rect2 { // Y is down
miny := r.min.y;
r.min.y = FloatMin(r.min.y + value, r.max.y);
return :Rect2{
{r.min.x, miny},
{r.max.x, r.min.y},
};
}
Shrink :: proc(r: Rect2, value: float): Rect2 {
r.min.x += value;
r.max.x -= value;
r.min.y += value;
r.max.y -= value;
return r;
}
RectFromSize :: proc(pos: Vector2, size: Vector2): Rect2 {
result: Rect2 = {pos, Vector2Add(pos, size)};
return result;
}
GetRectSize :: proc(rect: Rect2): Vector2 {
result: Vector2 = {rect.max.x - rect.min.x, rect.max.y - rect.min.y};
return result;
}
RectToRectangle :: proc(rect: Rect2): Rectangle {
size := GetRectSize(rect);
result: Rectangle = {rect.min.x, rect.min.y, size.x, size.y};
return result;
}

View File

@@ -1,49 +0,0 @@
ArrayOfName :: struct {
data: *Name;
len: int;
cap: int;
}
TryGrowingNameArray :: proc(arr: *ArrayOfName) {
if (arr.len + 1 > arr.cap) {
cap := arr.cap * 2;
if (cap == 0) cap = 16;
arr.data = libc.realloc(arr.data, sizeof(arr.data[0]) * :libc.size_t(cap));
arr.cap = cap;
}
}
AddName :: proc(arr: *ArrayOfName, item: Name) {
TryGrowingNameArray(arr);
arr.data[arr.len] = item;
arr.len += 1;
}
InsertName :: proc(a: *ArrayOfName, item: Name, index: int) {
if index == a.len {
AddName(a, item);
return;
}
libc.assert(index < a.len);
libc.assert(index >= 0);
TryGrowingNameArray(a);
right_len := :libc.size_t(a.len - index);
libc.memmove(&a.data[index + 1], &a.data[index], sizeof(a.data[0]) * right_len);
a.data[index] = item;
a.len += 1;
}
GetLastName :: proc(a: ArrayOfName): *Name {
libc.assert(a.len > 0);
result := &a.data[a.len - 1];
return result;
}
PopName :: proc(a: *ArrayOfName): Name {
a.len -= 1;
result := a.data[a.len];
return result;
}

View File

@@ -1,93 +0,0 @@
import "raylib";
Tile :: struct {
value: int;
}
Map :: struct {
tiles: *Tile;
x: int;
y: int;
}
CreateMap :: proc(x: int, y: int, map: *int): Map {
result: Map = {x = x, y = y};
result.tiles = MemAlloc(:uint(x*y) * sizeof(:Tile));
for i := 0; i < x*y; i += 1 {
result.tiles[i].value = map[i];
}
return result;
}
main :: proc(): int {
TestArena();
return 0;
InitWindow(800, 600, "Thing");
SetTargetFPS(60);
XPIX :: 32;
YPIX :: 32;
camera: Camera2D = {
zoom = 1.0,
};
_map_x :: 8;
_map_y :: 8;
map := CreateMap(_map_x, _map_y, &:[_map_x * _map_y]int{
1,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
1,0,0,0,0,0,0,1,
0,0,0,0,1,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
}[0]);
for !WindowShouldClose() {
if IsMouseButtonDown(MOUSE_BUTTON_LEFT) {
delta := GetMouseDelta();
camera.offset = Vector2Add(camera.offset, delta);
}
BeginDrawing();
ClearBackground(RAYWHITE);
BeginMode2D(camera);
for y_it := 0; y_it < map.y; y_it += 1 {
for x_it := 0; x_it < map.x; x_it += 1 {
tile := &map.tiles[x_it + y_it * map.x];
original_rect := RectFromSize({XPIX * :float(x_it), YPIX * :float(y_it)}, {XPIX, YPIX});
rect := Shrink(original_rect, 2);
r := RectToRectangle(rect);
min_screen := GetWorldToScreen2D(original_rect.min, camera);
size := GetRectSize(original_rect);
screen_rect: Rectangle = {min_screen.x, min_screen.y, size.x, size.y};
mouse_p := GetMousePosition();
if tile.value == 1 {
DrawRectangleRec(r, RED);
} else {
DrawRectangleRec(r, GREEN);
}
if CheckCollisionPointRec(mouse_p, screen_rect) {
DrawRectangleRec(r, BLUE);
}
}
}
EndMode2D();
// DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY);
EndDrawing();
}
CloseWindow();
return 0;
}

View File

@@ -6,9 +6,9 @@ bool text_editor() {
defer { LC_LangEnd(lang); };
LC_RegisterPackageDir("../pkgs");
LC_RegisterPackageDir("../examples");
LC_RegisterPackageDir("../examples/text_editor");
LC_Intern name = LC_ILit("text_editor");
LC_Intern name = LC_ILit("entry_point");
LC_ParseAndResolve(name);
if (L->errors) return false;
@@ -26,7 +26,7 @@ bool text_editor() {
OS_WriteFile(path, code);
if (!UseCL) return true;
S8_String cmd = Fmt("cl %.*s -Zi -std:c11 -nologo -FC -Fd:examples/text_editor/a.pdb -Fe:examples/text_editor/text_editor.exe %.*s", S8_Expand(path), S8_Expand(RaylibLIB));
S8_String cmd = Fmt("cl %.*s ../src/core/core.c -Zi -std:c11 -nologo -FC -Fd:examples/text_editor/a.pdb -Fe:examples/text_editor/text_editor.exe %.*s", S8_Expand(path), S8_Expand(RaylibLIB));
int errcode = Run(cmd);
if (errcode != 0) return false;

View File

@@ -0,0 +1,43 @@
import "raylib";
import "libc";
import "std_types";
ClampInt :: proc(val: int, min: int, max: int): int {
result := val;
if (val < min) result = min;
if (val > max) result = max;
return result;
}
MinInt :: proc(a: int, b: int): int {
result := a;
if (a > b) result = b;
return result;
}
MaxInt :: proc(a: int, b: int): int {
result := b;
if (a > b) result = a;
return result;
}
MaxFloat :: proc(a: float, b: float): float {
if a > b return a;
return b;
}
MinFloat :: proc(a: float, b: float): float {
if a > b return b;
return a;
}
ClampFloat :: proc(val: float, min: float, max: float): float {
if (val > max) return max;
if (val < min) return min;
return val;
}
IsFlagSet :: proc(flags: u64, f: u64): bool {
result := flags & f;
return :bool(result);
}

View File

@@ -0,0 +1,394 @@
IO_MessageHandler :: typedef proc(a: int, b: *char, c: int, d: *char, e: int): void; @api
IO__FatalErrorf :: proc(file: *char, line: int, msg: *char, ...): bool; @api
IO__Printf :: proc(kind: int, file: *char, line: int, msg: *char, ...); @api
IO__FatalError :: proc(msg: *char): bool; @api
IO_Print :: proc(kind: int, file: *char, line: int, msg: *char, len: int); @api
IO_OutputMessage :: proc(str: *char, len: int); @api
IO_Exit :: proc(error_code: int); @api
IO_IsDebuggerPresent :: proc(): bool; @api
MV_Memory :: struct {
commit: usize;
reserve: usize;
data: *u8;
} @api
MA_Arena :: struct {
memory: MV_Memory;
alignment: int;
len: usize;
base_len: usize;
} @api
MA_Temp :: struct {
arena: *MA_Arena;
pos: usize;
} @api
MA_SourceLoc :: struct {
file: *char;
line: int;
} @api
MA_SaveSourceLocEx :: proc(file: *char, line: int); @api
MA_InitEx :: proc(a: *MA_Arena, reserve: usize); @api
MA_Init :: proc(a: *MA_Arena); @api
MA_Create :: proc(): MA_Arena; @api
MA_MakeSureInitialized :: proc(a: *MA_Arena); @api
MA_InitFromBuffer :: proc(arena: *MA_Arena, buffer: *void, size: usize); @api
MA_MakeFromBuffer :: proc(buffer: *void, size: usize): MA_Arena; @api
MA_Bootstrap :: proc(): *MA_Arena; @api
MA_PushArena :: proc(arena: *MA_Arena, size: usize): MA_Arena; @api
MA_PushArenaP :: proc(arena: *MA_Arena, size: usize): *MA_Arena; @api
MA__PushSizeNonZeroed :: proc(a: *MA_Arena, size: usize): *void; @api
MA__PushSize :: proc(arena: *MA_Arena, size: usize): *void; @api
MA__PushStringCopy :: proc(arena: *MA_Arena, p: *char, size: usize): *char; @api
MA__PushCopy :: proc(arena: *MA_Arena, p: *void, size: usize): *void; @api
MA_BeginTemp :: proc(arena: *MA_Arena): MA_Temp; @api
MA_EndTemp :: proc(checkpoint: MA_Temp); @api
MA_PopToPos :: proc(arena: *MA_Arena, pos: usize); @api
MA_PopSize :: proc(arena: *MA_Arena, size: usize); @api
MA_DeallocateArena :: proc(arena: *MA_Arena); @api
MA_Reset :: proc(arena: *MA_Arena); @api
MA_GetAlignOffset :: proc(size: usize, align: usize): usize; @api
MA_AlignUp :: proc(size: usize, align: usize): usize; @api
MA_AlignDown :: proc(size: usize, align: usize): usize; @api
MA_IsPointerInside :: proc(arena: *MA_Arena, p: *void): bool; @api
MA_SetAlignment :: proc(arena: *MA_Arena, alignment: int); @api
MA_GetTop :: proc(a: *MA_Arena): *u8; @api
MV_Reserve :: proc(size: usize): MV_Memory; @api
MV_Commit :: proc(m: *MV_Memory, commit: usize): bool; @api
MV_Deallocate :: proc(m: *MV_Memory); @api
MV_DecommitPos :: proc(m: *MV_Memory, pos: usize): bool; @api
MA_GetScratchEx :: proc(conflicts: **MA_Arena, conflict_count: int): MA_Temp; @api
MA_GetScratch :: proc(): MA_Temp; @api
MA_GetScratch1 :: proc(conflict: *MA_Arena): MA_Temp; @api
S8_Length :: proc(string: *char): i64; @api
S8_String :: struct {
str: *char;
len: i64;
} @api
S8_Node :: struct {
next: *S8_Node;
string: S8_String;
} @api
S8_List :: struct {
node_count: i64;
char_count: i64;
first: *S8_Node;
last: *S8_Node;
} @api
S16_String :: struct {
str: *wchar_t;
len: i64;
} @api
S8_FindFlag :: typedef int;
S8_SplitFlag :: typedef int;
CHAR_ToLowerCase :: proc(a: char): char; @api
CHAR_ToUpperCase :: proc(a: char): char; @api
CHAR_IsWhitespace :: proc(w: char): bool; @api
CHAR_IsAlphabetic :: proc(a: char): bool; @api
CHAR_IsIdent :: proc(a: char): bool; @api
CHAR_IsDigit :: proc(a: char): bool; @api
CHAR_IsAlphanumeric :: proc(a: char): bool; @api
S8_AreEqual :: proc(a: S8_String, b: S8_String, ignore_case: uint): bool; @api
S8_EndsWith :: proc(a: S8_String, end: S8_String, ignore_case: uint): bool; @api
S8_StartsWith :: proc(a: S8_String, start: S8_String, ignore_case: uint): bool; @api
S8_Make :: proc(str: *char, len: i64): S8_String; @api
S8_Copy :: proc(allocator: *MA_Arena, string: S8_String): S8_String; @api
S8_CopyChar :: proc(allocator: *MA_Arena, s: *char): S8_String; @api
S8_NormalizePath :: proc(allocator: *MA_Arena, s: S8_String): S8_String; @api
S8_NormalizePathUnsafe :: proc(s: S8_String); @api
S8_Chop :: proc(string: S8_String, len: i64): S8_String; @api
S8_Skip :: proc(string: S8_String, len: i64): S8_String; @api
S8_GetPostfix :: proc(string: S8_String, len: i64): S8_String; @api
S8_GetPrefix :: proc(string: S8_String, len: i64): S8_String; @api
S8_Slice :: proc(string: S8_String, first_index: i64, one_past_last_index: i64): S8_String; @api
S8_Trim :: proc(string: S8_String): S8_String; @api
S8_TrimEnd :: proc(string: S8_String): S8_String; @api
S8_ToLowerCase :: proc(allocator: *MA_Arena, s: S8_String): S8_String; @api
S8_ToUpperCase :: proc(allocator: *MA_Arena, s: S8_String): S8_String; @api
S8_Seek :: proc(string: S8_String, find: S8_String, flags: S8_FindFlag, index_out: *i64): bool; @api
S8_Find :: proc(string: S8_String, find: S8_String, flags: S8_FindFlag): i64; @api
S8_ChopLastSlash :: proc(s: S8_String): S8_String; @api
S8_ChopLastPeriod :: proc(s: S8_String): S8_String; @api
S8_SkipToLastSlash :: proc(s: S8_String): S8_String; @api
S8_SkipToLastPeriod :: proc(s: S8_String): S8_String; @api
S8_GetNameNoExt :: proc(s: S8_String): S8_String; @api
S8_IsPointerInside :: proc(string: S8_String, p: *char): bool; @api
S8_SkipToP :: proc(string: S8_String, p: *char): S8_String; @api
S8_SkipPast :: proc(string: S8_String, a: S8_String): S8_String; @api
S8_WideLength :: proc(string: *wchar_t): i64; @api
S8_MakeFromChar :: proc(string: *char): S8_String; @api
S8_MakeEmpty :: proc(): S8_String; @api
S8_MakeEmptyList :: proc(): S8_List; @api
S8_FormatV :: proc(allocator: *MA_Arena, str: *char, args1: va_list): S8_String; @api
S8_Format :: proc(allocator: *MA_Arena, str: *char, ...): S8_String; @api
S8_Split :: proc(allocator: *MA_Arena, string: S8_String, find: S8_String, flags: S8_SplitFlag): S8_List; @api
S8_MergeWithSeparator :: proc(allocator: *MA_Arena, list: S8_List, separator: S8_String): S8_String; @api
S8_Merge :: proc(allocator: *MA_Arena, list: S8_List): S8_String; @api
S8_ReplaceAll :: proc(allocator: *MA_Arena, string: S8_String, replace: S8_String, with: S8_String, ignore_case: bool): S8_String; @api
S8_FindAll :: proc(allocator: *MA_Arena, string: S8_String, find: S8_String, ignore_case: bool): S8_List; @api
S8_CreateNode :: proc(allocator: *MA_Arena, string: S8_String): *S8_Node; @api
S8_ReplaceNodeString :: proc(list: *S8_List, node: *S8_Node, new_string: S8_String); @api
S8_AddExistingNode :: proc(list: *S8_List, node: *S8_Node); @api
S8_AddArray :: proc(allocator: *MA_Arena, list: *S8_List, array: **char, count: int); @api
S8_AddArrayWithPrefix :: proc(allocator: *MA_Arena, list: *S8_List, prefix: *char, array: **char, count: int); @api
S8_MakeList :: proc(allocator: *MA_Arena, a: S8_String): S8_List; @api
S8_CopyList :: proc(allocator: *MA_Arena, a: S8_List): S8_List; @api
S8_ConcatLists :: proc(allocator: *MA_Arena, a: S8_List, b: S8_List): S8_List; @api
S8_AddNode :: proc(allocator: *MA_Arena, list: *S8_List, string: S8_String): *S8_Node; @api
S8_Add :: proc(allocator: *MA_Arena, list: *S8_List, string: S8_String): *S8_Node; @api
S8_AddF :: proc(allocator: *MA_Arena, list: *S8_List, str: *char, ...): S8_String; @api
S8_ToWidecharEx :: proc(allocator: *MA_Arena, string: S8_String): S16_String; @api
S8_ToWidechar :: proc(allocator: *MA_Arena, string: S8_String): *wchar_t; @api
S8_FromWidecharEx :: proc(allocator: *MA_Arena, wstring: *wchar_t, wsize: i64): S8_String; @api
S8_FromWidechar :: proc(allocator: *MA_Arena, wstring: *wchar_t): S8_String; @api
RandomSeed :: struct {
a: u64;
} @api
HashBytes :: proc(data: *void, size: u64): u64; @api
MakeRandomSeed :: proc(value: u64): RandomSeed; @api
GetRandomU64 :: proc(state: *RandomSeed): u64; @api
GetRandomRangeI :: proc(seed: *RandomSeed, first: int, last_included: int): int; @api
GetRandomNormal :: proc(series: *RandomSeed): double; @api
GetRandomNormalRange :: proc(seed: *RandomSeed, min: double, max: double): double; @api
HashMix :: proc(x: u64, y: u64): u64; @api
GetRandomNormalF :: proc(series: *RandomSeed): float; @api
MU__Float2 :: struct {
x: float;
y: float;
} @api
MU__Int2 :: struct {
x: int;
y: int;
} @api
MU_glGetProcAddress :: typedef proc(a: *char): *void; @api
MU_Window_Params :: struct {
size: MU__Int2;
pos: MU__Int2;
title: *char;
enable_canvas: bool;
resizable: bool;
borderless: bool;
fps_cursor: bool;
} @api
MU_Params :: struct {
memory: *void;
cap: usize;
enable_opengl: bool;
opengl_major: int;
opengl_minor: int;
delta_time: double;
window: MU_Window_Params;
sound_callback: proc(a: *MU_Context, b: *u16, c: u32): void; @api
} @api
MU_Key_State :: struct {
down: bool;
press: bool;
unpress: bool;
raw_press: bool;
} @api
MU_Key :: typedef int;
MU_Mouse_State :: struct {
pos: MU__Int2;
posf: MU__Float2;
delta_pos: MU__Int2;
delta_pos_normalized: MU__Float2;
left: MU_Key_State;
middle: MU_Key_State;
right: MU_Key_State;
delta_wheel: float;
} @api
MU_DroppedFile :: struct {
next: *MU_DroppedFile;
filename: *char;
filename_size: int;
} @api
MU_Arena :: struct {
memory: *char;
len: usize;
cap: usize;
} @api
MU_Window :: struct {
size: MU__Int2;
sizef: MU__Float2;
pos: MU__Int2;
posf: MU__Float2;
dpi_scale: float;
is_fullscreen: bool;
is_fps_mode: bool;
is_focused: bool;
change_cursor_on_mouse_hold: bool;
processed_events_this_frame: u64; @api
should_render: bool;
first_dropped_file: *MU_DroppedFile;
canvas: *u32;
canvas_enabled: bool;
mouse: MU_Mouse_State;
key: [140]MU_Key_State;
user_text32: [32]u32;
user_text32_count: int;
user_text8: [32]char;
user_text8_count: int;
next: *MU_Window;
handle: *void;
platform: *void;
} @api
MU_Time :: struct {
app_start: double;
frame_start: double;
update: double;
update_total: double;
delta: double;
deltaf: float;
total: double;
totalf: float;
} @api
MU_Sound :: struct {
initialized: bool;
samples_per_second: uint;
number_of_channels: uint;
bytes_per_sample: uint;
callback: proc(a: *MU_Context, b: *u16, c: u32): void; @api
} @api
MU_Context :: struct {
quit: bool;
sound: MU_Sound;
time: MU_Time;
first_frame: bool;
_MU_Update_count: int;
frame: usize;
consecutive_missed_frames: usize;
total_missed_frames: usize;
primary_monitor_size: MU__Int2;
opengl_initialized: bool;
opengl_major: int;
opengl_minor: int;
gl_get_proc_address: proc(a: *char): *void; @api
params: MU_Params;
window: *MU_Window;
all_windows: *MU_Window;
perm_arena: MU_Arena;
frame_arena: MU_Arena;
platform: *void;
} @api
MU_Quit :: proc(mu: *MU_Context); @api
MU_DefaultSoundCallback :: proc(mu: *MU_Context, buffer: *u16, samples_to_fill: u32); @api
MU_GetTime :: proc(): double; @api
MU_ToggleFPSMode :: proc(window: *MU_Window); @api
MU_DisableFPSMode :: proc(window: *MU_Window); @api
MU_EnableFPSMode :: proc(window: *MU_Window); @api
MU_ToggleFullscreen :: proc(window: *MU_Window); @api
MU_Init :: proc(mu: *MU_Context, params: MU_Params, len: usize); @api
MU_AddWindow :: proc(mu: *MU_Context, params: MU_Window_Params): *MU_Window; @api
MU_InitWindow :: proc(mu: *MU_Context, window: *MU_Window, params: MU_Window_Params); @api
MU_Start :: proc(params: MU_Params): *MU_Context; @api
MU_Update :: proc(mu: *MU_Context): bool; @api
LIB_Library :: typedef *void;
LIB_LoadLibrary :: proc(str: *char): LIB_Library; @api
LIB_LoadSymbol :: proc(lib: LIB_Library, symbol: *char): *void; @api
LIB_UnloadLibrary :: proc(lib: LIB_Library): bool; @api
OS_Result :: typedef int;
OS_SUCCESS :: 0;
OS_ALREADY_EXISTS :: ^;
OS_PATH_NOT_FOUND :: ^;
OS_FAILURE :: ^;
OS_Date :: struct {
year: u32;
month: u32;
day: u32;
hour: u32;
minute: u32;
second: u32;
} @api
OS_IsAbsolute :: proc(path: S8_String): bool; @api
OS_GetExePath :: proc(arena: *MA_Arena): S8_String; @api
OS_GetExeDir :: proc(arena: *MA_Arena): S8_String; @api
OS_GetWorkingDir :: proc(arena: *MA_Arena): S8_String; @api
OS_SetWorkingDir :: proc(path: S8_String); @api
OS_GetAbsolutePath :: proc(arena: *MA_Arena, relative: S8_String): S8_String; @api
OS_FileExists :: proc(path: S8_String): bool; @api
OS_IsDir :: proc(path: S8_String): bool; @api
OS_IsFile :: proc(path: S8_String): bool; @api
OS_GetTime :: proc(): double; @api
OS_MakeDir :: proc(path: S8_String): OS_Result; @api
OS_CopyFile :: proc(from: S8_String, to: S8_String, overwrite: bool): OS_Result; @api
OS_DeleteFile :: proc(path: S8_String): OS_Result; @api
OS_DeleteDir :: proc(path: S8_String, flags: uint): OS_Result; @api
OS_AppendFile :: proc(path: S8_String, string: S8_String): OS_Result; @api
OS_WriteFile :: proc(path: S8_String, string: S8_String): OS_Result; @api
OS_ReadFile :: proc(arena: *MA_Arena, path: S8_String): S8_String; @api
OS_SystemF :: proc(string: *char, ...): int; @api
OS_GetFileModTime :: proc(file: S8_String): i64; @api
OS_GetDate :: proc(): OS_Date; @api
UTF_CreateStringFromWidechar :: proc(arena: *MA_Arena, wstr: *wchar_t, wsize: i64): S8_String; @api
OS_ExpandIncludesList :: proc(arena: *MA_Arena, out: *S8_List, filepath: S8_String): bool; @api
OS_ExpandIncludes :: proc(arena: *MA_Arena, filepath: S8_String): S8_String; @api
OS_EnableTerminalColors :: proc(): bool; @api
OS_IsValid :: proc(it: OS_FileIter): bool; @api
OS_Advance :: proc(it: *OS_FileIter); @api
OS_IterateFiles :: proc(scratch_arena: *MA_Arena, path: S8_String): OS_FileIter; @api
OS_FileIter :: struct {
is_valid: bool;
is_directory: bool;
absolute_path: S8_String;
relative_path: S8_String;
filename: S8_String;
path: S8_String;
arena: *MA_Arena;
_: OS_FileIterPlatform;
} @api
OS_FileIterPlatform :: union {
dir: *void;
w32: *void;
} @api
M_AllocatorOp :: typedef int;
M_AllocatorOp_Invalid :: 0;
M_AllocatorOp_Allocate :: ^;
M_AllocatorOp_Deallocate :: ^;
M_AllocatorOp_Reallocate :: ^;
M_AllocatorProc :: typedef proc(a: *void, b: M_AllocatorOp, c: *void, d: usize, e: usize): *void; @api
MA_AllocatorProc :: proc(allocator: *void, kind: M_AllocatorOp, p: *void, size: usize, old_size: usize): *void; @api
MA_ExclusiveAllocatorProc :: proc(allocator: *void, kind: M_AllocatorOp, p: *void, size: usize, old_size: usize): *void; @api
M_Allocator :: struct {
obj: *int;
p: *M_AllocatorProc; @api
} @api
M__AllocNonZeroed :: proc(allocator: M_Allocator, size: usize): *void; @api
M__Alloc :: proc(allocator: M_Allocator, size: usize): *void; @api
M__AllocCopy :: proc(allocator: M_Allocator, p: *void, size: usize): *void; @api
M__Realloc :: proc(allocator: M_Allocator, p: *void, size: usize, old_size: usize): *void; @api
M__Dealloc :: proc(allocator: M_Allocator, p: *void); @api
M_GetSystemAllocator :: proc(): M_Allocator; @api
MA_GetExclusiveAllocator :: proc(arena: *MA_Arena): M_Allocator; @api
MA_GetAllocator :: proc(arena: *MA_Arena): M_Allocator; @api
MA_BootstrapExclusive :: proc(): M_Allocator; @api

View File

@@ -3,22 +3,6 @@ Rect2P :: struct {
max: Vector2;
}
F32_Max :: proc(a: f32, b: f32): f32 {
if a > b return a;
return b;
}
F32_Min :: proc(a: f32, b: f32): f32 {
if a > b return b;
return a;
}
F32_Clamp :: proc(val: f32, min: f32, max: f32): f32 {
if (val > max) return max;
if (val < min) return min;
return val;
}
GetRectSize :: proc(rect: Rect2P): Vector2 {
result: Vector2 = {rect.max.x - rect.min.x, rect.max.y - rect.min.y};
return result;
@@ -36,7 +20,7 @@ GetRectX :: proc(rect: Rect2P): f32 {
CutLeft :: proc(r: *Rect2P, value: f32): Rect2P {
minx := r.min.x;
r.min.x = F32_Min(r.max.x, r.min.x + value);
r.min.x = MinFloat(r.max.x, r.min.x + value);
return :Rect2P{
{ minx, r.min.y},
{r.min.x, r.max.y},
@@ -45,7 +29,7 @@ CutLeft :: proc(r: *Rect2P, value: f32): Rect2P {
CutRight :: proc(r: *Rect2P, value: f32): Rect2P {
maxx := r.max.x;
r.max.x = F32_Max(r.max.x - value, r.min.x);
r.max.x = MaxFloat(r.max.x - value, r.min.x);
return :Rect2P{
{r.max.x, r.min.y},
{ maxx, r.max.y},
@@ -54,7 +38,7 @@ CutRight :: proc(r: *Rect2P, value: f32): Rect2P {
CutBottom :: proc(r: *Rect2P, value: f32): Rect2P { // Y is down
maxy := r.max.y;
r.max.y = F32_Max(r.min.y, r.max.y - value);
r.max.y = MaxFloat(r.min.y, r.max.y - value);
return :Rect2P{
{r.min.x, r.max.y},
{r.max.x, maxy},
@@ -63,7 +47,7 @@ CutBottom :: proc(r: *Rect2P, value: f32): Rect2P { // Y is down
CutTop :: proc(r: *Rect2P, value: f32): Rect2P { // Y is down
miny := r.min.y;
r.min.y = F32_Min(r.min.y + value, r.max.y);
r.min.y = MinFloat(r.min.y + value, r.max.y);
return :Rect2P{
{r.min.x, miny},
{r.max.x, r.min.y},

View File

@@ -0,0 +1,113 @@
/*
- Embedded windows
- Multiple buffers at the same time
- Ctrl+C
- Ctrl+V
- Ctrl+X
- Open a document dialog, save document to disk
- Buffer bound undo,redo
*/
import "raylib";
import "std_types";
import "libc";
import "core";
import TE "text_editor";
InvalidCodepath :: proc() {
assert(:*char("invalid codepath") == :*char(""));
}
main :: proc(): int {
InitWindow(800, 600, "TextEditor");
SetWindowState(FLAG_WINDOW_RESIZABLE);
SetTargetFPS(60);
font_size: float = 14;
font_spacing: float = 1;
font: Font = LoadFontEx("C:/Windows/Fonts/consola.ttf", :int(font_size), nil, 0);
glyph_info: GlyphInfo = GetGlyphInfo(font, 'A');
size := MeasureTextEx(font, "A", font_size, font_spacing);
TE.Monosize = {:float(glyph_info.image.width), size.y};
SANDBOX_TEXT_EDITOR :: 1;
SANDBOX_PROTOTYPE :: 2;
sandbox_chosen := SANDBOX_TEXT_EDITOR;
for !WindowShouldClose() {
screen_size: Vector2 = {:f32(GetScreenWidth()), :f32(GetScreenHeight())};
screen_rect := Rect2PSize(0, 0, screen_size.x, screen_size.y);
top_bar := CutTop(&screen_rect, 30);
top_bar_original := top_bar;
button1_text := "Text Editor";
button1_text_size := MeasureTextEx(font, button1_text, font_size, font_spacing);
button1 := CutLeft(&top_bar, :float(button1_text_size.x) * 1.5);
button1 = Shrink(button1, 4);
button1_text_pos: Vector2 = {
x = button1.min.x + (GetRectX(button1) - :float(button1_text_size.x)) * 0.5,
y = button1.min.y + (GetRectY(button1) - :float(button1_text_size.y)) * 0.7,
};
button1_hover := false;
button1_click := false;
if CheckCollisionPointRec(GetMousePosition(), Rect2PToRectangle(button1)) {
button1_hover = true;
if IsMouseButtonPressed(MOUSE_BUTTON_LEFT) {
button1_click = true;
}
}
button2_text := "Prototype";
button2_text_size := MeasureTextEx(font, button2_text, font_size, font_spacing);
button2 := CutLeft(&top_bar, :float(button2_text_size.x) * 1.5);
button2 = Shrink(button2, 4);
button2_text_pos: Vector2 = {
x = button2.min.x + (GetRectX(button2) - :float(button2_text_size.x)) * 0.5,
y = button2.min.y + (GetRectY(button2) - :float(button2_text_size.y)) * 0.7,
};
button2_hover := false;
button2_click := false;
if CheckCollisionPointRec(GetMousePosition(), Rect2PToRectangle(button2)) {
button2_hover = true;
if IsMouseButtonPressed(MOUSE_BUTTON_LEFT) {
button2_click = true;
}
}
if button1_click {
sandbox_chosen = SANDBOX_TEXT_EDITOR;
} else if button2_click {
sandbox_chosen = SANDBOX_PROTOTYPE;
}
BeginDrawing();
ClearBackground(RAYWHITE);
if sandbox_chosen == SANDBOX_TEXT_EDITOR {
TE.UpdateTextEditor(screen_rect, font, font_size, font_spacing);
} else if sandbox_chosen == SANDBOX_PROTOTYPE {
UpdatePrototype(screen_rect, font, font_size, font_spacing);
}
TE.DrawRect(top_bar_original, LIGHTGRAY);
DrawRectangleRoundedLines(Rect2PToRectangle(button1), 0.3, 12, 2, BLACK);
if button1_hover DrawRectangleRounded(Rect2PToRectangle(button1), 0.3, 12, WHITE);
DrawTextEx(font, button1_text, button1_text_pos, font_size, font_spacing, BLACK);
DrawRectangleRoundedLines(Rect2PToRectangle(button2), 0.3, 12, 2, BLACK);
if button2_hover DrawRectangleRounded(Rect2PToRectangle(button2), 0.3, 12, WHITE);
DrawTextEx(font, button2_text, button2_text_pos, font_size, font_spacing, BLACK);
EndDrawing();
}
CloseWindow();
return 0;
}

View File

@@ -0,0 +1,3 @@
UpdatePrototype :: proc(rect: Rect2P, font: Font, font_size: float, font_spacing: float) {
}

View File

@@ -27,25 +27,6 @@ GetRangeSize :: proc(range: Range): int {
return result;
}
ClampInt :: proc(val: int, min: int, max: int): int {
result := val;
if (val < min) result = min;
if (val > max) result = max;
return result;
}
MinInt :: proc(a: int, b: int): int {
result := a;
if (a > b) result = b;
return result;
}
MaxInt :: proc(a: int, b: int): int {
result := b;
if (a > b) result = a;
return result;
}
AdjustUTF8PosUnsafe :: proc(buffer: *Buffer, pos: int, direction: int = 1): int {
for pos >= 0 && pos < buffer.len && IsUTF8ContinuationByte(buffer.data[pos]) {
pos += direction;
@@ -53,10 +34,25 @@ AdjustUTF8PosUnsafe :: proc(buffer: *Buffer, pos: int, direction: int = 1): int
return pos;
}
GetBufferEnd :: proc(buffer: *Buffer): int {
result := MaxInt(0, buffer.len - 1);
return result;
}
GetBufferEndRange :: proc(buffer: *Buffer): Range {
result := GetBufferEnd(buffer);
return {result, result};
}
GetEntireBufferRange :: proc(buffer: *Buffer): Range {
result: Range = {0, GetBufferEnd(buffer)};
return result;
}
AdjustUTF8Pos :: proc(buffer: *Buffer, pos: int, direction: int = 1): int {
assert(direction == 1 || direction == -1);
pos = AdjustUTF8PosUnsafe(buffer, pos, direction);
pos = ClampInt(pos, 0, buffer.len - 1);
pos = ClampInt(pos, 0, GetBufferEnd(buffer));
if (buffer.data) assert(!IsUTF8ContinuationByte(buffer.data[pos]));
return pos;
}
@@ -150,8 +146,7 @@ GetStringFromBuffer :: proc(buffer: *Buffer, range: Range): String {
}
AddText :: proc(buffer: *Buffer, text: String) {
end_of_buffer: Range = {buffer.len - 1, buffer.len - 1};
ReplaceText(buffer, end_of_buffer, text);
ReplaceText(buffer, GetBufferEndRange(buffer), text);
}
FindLineOfPos :: proc(buffer: *Buffer, pos: int): LineInfo {
@@ -223,7 +218,7 @@ SeekOnWordBoundary :: proc(buffer: *Buffer, pos: int, direction: int = GO_FORWAR
seek_whitespace := standing_on_whitespace == false;
seek_word := standing_on_whitespace;
end := buffer.len - 1;
end := GetBufferEnd(buffer);
if (direction == GO_BACKWARD) end = 0;
result := end;

View File

@@ -1,14 +1,45 @@
/*
- Ctrl+C
- Ctrl+V
- Ctrl+X
- Windows
- Multiple buffers at the same time
*/
import "raylib";
import "std_types";
import "raylib";
import "libc";
import "core";
Inited := false;
TeBuffer: Buffer;
FocusedWindow: *Window;
WindowStack: [8]Window;
WindowStackCount: int;
UpdateTextEditor :: proc(rect: Rect2P, font: Font, font_size: float, font_spacing: float) {
if !Inited {
Inited = true;
file_content := LoadFileText("C:/Work/language/examples/text_editor/entry_point/entry_point.lc");
AddText(&TeBuffer, {file_content, :int(strlen(file_content))});
UnloadFileText(file_content);
AddWindow({buffer = &TeBuffer});
AddWindow({buffer = &TeBuffer});
FocusedWindow = &WindowStack[0];
}
ComputeWindowRects(rect);
UpdateAndDrawWindows(font, font_size);
}
WindowFlags_DrawScrollbar :: 1;
Window :: struct {
flags: u64;
buffer: *Buffer;
cursor: Selection;
scroll: Vector2;
mouse_scrolling: bool;
mouse_selecting: bool;
rect: Rect2P;
}
Selection :: struct {
a: int;
b: int;
@@ -19,19 +50,6 @@ GetRange :: proc(s: Selection): Range {
return result;
}
Window :: struct {
buffer: *Buffer;
cursor: Selection;
scroll: Vector2;
mouse_scrolling: bool;
rect: Rect2P;
}
FocusedWindow: *Window;
WindowStack: [8]Window;
WindowStackCount: int;
AddWindow :: proc(window: Window) {
if (WindowStackCount + 1 >= 8) return;
@@ -45,6 +63,7 @@ ComputeWindowRects :: proc(screen_rect: Rect2P) {
}
UpdateAndDrawWindows :: proc(font: Font, font_size: float) {
SetMouseCursor(MOUSE_CURSOR_DEFAULT);
for i := 0; i < WindowStackCount; i += 1 {
window: *Window = &WindowStack[i];
UpdateAndDrawWindow(window, font, font_size);
@@ -54,9 +73,11 @@ UpdateAndDrawWindows :: proc(font: Font, font_size: float) {
UpdateAndDrawWindow :: proc(w: *Window, font: Font, font_size: float) {
initial_cursor: Selection = w.cursor;
text_window_rect := w.rect;
bar := CutRight(&text_window_rect, 10);
bar_rect := CutRight(&text_window_rect, 10);
horizontal_bar_rect := CutBottom(&text_window_rect, 10);
// line_numbers_rect := CutLeft(&text_window_rect, Monosize.x * 4);
buffer_end_vpos := CalculateVisualPos(w.buffer, w.buffer.len - 1);
buffer_end_vpos := CalculateVisualPos(w.buffer, GetBufferEnd(w.buffer));
buffer_end_wpos := CalculateWorldPosUnscrolled(buffer_end_vpos);
if CheckCollisionPointRec(GetMousePosition(), Rect2PToRectangle(w.rect)) {
@@ -68,7 +89,6 @@ UpdateAndDrawWindow :: proc(w: *Window, font: Font, font_size: float) {
}
}
if w == FocusedWindow {
if IsKeyPressed(KEY_LEFT) || IsKeyPressedRepeat(KEY_LEFT) {
if IsKeyDown(KEY_LEFT_SHIFT) {
@@ -226,6 +246,12 @@ UpdateAndDrawWindow :: proc(w: *Window, font: Font, font_size: float) {
}
}
// @todo: buffer.len abstract
if IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_A) {
w.cursor.a = 0;
w.cursor.b = GetBufferEnd(w.buffer);
}
if IsKeyPressed(KEY_PAGE_DOWN) || IsKeyPressedRepeat(KEY_PAGE_DOWN) {
vpos := CalculateVisualPos(w.buffer, w.cursor.b);
move_by := :int(roundf(GetRectY(text_window_rect) / Monosize.y));
@@ -304,6 +330,7 @@ UpdateAndDrawWindow :: proc(w: *Window, font: Font, font_size: float) {
if CheckCollisionPointRec(mouse_p, Rect2PToRectangle(w.rect)) {
if CheckCollisionPointRec(mouse_p, Rect2PToRectangle(text_window_rect)) && !w.mouse_scrolling {
if IsMouseButtonPressed(MOUSE_BUTTON_LEFT) {
w.mouse_selecting = true;
p := Vector2Add(mouse_p, w.scroll);
p = Vector2Subtract(p, text_window_rect.min);
p = Vector2Divide(p, Monosize);
@@ -311,26 +338,30 @@ UpdateAndDrawWindow :: proc(w: *Window, font: Font, font_size: float) {
y := :int(floorf(p.y));
w.cursor.a = CalculatePosFromVisualPos(w.buffer, {x, y});
w.cursor.b = w.cursor.a;
} else if IsMouseButtonDown(MOUSE_BUTTON_LEFT) {
p := Vector2Add(mouse_p, w.scroll);
p = Vector2Subtract(p, text_window_rect.min);
p = Vector2Divide(p, Monosize);
x := :int(floorf(p.x));
y := :int(floorf(p.y));
w.cursor.b = CalculatePosFromVisualPos(w.buffer, {x, y});
}
SetMouseCursor(MOUSE_CURSOR_IBEAM);
} else {
SetMouseCursor(MOUSE_CURSOR_DEFAULT);
if IsMouseButtonPressed(MOUSE_BUTTON_LEFT) {
w.mouse_scrolling = true;
}
}
}
if w.mouse_scrolling {
mouse_scroll_marker_normalized := (mouse_p.y - w.rect.min.y) / GetRectY(bar);
if w.mouse_selecting && IsMouseButtonDown(MOUSE_BUTTON_LEFT) {
SetMouseCursor(MOUSE_CURSOR_DEFAULT);
p := Vector2Add(mouse_p, w.scroll);
p = Vector2Subtract(p, text_window_rect.min);
p = Vector2Divide(p, Monosize);
x := :int(floorf(p.x));
y := :int(floorf(p.y));
w.cursor.b = CalculatePosFromVisualPos(w.buffer, {x, y});
} else {
w.mouse_selecting = false;
}
if IsFlagSet(w.flags, WindowFlags_DrawScrollbar) && w.mouse_scrolling {
mouse_scroll_marker_normalized := (mouse_p.y - w.rect.min.y) / GetRectY(bar_rect);
w.scroll.y = mouse_scroll_marker_normalized * buffer_end_wpos.y;
if IsMouseButtonReleased(MOUSE_BUTTON_LEFT) w.mouse_scrolling = false;
@@ -362,22 +393,28 @@ UpdateAndDrawWindow :: proc(w: *Window, font: Font, font_size: float) {
}
}
BeginScissorMode(:int(text_window_rect.min.x), :int(text_window_rect.min.y), :int(GetRectX(text_window_rect)), :int(GetRectY(text_window_rect)));
BeginScissorMode(:int(w.rect.min.x), :int(w.rect.min.y), :int(GetRectX(w.rect)), :int(GetRectY(w.rect)));
// Draw text
// Draw text and line numbers
{
FONT_SPACING :: 1;
// DrawRect(line_numbers_rect, LIGHTGRAY);
miny = ClampInt(miny, 0, w.buffer.lines.len - 1);
maxy = ClampInt(maxy, 0, w.buffer.lines.len - 1);
for y := miny; y <= maxy; y += 1 {
line := w.buffer.lines.data[y];
line_range := w.buffer.lines.data[y];
string := AllocStringFromBuffer(w.buffer, line, null_terminate = true);
string := AllocStringFromBuffer(w.buffer, line_range, null_terminate = true);
defer free(string.str);
pos := CalculateWorldPos(w.scroll, {0, y});
pos_adjusted_by_buffer := Vector2Add(pos, text_window_rect.min);
FONT_SPACING :: 1;
DrawTextEx(font, string.str, pos_adjusted_by_buffer, font_size, FONT_SPACING, BLACK);
// line_number_pos: Vector2 = {w.rect.min.x, pos_adjusted_by_buffer.y};
// line_number_string := TextFormat("%d", y);
// DrawTextEx(font, line_number_string, line_number_pos, font_size, FONT_SPACING, GRAY);
}
}
@@ -391,7 +428,7 @@ UpdateAndDrawWindow :: proc(w: *Window, font: Font, font_size: float) {
world_pos_adjusted_by_buffer := Vector2Add(world_pos, text_window_rect.min);
rect := Rect2PSize(world_pos_adjusted_by_buffer.x, world_pos_adjusted_by_buffer.y, Monosize.x, Monosize.y);
DrawRect(rect, {0, 255, 0, 40});
DrawRect(rect, {0, 92, 222, 40});
pos.x += 1;
if iter.item == '\n' {
@@ -418,55 +455,18 @@ UpdateAndDrawWindow :: proc(w: *Window, font: Font, font_size: float) {
// Draw bar
{
DrawRect(bar, LIGHTGRAY);
if IsFlagSet(w.flags, WindowFlags_DrawScrollbar) {
DrawRect(bar_rect, LIGHTGRAY);
DrawRect(horizontal_bar_rect, LIGHTGRAY);
scroll_start_normalized := :f32(w.scroll.y) / :f32(buffer_end_wpos.y);
scroll_start := scroll_start_normalized * GetRectSize(bar).y;
CutTop(&bar, scroll_start);
marker := CutTop(&bar, 20);
scroll_start := scroll_start_normalized * GetRectSize(bar_rect).y;
CutTop(&bar_rect, scroll_start);
marker := CutTop(&bar_rect, 20);
DrawRect(marker, GRAY);
}
}
InvalidCodepath :: proc() {
assert(:*char("invalid codepath") == :*char(""));
}
main :: proc(): int {
InitWindow(800, 600, "TextEditor");
SetWindowState(FLAG_WINDOW_RESIZABLE | FLAG_WINDOW_MAXIMIZED);
SetTargetFPS(60);
font_size: float = 14;
font_spacing: float = 1;
font: Font = LoadFontEx("C:/Windows/Fonts/consola.ttf", :int(font_size), nil, 0);
glyph_info: GlyphInfo = GetGlyphInfo(font, 'A');
size := MeasureTextEx(font, "A", font_size, font_spacing);
Monosize = {:float(glyph_info.image.width), size.y};
buffer: Buffer;
file_content := LoadFileText("C:/Work/language/examples/text_editor/main.lc");
AddText(&buffer, {file_content, :int(strlen(file_content))});
UnloadFileText(file_content);
AddWindow({buffer = &buffer});
AddWindow({buffer = &buffer});
FocusedWindow = &WindowStack[0];
for !WindowShouldClose() {
screen_size: Vector2 = {:f32(GetScreenWidth()), :f32(GetScreenHeight())};
screen_rect := Rect2PSize(0, 0, screen_size.x, screen_size.y);
ComputeWindowRects(screen_rect);
BeginDrawing();
ClearBackground(RAYWHITE);
UpdateAndDrawWindows(font, font_size);
EndDrawing();
if w != FocusedWindow {
DrawRect(w.rect, {0,0,0,20});
}
CloseWindow();
return 0;
}
}

View File

@@ -1045,9 +1045,9 @@ LC_FUNCTION void LC_ResolveProcBodiesPass(void); // The Parse an
LC_FUNCTION void LC_FindUnusedLocalsAndRemoveUnusedGlobalDeclsPass(void); // Extended pass that you can execute once you have resolved all packages
// These three functions are used to implement LC_FindUnusedLocalsAndRemoveUnusedGlobalDeclsPass
LC_FUNCTION LC_Map LC_CountDeclRefs(LC_Arena *arena);
LC_FUNCTION void LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits);
LC_FUNCTION void LC_ErrorOnUnreferencedLocalsPass(LC_Map *map_of_visits);
LC_FUNCTION void LC_CountDeclRefs(LC_Arena *arena, LC_Map *map, LC_AST *ast);
LC_FUNCTION LC_Decl *LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits);
LC_FUNCTION void LC_ErrorOnUnreferencedLocalsPass(LC_Map *map_of_visits);
// Notes
LC_FUNCTION void LC_DeclareNote(LC_Intern intern);
@@ -6855,16 +6855,15 @@ LC_FUNCTION LC_Operand LC_ResolveExprEx(LC_AST *n) {
} break;
case LC_ASTKind_ExprField: {
bool first_part_executed = false;
bool resolved_import = false;
LC_Operand op = {0};
if (n->efield.left->kind == LC_ASTKind_ExprIdent) {
LC_AST *nf = n->efield.left;
LC_Operand LC_PROP_ERROR(op_name, nf, LC_ResolveName(nf, nf->eident.name));
// LC_Match (Package.) and fold (Package.Other) into just (Other)
if (op_name.decl->kind == LC_DeclKind_Import) {
first_part_executed = true;
resolved_import = true;
nf->eident.resolved_decl = op_name.decl;
nf->type = L->tvoid;
@@ -6872,7 +6871,7 @@ LC_FUNCTION LC_Operand LC_ResolveExprEx(LC_AST *n) {
}
}
if (!first_part_executed) {
if (!resolved_import) {
LC_ASTKind left_kind = n->efield.left->kind;
LC_PROP_ERROR(op, n, LC_ResolveExpr(n->efield.left));
@@ -6882,8 +6881,17 @@ LC_FUNCTION LC_Operand LC_ResolveExprEx(LC_AST *n) {
LC_PROP_ERROR(op, n, LC_ResolveNameInScope(n, type->decl));
LC_ASSERT(n, op.decl->kind == LC_DeclKind_Var);
result.flags |= LC_OPF_LValue | LC_OPF_Const;
result.val = op.decl->val;
} else {
result.val = op.decl->val;
// @copy_paste from ExprIdent
if (op.decl->kind == LC_DeclKind_Const) {
result.flags |= LC_OPF_UTConst | LC_OPF_Const;
SetConstVal(n, result.val);
} else {
result.flags |= LC_OPF_LValue | LC_OPF_Const;
}
}
result.val = op.decl->val;
} break;
case LC_ASTKind_ExprCall: {
@@ -9891,20 +9899,16 @@ LC_FUNCTION void WalkAndCountDeclRefs(LC_ASTWalker *ctx, LC_AST *n) {
}
}
LC_FUNCTION LC_Map LC_CountDeclRefs(LC_Arena *arena) {
LC_Map map = {arena};
LC_MapReserve(&map, 512);
LC_AST *package = LC_GetPackageByName(L->first_package);
LC_ASTWalker walker = LC_GetDefaultWalker(arena, WalkAndCountDeclRefs);
walker.user_data = (void *)&map;
walker.visit_notes = true;
LC_WalkAST(&walker, package);
return map;
LC_FUNCTION void LC_CountDeclRefs(LC_Arena *arena, LC_Map *map, LC_AST *ast) {
LC_ASTWalker walker = LC_GetDefaultWalker(arena, WalkAndCountDeclRefs);
walker.user_data = (void *)map;
walker.visit_notes = true;
LC_WalkAST(&walker, ast);
}
LC_FUNCTION void LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits) {
LC_FUNCTION LC_Decl *LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits) {
LC_Decl *first_removed_decl = NULL;
LC_Decl *last_removed_decl = NULL;
for (LC_ASTRef *it = L->ordered_packages.first; it; it = it->next) {
for (LC_Decl *decl = it->ast->apackage.ext->first_ordered; decl;) {
intptr_t ref_count = (intptr_t)LC_MapGetP(map_of_visits, decl);
@@ -9913,9 +9917,11 @@ LC_FUNCTION void LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits) {
decl = decl->next;
if (ref_count == 0 && remove->foreign_name != LC_ILit("main")) {
LC_DLLRemove(it->ast->apackage.ext->first_ordered, it->ast->apackage.ext->last_ordered, remove);
LC_DLLAdd(first_removed_decl, last_removed_decl, remove);
}
}
}
return first_removed_decl;
}
LC_FUNCTION void LC_ErrorOnUnreferencedLocalsPass(LC_Map *map_of_visits) {
@@ -9939,9 +9945,16 @@ LC_FUNCTION void LC_FindUnusedLocalsAndRemoveUnusedGlobalDeclsPass(void) {
if (L->errors) return;
LC_TempArena check = LC_BeginTemp(L->arena);
LC_Map map = LC_CountDeclRefs(check.arena);
LC_AST *package = LC_GetPackageByName(L->first_package);
LC_Map map = {check.arena};
LC_MapReserve(&map, 512);
LC_CountDeclRefs(check.arena, &map, package);
LC_Decl *first_removed_decl = LC_RemoveUnreferencedGlobalDeclsPass(&map);
for (LC_Decl *it = first_removed_decl; it; it = it->next) {
LC_CountDeclRefs(check.arena, &map, it->ast);
}
LC_ErrorOnUnreferencedLocalsPass(&map);
LC_RemoveUnreferencedGlobalDeclsPass(&map);
LC_EndTemp(check);
}

View File

@@ -16,20 +16,16 @@ LC_FUNCTION void WalkAndCountDeclRefs(LC_ASTWalker *ctx, LC_AST *n) {
}
}
LC_FUNCTION LC_Map LC_CountDeclRefs(LC_Arena *arena) {
LC_Map map = {arena};
LC_MapReserve(&map, 512);
LC_AST *package = LC_GetPackageByName(L->first_package);
LC_ASTWalker walker = LC_GetDefaultWalker(arena, WalkAndCountDeclRefs);
walker.user_data = (void *)&map;
walker.visit_notes = true;
LC_WalkAST(&walker, package);
return map;
LC_FUNCTION void LC_CountDeclRefs(LC_Arena *arena, LC_Map *map, LC_AST *ast) {
LC_ASTWalker walker = LC_GetDefaultWalker(arena, WalkAndCountDeclRefs);
walker.user_data = (void *)map;
walker.visit_notes = true;
LC_WalkAST(&walker, ast);
}
LC_FUNCTION void LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits) {
LC_FUNCTION LC_Decl *LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits) {
LC_Decl *first_removed_decl = NULL;
LC_Decl *last_removed_decl = NULL;
for (LC_ASTRef *it = L->ordered_packages.first; it; it = it->next) {
for (LC_Decl *decl = it->ast->apackage.ext->first_ordered; decl;) {
intptr_t ref_count = (intptr_t)LC_MapGetP(map_of_visits, decl);
@@ -38,9 +34,11 @@ LC_FUNCTION void LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits) {
decl = decl->next;
if (ref_count == 0 && remove->foreign_name != LC_ILit("main")) {
LC_DLLRemove(it->ast->apackage.ext->first_ordered, it->ast->apackage.ext->last_ordered, remove);
LC_DLLAdd(first_removed_decl, last_removed_decl, remove);
}
}
}
return first_removed_decl;
}
LC_FUNCTION void LC_ErrorOnUnreferencedLocalsPass(LC_Map *map_of_visits) {
@@ -64,9 +62,16 @@ LC_FUNCTION void LC_FindUnusedLocalsAndRemoveUnusedGlobalDeclsPass(void) {
if (L->errors) return;
LC_TempArena check = LC_BeginTemp(L->arena);
LC_Map map = LC_CountDeclRefs(check.arena);
LC_AST *package = LC_GetPackageByName(L->first_package);
LC_Map map = {check.arena};
LC_MapReserve(&map, 512);
LC_CountDeclRefs(check.arena, &map, package);
LC_Decl *first_removed_decl = LC_RemoveUnreferencedGlobalDeclsPass(&map);
for (LC_Decl *it = first_removed_decl; it; it = it->next) {
LC_CountDeclRefs(check.arena, &map, it->ast);
}
LC_ErrorOnUnreferencedLocalsPass(&map);
LC_RemoveUnreferencedGlobalDeclsPass(&map);
LC_EndTemp(check);
}

View File

@@ -1001,9 +1001,9 @@ LC_FUNCTION void LC_ResolveProcBodiesPass(void); // The Parse an
LC_FUNCTION void LC_FindUnusedLocalsAndRemoveUnusedGlobalDeclsPass(void); // Extended pass that you can execute once you have resolved all packages
// These three functions are used to implement LC_FindUnusedLocalsAndRemoveUnusedGlobalDeclsPass
LC_FUNCTION LC_Map LC_CountDeclRefs(LC_Arena *arena);
LC_FUNCTION void LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits);
LC_FUNCTION void LC_ErrorOnUnreferencedLocalsPass(LC_Map *map_of_visits);
LC_FUNCTION void LC_CountDeclRefs(LC_Arena *arena, LC_Map *map, LC_AST *ast);
LC_FUNCTION LC_Decl *LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits);
LC_FUNCTION void LC_ErrorOnUnreferencedLocalsPass(LC_Map *map_of_visits);
// Notes
LC_FUNCTION void LC_DeclareNote(LC_Intern intern);

View File

@@ -690,16 +690,15 @@ LC_FUNCTION LC_Operand LC_ResolveExprEx(LC_AST *n) {
} break;
case LC_ASTKind_ExprField: {
bool first_part_executed = false;
bool resolved_import = false;
LC_Operand op = {0};
if (n->efield.left->kind == LC_ASTKind_ExprIdent) {
LC_AST *nf = n->efield.left;
LC_Operand LC_PROP_ERROR(op_name, nf, LC_ResolveName(nf, nf->eident.name));
// LC_Match (Package.) and fold (Package.Other) into just (Other)
if (op_name.decl->kind == LC_DeclKind_Import) {
first_part_executed = true;
resolved_import = true;
nf->eident.resolved_decl = op_name.decl;
nf->type = L->tvoid;
@@ -707,7 +706,7 @@ LC_FUNCTION LC_Operand LC_ResolveExprEx(LC_AST *n) {
}
}
if (!first_part_executed) {
if (!resolved_import) {
LC_ASTKind left_kind = n->efield.left->kind;
LC_PROP_ERROR(op, n, LC_ResolveExpr(n->efield.left));
@@ -717,8 +716,17 @@ LC_FUNCTION LC_Operand LC_ResolveExprEx(LC_AST *n) {
LC_PROP_ERROR(op, n, LC_ResolveNameInScope(n, type->decl));
LC_ASSERT(n, op.decl->kind == LC_DeclKind_Var);
result.flags |= LC_OPF_LValue | LC_OPF_Const;
result.val = op.decl->val;
} else {
result.val = op.decl->val;
// @copy_paste from ExprIdent
if (op.decl->kind == LC_DeclKind_Const) {
result.flags |= LC_OPF_UTConst | LC_OPF_Const;
SetConstVal(n, result.val);
} else {
result.flags |= LC_OPF_LValue | LC_OPF_Const;
}
}
result.val = op.decl->val;
} break;
case LC_ASTKind_ExprCall: {

View File

@@ -118,7 +118,7 @@ MA_API void * MA__PushSizeNonZeroed(MA_Arena *a, size_t size);
MA_API void * MA__PushSize(MA_Arena *arena, size_t size);
MA_API char * MA__PushStringCopy(MA_Arena *arena, char *p, size_t size);
MA_API void * MA__PushCopy(MA_Arena *arena, void *p, size_t size);
MA_API MA_Temp MA_BeginTemp(MA_Arena *arena);
MA_API MA_Temp MA_BeginTemp(MA_Arena *arena);
MA_API void MA_EndTemp(MA_Temp checkpoint);
MA_API void MA_PopToPos(MA_Arena *arena, size_t pos);

View File

@@ -0,0 +1,8 @@
import b "second";
main :: proc(): int {
a: int;
b.cool_variable = &a;
b.other_thing();
return 0;
}

View File

@@ -0,0 +1,7 @@
cool_variable: *int;
other_thing :: proc(): int {
a := 0;
return a;
}

View File

@@ -31,10 +31,10 @@ int main(int argc, char **argv) {
LC_RegisterPackageDir(it->string.str);
}
LC_Intern name = LC_InternStrLen(package.str, (int)package.len);
LC_ASTRefList packages = LC_ParseAndResolve(name);
LC_Intern name = LC_InternStrLen(package.str, (int)package.len);
LC_ParseAndResolve(name);
if (lang->errors) return 1;
LC_String code = LC_GenerateUnityBuild(packages);
LC_String code = LC_GenerateUnityBuild();
(void)code;
}

View File

@@ -31,10 +31,10 @@ int main(int argc, char **argv) {
LC_RegisterPackageDir(it->string.str);
}
LC_Intern name = LC_InternStrLen(package.str, (int)package.len);
LC_ASTRefList packages = LC_ParseAndResolve(name);
LC_Intern name = LC_InternStrLen(package.str, (int)package.len);
LC_ParseAndResolve(name);
if (lang->errors) return 1;
LC_String code = LC_GenerateUnityBuild(packages);
LC_String code = LC_GenerateUnityBuild();
(void)code;
}

View File

@@ -0,0 +1,5 @@
import b "second";
main :: proc(): int {
return b.A;
}

View File

@@ -0,0 +1 @@
A :: 0;

11
tests/defer_todo.txt Normal file
View File

@@ -0,0 +1,11 @@
a: char;
main :: proc(): int {
/*for i := 0; i < 4; i += 1 {
if i == 2 { break; }
string := &a;
defer *string = 1;
}*/
return 0;
}

View File

@@ -0,0 +1,5 @@
import b "second";
main :: proc(): int {
return 0;
}

View File

@@ -0,0 +1,5 @@
other_thing :: proc(): int {
a := 0;
return a;
}

View File

@@ -119,6 +119,7 @@ def parse_decl(decl):
return None
def bindgen_enum(decl):
r = ""
r += decl["name"] + " :: typedef int;\n"
for item in decl["items"]:
r += item["name"]
@@ -209,7 +210,7 @@ def bindgen_func(decl):
if i != len(decl["params"]) - 1 or vargs:
r += ", "
i += 1
if vargs: r += ".."
if vargs: r += "..."
r += ")"
decl_type = decl["type"]
return_type = decl_type[:decl_type.index('(')].strip()

View File

@@ -41,10 +41,10 @@ int main(int argc, char **argv) {
LC_RegisterPackageDir(path_to_package.str);
S8_For(it, dirs) { LC_RegisterPackageDir(it->string.str); }
LC_Intern name = LC_InternStrLen(package.str, (int)package.len);
LC_ASTRefList packages = LC_ParseAndResolve(name);
LC_Intern name = LC_InternStrLen(package.str, (int)package.len);
LC_ParseAndResolve(name);
if (lang->errors) return 1;
S8_String code = LC_GenerateUnityBuild(packages);
S8_String code = LC_GenerateUnityBuild();
OS_WriteFile(S8_Lit("output.c"), code);
}