Compare commits
10 Commits
6ac3f01ebf
...
ced67bbb96
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ced67bbb96 | ||
|
|
827e838550 | ||
|
|
62b15a1077 | ||
|
|
42ec3f7a18 | ||
|
|
ff612d00ef | ||
|
|
f8cf91ed2a | ||
|
|
39cb9cb4b4 | ||
|
|
b08c7c9ce6 | ||
|
|
2ec4a2a28d | ||
|
|
27b197840b |
12
.github/workflows/run_tests.yaml
vendored
12
.github/workflows/run_tests.yaml
vendored
@@ -7,12 +7,6 @@ jobs:
|
|||||||
- run: sudo apt install g++
|
- run: sudo apt install g++
|
||||||
- run: sudo apt install clang
|
- run: sudo apt install clang
|
||||||
- run: g++ -o bld src/build_tool/main.cpp -g -lm && ./bld
|
- 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:
|
run-and-compile-windows:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
@@ -23,3 +17,9 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- run: cl.exe src/build_tool/main.cpp /Fe:bld.exe && bld.exe
|
- 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
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# Compiler front-end in a single-header-file C library
|
# 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!**
|
- **User has full control over compilation!**
|
||||||
- **No dependencies, permissive license, single file that compile both in C and C++!**
|
- **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`.
|
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
|
# 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.
|
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.
|
||||||
|
|||||||
@@ -8,4 +8,4 @@ if not exist build\bld.exe (
|
|||||||
)
|
)
|
||||||
|
|
||||||
rem ubuntu run ./build.sh
|
rem ubuntu run ./build.sh
|
||||||
build\bld.exe --tests text_editor
|
build\bld.exe
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ S8_String RaylibDLL;
|
|||||||
#include "examples/add_dynamic_array_macro/build.cpp"
|
#include "examples/add_dynamic_array_macro/build.cpp"
|
||||||
#include "examples/text_editor/build.cpp"
|
#include "examples/text_editor/build.cpp"
|
||||||
#include "examples/hello_world/build.cpp"
|
#include "examples/hello_world/build.cpp"
|
||||||
#include "examples/sandbox/build.cpp"
|
|
||||||
#include "examples/create_raylib_window/build.cpp"
|
#include "examples/create_raylib_window/build.cpp"
|
||||||
#include "examples/add_instrumentation/build.cpp"
|
#include "examples/add_instrumentation/build.cpp"
|
||||||
#include "examples/use_as_data_format_with_typechecking/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) {
|
int main(int argc, char **argv) {
|
||||||
MA_InitScratch();
|
MA_InitScratch();
|
||||||
|
|
||||||
MA_Scratch scratch;
|
|
||||||
UseColoredIO = OS_EnableTerminalColors();
|
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, &BuildX64Sandbox, "build-x64-sandbox", "build the x64 sandbox program using msvc");
|
||||||
AddBool(&p, &QuickRun, "quick", "build tests using tcc compiler only");
|
AddBool(&p, &QuickRun, "quick", "build tests using tcc compiler only");
|
||||||
AddBool(&p, &BreakpointOnError, "breakpoint", "breakpoint if a compiler error is thrown");
|
AddBool(&p, &BreakpointOnError, "breakpoint", "breakpoint if a compiler error is thrown");
|
||||||
@@ -110,7 +107,7 @@ int main(int argc, char **argv) {
|
|||||||
PushDir("x64_sandbox");
|
PushDir("x64_sandbox");
|
||||||
S8_String cc = "cl";
|
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 += "/MP /Zi -D_CRT_SECURE_NO_WARNINGS";
|
||||||
flags += "/FC /WX /W3 /wd4200 /diagnostics:column /nologo";
|
flags += "/FC /WX /W3 /wd4200 /diagnostics:column /nologo";
|
||||||
flags += "/GF /Gm- /Oi";
|
flags += "/GF /Gm- /Oi";
|
||||||
@@ -166,12 +163,6 @@ int main(int argc, char **argv) {
|
|||||||
else IO_Printf("%-50s - ERROR\n", "hello_world");
|
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")) {
|
if (ShouldRun("create_raylib_window")) {
|
||||||
bool result = create_raylib_window();
|
bool result = create_raylib_window();
|
||||||
if (result) IO_Printf("%-50s - OK\n", "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");
|
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");
|
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");
|
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();
|
S8_List programs = S8_MakeEmptyList();
|
||||||
|
|
||||||
OS_SetWorkingDir("wasm_playground"); // so that RegisterDir("../../pkgs") works
|
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)) {
|
if (S8_EndsWith(it.filename, ".lc", false)) {
|
||||||
RunTestFile({TestKind_File, it.absolute_path, it.filename, "not_needed", true});
|
RunTestFile({TestKind_File, it.absolute_path, it.filename, "not_needed", true});
|
||||||
|
|
||||||
S8_String file = OS_ReadFile(scratch, it.absolute_path);
|
S8_String file = OS_ReadFile(Perm, it.absolute_path);
|
||||||
file = S8_ReplaceAll(scratch, file, S8_Lit("\\"), S8_Lit("\\\\"), true);
|
file = S8_ReplaceAll(Perm, file, S8_Lit("\\"), S8_Lit("\\\\"), true);
|
||||||
S8_AddF(scratch, &programs, "`%.*s`,\n", S8_Expand(file));
|
S8_AddF(Perm, &programs, "`%.*s`,\n", S8_Expand(file));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OS_SetWorkingDir("..");
|
OS_SetWorkingDir("..");
|
||||||
|
|
||||||
S8_String programs_string = S8_Merge(scratch, programs);
|
S8_String programs_string = S8_Merge(Perm, programs);
|
||||||
S8_String new_index = S8_ReplaceAll(scratch, index, "<InsertPrograms>", programs_string, false);
|
S8_String new_index = S8_ReplaceAll(Perm, index, "<InsertPrograms>", programs_string, false);
|
||||||
|
|
||||||
OS_WriteFile("wasm_playground/playground.html", new_index);
|
OS_WriteFile("wasm_playground/playground.html", new_index);
|
||||||
OS_CopyFile("../src/wasm_playground/run_server.bat", "wasm_playground/run_server.bat", true);
|
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");
|
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")) {
|
if (ShouldRun("compilation")) {
|
||||||
//
|
//
|
||||||
// Test if things compile in C and C++ mode on all available compilers
|
// Test if things compile in C and C++ mode on all available compilers
|
||||||
//
|
//
|
||||||
S8_String working_dir = PushDir("targets");
|
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.c");
|
||||||
files.add("../../../tests/compilation/test_compile_packed_cpp.c");
|
files.add("../../../tests/compilation/test_compile_packed_cpp.c");
|
||||||
@@ -249,12 +241,12 @@ int main(int argc, char **argv) {
|
|||||||
if (UseCL) {
|
if (UseCL) {
|
||||||
S8_String cc = "cl";
|
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 += "/Zi -D_CRT_SECURE_NO_WARNINGS";
|
||||||
flags += "/FC /WX /W3 /wd4200 /diagnostics:column /nologo";
|
flags += "/FC /WX /W3 /wd4200 /diagnostics:column /nologo";
|
||||||
flags += Fmt("/Fe:%.*s /Fd:%.*s.pdb", S8_Expand(exe), S8_Expand(name_no_ext));
|
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";
|
link += "/link /incremental:no";
|
||||||
|
|
||||||
S8_String dir = Fmt("%.*s_cl_debug_" OS_NAME, S8_Expand(name_no_ext));
|
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) {
|
if (UseClang) {
|
||||||
S8_String cc = "clang";
|
S8_String cc = "clang";
|
||||||
|
|
||||||
Array<S8_String> flags = {MA_GetAllocator(scratch)};
|
Array<S8_String> flags = {MA_GetAllocator(Perm)};
|
||||||
flags += "-g -Wno-write-strings";
|
flags += "-g -Wno-write-strings";
|
||||||
flags += "-fdiagnostics-absolute-paths";
|
flags += "-fdiagnostics-absolute-paths";
|
||||||
flags += "-fsanitize=address";
|
flags += "-fsanitize=address";
|
||||||
@@ -281,7 +273,7 @@ int main(int argc, char **argv) {
|
|||||||
if (UseGCC) {
|
if (UseGCC) {
|
||||||
S8_String cc = "gcc";
|
S8_String cc = "gcc";
|
||||||
|
|
||||||
Array<S8_String> flags = {MA_GetAllocator(scratch)};
|
Array<S8_String> flags = {MA_GetAllocator(Perm)};
|
||||||
flags += "-g -Wno-write-strings";
|
flags += "-g -Wno-write-strings";
|
||||||
flags += "-fsanitize=address";
|
flags += "-fsanitize=address";
|
||||||
if (is_cpp) flags += "-std=c++11";
|
if (is_cpp) flags += "-std=c++11";
|
||||||
|
|||||||
@@ -37,12 +37,12 @@ bool add_instrumentation() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LC_String code = LC_GenerateUnityBuild();
|
LC_String code = LC_GenerateUnityBuild();
|
||||||
LC_LangEnd(lang);
|
|
||||||
|
|
||||||
S8_String path = "examples/add_instrumentation/add_instrumentation.c";
|
S8_String path = "examples/add_instrumentation/add_instrumentation.c";
|
||||||
OS_MakeDir("examples");
|
OS_MakeDir("examples");
|
||||||
OS_MakeDir("examples/add_instrumentation");
|
OS_MakeDir("examples/add_instrumentation");
|
||||||
OS_WriteFile(path, code);
|
OS_WriteFile(path, code);
|
||||||
|
LC_LangEnd(lang);
|
||||||
if (!UseCL) return true;
|
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));
|
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));
|
||||||
|
|||||||
@@ -34,10 +34,9 @@ bool add_source_location_macro() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LC_String code = LC_GenerateUnityBuild();
|
LC_String code = LC_GenerateUnityBuild();
|
||||||
LC_LangEnd(lang);
|
|
||||||
|
|
||||||
OS_MakeDir("examples/add_source_location_macro");
|
OS_MakeDir("examples/add_source_location_macro");
|
||||||
OS_WriteFile("examples/add_source_location_macro/add_source_location_macro.c", code);
|
OS_WriteFile("examples/add_source_location_macro/add_source_location_macro.c", code);
|
||||||
|
LC_LangEnd(lang);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -16,10 +16,10 @@ bool hello_world() {
|
|||||||
OS_MakeDir("examples/hello_world");
|
OS_MakeDir("examples/hello_world");
|
||||||
LC_ParseAndResolve(name);
|
LC_ParseAndResolve(name);
|
||||||
LC_String code = LC_GenerateUnityBuild();
|
LC_String code = LC_GenerateUnityBuild();
|
||||||
LC_LangEnd(lang);
|
|
||||||
|
|
||||||
S8_String path = "examples/hello_world/hello_world.c";
|
S8_String path = "examples/hello_world/hello_world.c";
|
||||||
OS_WriteFile(path, code);
|
OS_WriteFile(path, code);
|
||||||
|
LC_LangEnd(lang);
|
||||||
if (UseCL) {
|
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));
|
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;
|
if (Run(cmd) != 0) return false;
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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 *)⁢
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -6,9 +6,9 @@ bool text_editor() {
|
|||||||
defer { LC_LangEnd(lang); };
|
defer { LC_LangEnd(lang); };
|
||||||
|
|
||||||
LC_RegisterPackageDir("../pkgs");
|
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);
|
LC_ParseAndResolve(name);
|
||||||
if (L->errors) return false;
|
if (L->errors) return false;
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ bool text_editor() {
|
|||||||
OS_WriteFile(path, code);
|
OS_WriteFile(path, code);
|
||||||
|
|
||||||
if (!UseCL) return true;
|
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);
|
int errcode = Run(cmd);
|
||||||
if (errcode != 0) return false;
|
if (errcode != 0) return false;
|
||||||
|
|
||||||
|
|||||||
43
examples/text_editor/core/basic.lc
Normal file
43
examples/text_editor/core/basic.lc
Normal 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);
|
||||||
|
}
|
||||||
394
examples/text_editor/core/core.lc
Normal file
394
examples/text_editor/core/core.lc
Normal 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
|
||||||
@@ -3,22 +3,6 @@ Rect2P :: struct {
|
|||||||
max: Vector2;
|
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 {
|
GetRectSize :: proc(rect: Rect2P): Vector2 {
|
||||||
result: Vector2 = {rect.max.x - rect.min.x, rect.max.y - rect.min.y};
|
result: Vector2 = {rect.max.x - rect.min.x, rect.max.y - rect.min.y};
|
||||||
return result;
|
return result;
|
||||||
@@ -36,7 +20,7 @@ GetRectX :: proc(rect: Rect2P): f32 {
|
|||||||
|
|
||||||
CutLeft :: proc(r: *Rect2P, value: f32): Rect2P {
|
CutLeft :: proc(r: *Rect2P, value: f32): Rect2P {
|
||||||
minx := r.min.x;
|
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{
|
return :Rect2P{
|
||||||
{ minx, r.min.y},
|
{ minx, r.min.y},
|
||||||
{r.min.x, r.max.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 {
|
CutRight :: proc(r: *Rect2P, value: f32): Rect2P {
|
||||||
maxx := r.max.x;
|
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{
|
return :Rect2P{
|
||||||
{r.max.x, r.min.y},
|
{r.max.x, r.min.y},
|
||||||
{ maxx, r.max.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
|
CutBottom :: proc(r: *Rect2P, value: f32): Rect2P { // Y is down
|
||||||
maxy := r.max.y;
|
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{
|
return :Rect2P{
|
||||||
{r.min.x, r.max.y},
|
{r.min.x, r.max.y},
|
||||||
{r.max.x, maxy},
|
{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
|
CutTop :: proc(r: *Rect2P, value: f32): Rect2P { // Y is down
|
||||||
miny := r.min.y;
|
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{
|
return :Rect2P{
|
||||||
{r.min.x, miny},
|
{r.min.x, miny},
|
||||||
{r.max.x, r.min.y},
|
{r.max.x, r.min.y},
|
||||||
113
examples/text_editor/entry_point/entry_point.lc
Normal file
113
examples/text_editor/entry_point/entry_point.lc
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
3
examples/text_editor/entry_point/prototype.lc
Normal file
3
examples/text_editor/entry_point/prototype.lc
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
UpdatePrototype :: proc(rect: Rect2P, font: Font, font_size: float, font_spacing: float) {
|
||||||
|
}
|
||||||
|
|
||||||
@@ -27,25 +27,6 @@ GetRangeSize :: proc(range: Range): int {
|
|||||||
return result;
|
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 {
|
AdjustUTF8PosUnsafe :: proc(buffer: *Buffer, pos: int, direction: int = 1): int {
|
||||||
for pos >= 0 && pos < buffer.len && IsUTF8ContinuationByte(buffer.data[pos]) {
|
for pos >= 0 && pos < buffer.len && IsUTF8ContinuationByte(buffer.data[pos]) {
|
||||||
pos += direction;
|
pos += direction;
|
||||||
@@ -53,10 +34,25 @@ AdjustUTF8PosUnsafe :: proc(buffer: *Buffer, pos: int, direction: int = 1): int
|
|||||||
return pos;
|
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 {
|
AdjustUTF8Pos :: proc(buffer: *Buffer, pos: int, direction: int = 1): int {
|
||||||
assert(direction == 1 || direction == -1);
|
assert(direction == 1 || direction == -1);
|
||||||
pos = AdjustUTF8PosUnsafe(buffer, pos, direction);
|
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]));
|
if (buffer.data) assert(!IsUTF8ContinuationByte(buffer.data[pos]));
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
@@ -150,8 +146,7 @@ GetStringFromBuffer :: proc(buffer: *Buffer, range: Range): String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AddText :: proc(buffer: *Buffer, text: String) {
|
AddText :: proc(buffer: *Buffer, text: String) {
|
||||||
end_of_buffer: Range = {buffer.len - 1, buffer.len - 1};
|
ReplaceText(buffer, GetBufferEndRange(buffer), text);
|
||||||
ReplaceText(buffer, end_of_buffer, text);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FindLineOfPos :: proc(buffer: *Buffer, pos: int): LineInfo {
|
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_whitespace := standing_on_whitespace == false;
|
||||||
seek_word := standing_on_whitespace;
|
seek_word := standing_on_whitespace;
|
||||||
|
|
||||||
end := buffer.len - 1;
|
end := GetBufferEnd(buffer);
|
||||||
if (direction == GO_BACKWARD) end = 0;
|
if (direction == GO_BACKWARD) end = 0;
|
||||||
|
|
||||||
result := end;
|
result := end;
|
||||||
@@ -1,14 +1,45 @@
|
|||||||
/*
|
|
||||||
- Ctrl+C
|
|
||||||
- Ctrl+V
|
|
||||||
- Ctrl+X
|
|
||||||
- Windows
|
|
||||||
- Multiple buffers at the same time
|
|
||||||
*/
|
|
||||||
import "raylib";
|
|
||||||
import "std_types";
|
import "std_types";
|
||||||
|
import "raylib";
|
||||||
import "libc";
|
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 {
|
Selection :: struct {
|
||||||
a: int;
|
a: int;
|
||||||
b: int;
|
b: int;
|
||||||
@@ -19,19 +50,6 @@ GetRange :: proc(s: Selection): Range {
|
|||||||
return result;
|
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) {
|
AddWindow :: proc(window: Window) {
|
||||||
if (WindowStackCount + 1 >= 8) return;
|
if (WindowStackCount + 1 >= 8) return;
|
||||||
|
|
||||||
@@ -45,6 +63,7 @@ ComputeWindowRects :: proc(screen_rect: Rect2P) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
UpdateAndDrawWindows :: proc(font: Font, font_size: float) {
|
UpdateAndDrawWindows :: proc(font: Font, font_size: float) {
|
||||||
|
SetMouseCursor(MOUSE_CURSOR_DEFAULT);
|
||||||
for i := 0; i < WindowStackCount; i += 1 {
|
for i := 0; i < WindowStackCount; i += 1 {
|
||||||
window: *Window = &WindowStack[i];
|
window: *Window = &WindowStack[i];
|
||||||
UpdateAndDrawWindow(window, font, font_size);
|
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) {
|
UpdateAndDrawWindow :: proc(w: *Window, font: Font, font_size: float) {
|
||||||
initial_cursor: Selection = w.cursor;
|
initial_cursor: Selection = w.cursor;
|
||||||
text_window_rect := w.rect;
|
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);
|
buffer_end_wpos := CalculateWorldPosUnscrolled(buffer_end_vpos);
|
||||||
|
|
||||||
if CheckCollisionPointRec(GetMousePosition(), Rect2PToRectangle(w.rect)) {
|
if CheckCollisionPointRec(GetMousePosition(), Rect2PToRectangle(w.rect)) {
|
||||||
@@ -68,7 +89,6 @@ UpdateAndDrawWindow :: proc(w: *Window, font: Font, font_size: float) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if w == FocusedWindow {
|
if w == FocusedWindow {
|
||||||
if IsKeyPressed(KEY_LEFT) || IsKeyPressedRepeat(KEY_LEFT) {
|
if IsKeyPressed(KEY_LEFT) || IsKeyPressedRepeat(KEY_LEFT) {
|
||||||
if IsKeyDown(KEY_LEFT_SHIFT) {
|
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) {
|
if IsKeyPressed(KEY_PAGE_DOWN) || IsKeyPressedRepeat(KEY_PAGE_DOWN) {
|
||||||
vpos := CalculateVisualPos(w.buffer, w.cursor.b);
|
vpos := CalculateVisualPos(w.buffer, w.cursor.b);
|
||||||
move_by := :int(roundf(GetRectY(text_window_rect) / Monosize.y));
|
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(w.rect)) {
|
||||||
if CheckCollisionPointRec(mouse_p, Rect2PToRectangle(text_window_rect)) && !w.mouse_scrolling {
|
if CheckCollisionPointRec(mouse_p, Rect2PToRectangle(text_window_rect)) && !w.mouse_scrolling {
|
||||||
if IsMouseButtonPressed(MOUSE_BUTTON_LEFT) {
|
if IsMouseButtonPressed(MOUSE_BUTTON_LEFT) {
|
||||||
|
w.mouse_selecting = true;
|
||||||
p := Vector2Add(mouse_p, w.scroll);
|
p := Vector2Add(mouse_p, w.scroll);
|
||||||
p = Vector2Subtract(p, text_window_rect.min);
|
p = Vector2Subtract(p, text_window_rect.min);
|
||||||
p = Vector2Divide(p, Monosize);
|
p = Vector2Divide(p, Monosize);
|
||||||
@@ -311,26 +338,30 @@ UpdateAndDrawWindow :: proc(w: *Window, font: Font, font_size: float) {
|
|||||||
y := :int(floorf(p.y));
|
y := :int(floorf(p.y));
|
||||||
w.cursor.a = CalculatePosFromVisualPos(w.buffer, {x, y});
|
w.cursor.a = CalculatePosFromVisualPos(w.buffer, {x, y});
|
||||||
w.cursor.b = w.cursor.a;
|
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);
|
SetMouseCursor(MOUSE_CURSOR_IBEAM);
|
||||||
} else {
|
} else {
|
||||||
SetMouseCursor(MOUSE_CURSOR_DEFAULT);
|
SetMouseCursor(MOUSE_CURSOR_DEFAULT);
|
||||||
|
|
||||||
if IsMouseButtonPressed(MOUSE_BUTTON_LEFT) {
|
if IsMouseButtonPressed(MOUSE_BUTTON_LEFT) {
|
||||||
w.mouse_scrolling = true;
|
w.mouse_scrolling = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.mouse_scrolling {
|
if w.mouse_selecting && IsMouseButtonDown(MOUSE_BUTTON_LEFT) {
|
||||||
mouse_scroll_marker_normalized := (mouse_p.y - w.rect.min.y) / GetRectY(bar);
|
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;
|
w.scroll.y = mouse_scroll_marker_normalized * buffer_end_wpos.y;
|
||||||
|
|
||||||
if IsMouseButtonReleased(MOUSE_BUTTON_LEFT) w.mouse_scrolling = false;
|
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);
|
miny = ClampInt(miny, 0, w.buffer.lines.len - 1);
|
||||||
maxy = ClampInt(maxy, 0, w.buffer.lines.len - 1);
|
maxy = ClampInt(maxy, 0, w.buffer.lines.len - 1);
|
||||||
for y := miny; y <= maxy; y += 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);
|
defer free(string.str);
|
||||||
|
|
||||||
pos := CalculateWorldPos(w.scroll, {0, y});
|
pos := CalculateWorldPos(w.scroll, {0, y});
|
||||||
pos_adjusted_by_buffer := Vector2Add(pos, text_window_rect.min);
|
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);
|
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);
|
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);
|
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;
|
pos.x += 1;
|
||||||
if iter.item == '\n' {
|
if iter.item == '\n' {
|
||||||
@@ -418,55 +455,18 @@ UpdateAndDrawWindow :: proc(w: *Window, font: Font, font_size: float) {
|
|||||||
|
|
||||||
|
|
||||||
// Draw bar
|
// Draw bar
|
||||||
{
|
if IsFlagSet(w.flags, WindowFlags_DrawScrollbar) {
|
||||||
DrawRect(bar, LIGHTGRAY);
|
DrawRect(bar_rect, LIGHTGRAY);
|
||||||
|
DrawRect(horizontal_bar_rect, LIGHTGRAY);
|
||||||
|
|
||||||
scroll_start_normalized := :f32(w.scroll.y) / :f32(buffer_end_wpos.y);
|
scroll_start_normalized := :f32(w.scroll.y) / :f32(buffer_end_wpos.y);
|
||||||
scroll_start := scroll_start_normalized * GetRectSize(bar).y;
|
scroll_start := scroll_start_normalized * GetRectSize(bar_rect).y;
|
||||||
CutTop(&bar, scroll_start);
|
CutTop(&bar_rect, scroll_start);
|
||||||
marker := CutTop(&bar, 20);
|
marker := CutTop(&bar_rect, 20);
|
||||||
DrawRect(marker, GRAY);
|
DrawRect(marker, GRAY);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
InvalidCodepath :: proc() {
|
if w != FocusedWindow {
|
||||||
assert(:*char("invalid codepath") == :*char(""));
|
DrawRect(w.rect, {0,0,0,20});
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
CloseWindow();
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
@@ -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
|
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
|
// These three functions are used to implement LC_FindUnusedLocalsAndRemoveUnusedGlobalDeclsPass
|
||||||
LC_FUNCTION LC_Map LC_CountDeclRefs(LC_Arena *arena);
|
LC_FUNCTION void LC_CountDeclRefs(LC_Arena *arena, LC_Map *map, LC_AST *ast);
|
||||||
LC_FUNCTION void LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits);
|
LC_FUNCTION LC_Decl *LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits);
|
||||||
LC_FUNCTION void LC_ErrorOnUnreferencedLocalsPass(LC_Map *map_of_visits);
|
LC_FUNCTION void LC_ErrorOnUnreferencedLocalsPass(LC_Map *map_of_visits);
|
||||||
|
|
||||||
// Notes
|
// Notes
|
||||||
LC_FUNCTION void LC_DeclareNote(LC_Intern intern);
|
LC_FUNCTION void LC_DeclareNote(LC_Intern intern);
|
||||||
@@ -6855,16 +6855,15 @@ LC_FUNCTION LC_Operand LC_ResolveExprEx(LC_AST *n) {
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case LC_ASTKind_ExprField: {
|
case LC_ASTKind_ExprField: {
|
||||||
bool first_part_executed = false;
|
bool resolved_import = false;
|
||||||
|
|
||||||
LC_Operand op = {0};
|
LC_Operand op = {0};
|
||||||
if (n->efield.left->kind == LC_ASTKind_ExprIdent) {
|
if (n->efield.left->kind == LC_ASTKind_ExprIdent) {
|
||||||
LC_AST *nf = n->efield.left;
|
LC_AST *nf = n->efield.left;
|
||||||
LC_Operand LC_PROP_ERROR(op_name, nf, LC_ResolveName(nf, nf->eident.name));
|
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) {
|
if (op_name.decl->kind == LC_DeclKind_Import) {
|
||||||
first_part_executed = true;
|
resolved_import = true;
|
||||||
nf->eident.resolved_decl = op_name.decl;
|
nf->eident.resolved_decl = op_name.decl;
|
||||||
nf->type = L->tvoid;
|
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_ASTKind left_kind = n->efield.left->kind;
|
||||||
LC_PROP_ERROR(op, n, LC_ResolveExpr(n->efield.left));
|
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_PROP_ERROR(op, n, LC_ResolveNameInScope(n, type->decl));
|
||||||
LC_ASSERT(n, op.decl->kind == LC_DeclKind_Var);
|
LC_ASSERT(n, op.decl->kind == LC_DeclKind_Var);
|
||||||
result.flags |= LC_OPF_LValue | LC_OPF_Const;
|
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;
|
} break;
|
||||||
|
|
||||||
case LC_ASTKind_ExprCall: {
|
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_FUNCTION void LC_CountDeclRefs(LC_Arena *arena, LC_Map *map, LC_AST *ast) {
|
||||||
LC_Map map = {arena};
|
LC_ASTWalker walker = LC_GetDefaultWalker(arena, WalkAndCountDeclRefs);
|
||||||
LC_MapReserve(&map, 512);
|
walker.user_data = (void *)map;
|
||||||
|
walker.visit_notes = true;
|
||||||
LC_AST *package = LC_GetPackageByName(L->first_package);
|
LC_WalkAST(&walker, ast);
|
||||||
LC_ASTWalker walker = LC_GetDefaultWalker(arena, WalkAndCountDeclRefs);
|
|
||||||
walker.user_data = (void *)↦
|
|
||||||
walker.visit_notes = true;
|
|
||||||
LC_WalkAST(&walker, package);
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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_ASTRef *it = L->ordered_packages.first; it; it = it->next) {
|
||||||
for (LC_Decl *decl = it->ast->apackage.ext->first_ordered; decl;) {
|
for (LC_Decl *decl = it->ast->apackage.ext->first_ordered; decl;) {
|
||||||
intptr_t ref_count = (intptr_t)LC_MapGetP(map_of_visits, 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;
|
decl = decl->next;
|
||||||
if (ref_count == 0 && remove->foreign_name != LC_ILit("main")) {
|
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_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) {
|
LC_FUNCTION void LC_ErrorOnUnreferencedLocalsPass(LC_Map *map_of_visits) {
|
||||||
@@ -9939,9 +9945,16 @@ LC_FUNCTION void LC_FindUnusedLocalsAndRemoveUnusedGlobalDeclsPass(void) {
|
|||||||
if (L->errors) return;
|
if (L->errors) return;
|
||||||
LC_TempArena check = LC_BeginTemp(L->arena);
|
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_ErrorOnUnreferencedLocalsPass(&map);
|
||||||
LC_RemoveUnreferencedGlobalDeclsPass(&map);
|
|
||||||
|
|
||||||
LC_EndTemp(check);
|
LC_EndTemp(check);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,20 +16,16 @@ LC_FUNCTION void WalkAndCountDeclRefs(LC_ASTWalker *ctx, LC_AST *n) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LC_FUNCTION LC_Map LC_CountDeclRefs(LC_Arena *arena) {
|
LC_FUNCTION void LC_CountDeclRefs(LC_Arena *arena, LC_Map *map, LC_AST *ast) {
|
||||||
LC_Map map = {arena};
|
LC_ASTWalker walker = LC_GetDefaultWalker(arena, WalkAndCountDeclRefs);
|
||||||
LC_MapReserve(&map, 512);
|
walker.user_data = (void *)map;
|
||||||
|
walker.visit_notes = true;
|
||||||
LC_AST *package = LC_GetPackageByName(L->first_package);
|
LC_WalkAST(&walker, ast);
|
||||||
LC_ASTWalker walker = LC_GetDefaultWalker(arena, WalkAndCountDeclRefs);
|
|
||||||
walker.user_data = (void *)↦
|
|
||||||
walker.visit_notes = true;
|
|
||||||
LC_WalkAST(&walker, package);
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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_ASTRef *it = L->ordered_packages.first; it; it = it->next) {
|
||||||
for (LC_Decl *decl = it->ast->apackage.ext->first_ordered; decl;) {
|
for (LC_Decl *decl = it->ast->apackage.ext->first_ordered; decl;) {
|
||||||
intptr_t ref_count = (intptr_t)LC_MapGetP(map_of_visits, 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;
|
decl = decl->next;
|
||||||
if (ref_count == 0 && remove->foreign_name != LC_ILit("main")) {
|
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_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) {
|
LC_FUNCTION void LC_ErrorOnUnreferencedLocalsPass(LC_Map *map_of_visits) {
|
||||||
@@ -64,9 +62,16 @@ LC_FUNCTION void LC_FindUnusedLocalsAndRemoveUnusedGlobalDeclsPass(void) {
|
|||||||
if (L->errors) return;
|
if (L->errors) return;
|
||||||
LC_TempArena check = LC_BeginTemp(L->arena);
|
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_ErrorOnUnreferencedLocalsPass(&map);
|
||||||
LC_RemoveUnreferencedGlobalDeclsPass(&map);
|
|
||||||
|
|
||||||
LC_EndTemp(check);
|
LC_EndTemp(check);
|
||||||
}
|
}
|
||||||
@@ -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
|
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
|
// These three functions are used to implement LC_FindUnusedLocalsAndRemoveUnusedGlobalDeclsPass
|
||||||
LC_FUNCTION LC_Map LC_CountDeclRefs(LC_Arena *arena);
|
LC_FUNCTION void LC_CountDeclRefs(LC_Arena *arena, LC_Map *map, LC_AST *ast);
|
||||||
LC_FUNCTION void LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits);
|
LC_FUNCTION LC_Decl *LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits);
|
||||||
LC_FUNCTION void LC_ErrorOnUnreferencedLocalsPass(LC_Map *map_of_visits);
|
LC_FUNCTION void LC_ErrorOnUnreferencedLocalsPass(LC_Map *map_of_visits);
|
||||||
|
|
||||||
// Notes
|
// Notes
|
||||||
LC_FUNCTION void LC_DeclareNote(LC_Intern intern);
|
LC_FUNCTION void LC_DeclareNote(LC_Intern intern);
|
||||||
|
|||||||
@@ -690,16 +690,15 @@ LC_FUNCTION LC_Operand LC_ResolveExprEx(LC_AST *n) {
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case LC_ASTKind_ExprField: {
|
case LC_ASTKind_ExprField: {
|
||||||
bool first_part_executed = false;
|
bool resolved_import = false;
|
||||||
|
|
||||||
LC_Operand op = {0};
|
LC_Operand op = {0};
|
||||||
if (n->efield.left->kind == LC_ASTKind_ExprIdent) {
|
if (n->efield.left->kind == LC_ASTKind_ExprIdent) {
|
||||||
LC_AST *nf = n->efield.left;
|
LC_AST *nf = n->efield.left;
|
||||||
LC_Operand LC_PROP_ERROR(op_name, nf, LC_ResolveName(nf, nf->eident.name));
|
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) {
|
if (op_name.decl->kind == LC_DeclKind_Import) {
|
||||||
first_part_executed = true;
|
resolved_import = true;
|
||||||
nf->eident.resolved_decl = op_name.decl;
|
nf->eident.resolved_decl = op_name.decl;
|
||||||
nf->type = L->tvoid;
|
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_ASTKind left_kind = n->efield.left->kind;
|
||||||
LC_PROP_ERROR(op, n, LC_ResolveExpr(n->efield.left));
|
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_PROP_ERROR(op, n, LC_ResolveNameInScope(n, type->decl));
|
||||||
LC_ASSERT(n, op.decl->kind == LC_DeclKind_Var);
|
LC_ASSERT(n, op.decl->kind == LC_DeclKind_Var);
|
||||||
result.flags |= LC_OPF_LValue | LC_OPF_Const;
|
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;
|
} break;
|
||||||
|
|
||||||
case LC_ASTKind_ExprCall: {
|
case LC_ASTKind_ExprCall: {
|
||||||
|
|||||||
@@ -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 void * MA__PushSize(MA_Arena *arena, size_t size);
|
||||||
MA_API char * MA__PushStringCopy(MA_Arena *arena, char *p, 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 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_EndTemp(MA_Temp checkpoint);
|
||||||
|
|
||||||
MA_API void MA_PopToPos(MA_Arena *arena, size_t pos);
|
MA_API void MA_PopToPos(MA_Arena *arena, size_t pos);
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import b "second";
|
||||||
|
|
||||||
|
main :: proc(): int {
|
||||||
|
a: int;
|
||||||
|
b.cool_variable = &a;
|
||||||
|
b.other_thing();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
7
tests/accessing_variable_across_modules/second/second.lc
Normal file
7
tests/accessing_variable_across_modules/second/second.lc
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
cool_variable: *int;
|
||||||
|
|
||||||
|
other_thing :: proc(): int {
|
||||||
|
a := 0;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
@@ -31,10 +31,10 @@ int main(int argc, char **argv) {
|
|||||||
LC_RegisterPackageDir(it->string.str);
|
LC_RegisterPackageDir(it->string.str);
|
||||||
}
|
}
|
||||||
|
|
||||||
LC_Intern name = LC_InternStrLen(package.str, (int)package.len);
|
LC_Intern name = LC_InternStrLen(package.str, (int)package.len);
|
||||||
LC_ASTRefList packages = LC_ParseAndResolve(name);
|
LC_ParseAndResolve(name);
|
||||||
if (lang->errors) return 1;
|
if (lang->errors) return 1;
|
||||||
|
|
||||||
LC_String code = LC_GenerateUnityBuild(packages);
|
LC_String code = LC_GenerateUnityBuild();
|
||||||
(void)code;
|
(void)code;
|
||||||
}
|
}
|
||||||
@@ -31,10 +31,10 @@ int main(int argc, char **argv) {
|
|||||||
LC_RegisterPackageDir(it->string.str);
|
LC_RegisterPackageDir(it->string.str);
|
||||||
}
|
}
|
||||||
|
|
||||||
LC_Intern name = LC_InternStrLen(package.str, (int)package.len);
|
LC_Intern name = LC_InternStrLen(package.str, (int)package.len);
|
||||||
LC_ASTRefList packages = LC_ParseAndResolve(name);
|
LC_ParseAndResolve(name);
|
||||||
if (lang->errors) return 1;
|
if (lang->errors) return 1;
|
||||||
|
|
||||||
LC_String code = LC_GenerateUnityBuild(packages);
|
LC_String code = LC_GenerateUnityBuild();
|
||||||
(void)code;
|
(void)code;
|
||||||
}
|
}
|
||||||
5
tests/const_not_folding/main/test_unused.lc
Normal file
5
tests/const_not_folding/main/test_unused.lc
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import b "second";
|
||||||
|
|
||||||
|
main :: proc(): int {
|
||||||
|
return b.A;
|
||||||
|
}
|
||||||
1
tests/const_not_folding/second/second.lc
Normal file
1
tests/const_not_folding/second/second.lc
Normal file
@@ -0,0 +1 @@
|
|||||||
|
A :: 0;
|
||||||
11
tests/defer_todo.txt
Normal file
11
tests/defer_todo.txt
Normal 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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import b "second";
|
||||||
|
|
||||||
|
main :: proc(): int {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
other_thing :: proc(): int {
|
||||||
|
a := 0;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
@@ -119,6 +119,7 @@ def parse_decl(decl):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def bindgen_enum(decl):
|
def bindgen_enum(decl):
|
||||||
|
r = ""
|
||||||
r += decl["name"] + " :: typedef int;\n"
|
r += decl["name"] + " :: typedef int;\n"
|
||||||
for item in decl["items"]:
|
for item in decl["items"]:
|
||||||
r += item["name"]
|
r += item["name"]
|
||||||
@@ -209,7 +210,7 @@ def bindgen_func(decl):
|
|||||||
if i != len(decl["params"]) - 1 or vargs:
|
if i != len(decl["params"]) - 1 or vargs:
|
||||||
r += ", "
|
r += ", "
|
||||||
i += 1
|
i += 1
|
||||||
if vargs: r += ".."
|
if vargs: r += "..."
|
||||||
r += ")"
|
r += ")"
|
||||||
decl_type = decl["type"]
|
decl_type = decl["type"]
|
||||||
return_type = decl_type[:decl_type.index('(')].strip()
|
return_type = decl_type[:decl_type.index('(')].strip()
|
||||||
|
|||||||
@@ -41,10 +41,10 @@ int main(int argc, char **argv) {
|
|||||||
LC_RegisterPackageDir(path_to_package.str);
|
LC_RegisterPackageDir(path_to_package.str);
|
||||||
S8_For(it, dirs) { LC_RegisterPackageDir(it->string.str); }
|
S8_For(it, dirs) { LC_RegisterPackageDir(it->string.str); }
|
||||||
|
|
||||||
LC_Intern name = LC_InternStrLen(package.str, (int)package.len);
|
LC_Intern name = LC_InternStrLen(package.str, (int)package.len);
|
||||||
LC_ASTRefList packages = LC_ParseAndResolve(name);
|
LC_ParseAndResolve(name);
|
||||||
if (lang->errors) return 1;
|
if (lang->errors) return 1;
|
||||||
|
|
||||||
S8_String code = LC_GenerateUnityBuild(packages);
|
S8_String code = LC_GenerateUnityBuild();
|
||||||
OS_WriteFile(S8_Lit("output.c"), code);
|
OS_WriteFile(S8_Lit("output.c"), code);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user