Compare commits
10 Commits
6ac3f01ebf
...
ced67bbb96
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ced67bbb96 | ||
|
|
827e838550 | ||
|
|
62b15a1077 | ||
|
|
42ec3f7a18 | ||
|
|
ff612d00ef | ||
|
|
f8cf91ed2a | ||
|
|
39cb9cb4b4 | ||
|
|
b08c7c9ce6 | ||
|
|
2ec4a2a28d | ||
|
|
27b197840b |
14
.github/workflows/run_tests.yaml
vendored
14
.github/workflows/run_tests.yaml
vendored
@@ -7,12 +7,6 @@ jobs:
|
||||
- run: sudo apt install g++
|
||||
- run: sudo apt install clang
|
||||
- run: g++ -o bld src/build_tool/main.cpp -g -lm && ./bld
|
||||
run-and-compile-mac:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: brew install llvm
|
||||
- run: clang++ src/build_tool/main.cpp -std=c++11 -o bld && ./bld
|
||||
run-and-compile-windows:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
@@ -22,4 +16,10 @@ jobs:
|
||||
arch: x64
|
||||
- uses: actions/checkout@v4
|
||||
- run: cl.exe src/build_tool/main.cpp /Fe:bld.exe && bld.exe
|
||||
shell: cmd
|
||||
shell: cmd
|
||||
# run-and-compile-mac:
|
||||
# runs-on: macos-latest
|
||||
# steps:
|
||||
# - uses: actions/checkout@v4
|
||||
# - run: brew install llvm
|
||||
# - run: clang++ src/build_tool/main.cpp -std=c++11 -o bld && ./bld --threads 1
|
||||
@@ -1,6 +1,6 @@
|
||||
# Compiler front-end in a single-header-file C library
|
||||
|
||||
I have no illusions here, this is not the next big language. What I propose is very simple - a return to C. Not to the language as it was, but a return to the ideal of 'C'. A return to something in it - that is more then it. A small language supplemented with modern ideas - distributed as a dependency free, easy to use single-header-file library.
|
||||
.. for a very simple statically typed language. I mostly designed it for personal use, it's small but complete - you can actually program in it and so on. It compiles to C with all the debug info so debuggers work. Currently I find that it's pretty good for metaprogramming and code generation, particularly when you have a workflow "metaprogram -> program". The library provides functions for traversing, printing the AST and other niceties:
|
||||
|
||||
- **User has full control over compilation!**
|
||||
- **No dependencies, permissive license, single file that compile both in C and C++!**
|
||||
@@ -81,12 +81,6 @@ clang++ src/build_tool/main.cpp -o bld.exe
|
||||
|
||||
You only need to compile the build tool once. Afterwards just call `./bld.exe`. There are multiple testing options so checkout: `./bld.exe --help`.
|
||||
|
||||
## Further plans
|
||||
|
||||
- **My priority is to improve the C user API, harden the compiler, accommodate things that I didn't foresee and stuff like that.**
|
||||
- I want to implement a bytecode backend (in the future) so that the language can be used like Lua.
|
||||
- New features are of second priority unless they important. I'm considering the addition of overloaded procedures because it would greatly aid in writing macros.
|
||||
|
||||
# Language overview
|
||||
|
||||
The language is strictly procedural, I have taken most of the inspiration from C, Golang, Ion, Jai and Odin. There are no classes, methods etc. only procedures and data types.
|
||||
|
||||
@@ -8,4 +8,4 @@ if not exist build\bld.exe (
|
||||
)
|
||||
|
||||
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/text_editor/build.cpp"
|
||||
#include "examples/hello_world/build.cpp"
|
||||
#include "examples/sandbox/build.cpp"
|
||||
#include "examples/create_raylib_window/build.cpp"
|
||||
#include "examples/add_instrumentation/build.cpp"
|
||||
#include "examples/use_as_data_format_with_typechecking/build.cpp"
|
||||
@@ -53,12 +52,10 @@ S8_String RaylibDLL;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
MA_InitScratch();
|
||||
|
||||
MA_Scratch scratch;
|
||||
UseColoredIO = OS_EnableTerminalColors();
|
||||
|
||||
{
|
||||
CmdParser p = MakeCmdParser(scratch, argc, argv, "I'm a build tool for this codebase, by default I build the entire test suite");
|
||||
CmdParser p = MakeCmdParser(Perm, argc, argv, "I'm a build tool for this codebase, by default I build the entire test suite");
|
||||
AddBool(&p, &BuildX64Sandbox, "build-x64-sandbox", "build the x64 sandbox program using msvc");
|
||||
AddBool(&p, &QuickRun, "quick", "build tests using tcc compiler only");
|
||||
AddBool(&p, &BreakpointOnError, "breakpoint", "breakpoint if a compiler error is thrown");
|
||||
@@ -110,7 +107,7 @@ int main(int argc, char **argv) {
|
||||
PushDir("x64_sandbox");
|
||||
S8_String cc = "cl";
|
||||
|
||||
Array<S8_String> flags = {MA_GetAllocator(scratch)};
|
||||
Array<S8_String> flags = {MA_GetAllocator(Perm)};
|
||||
flags += "/MP /Zi -D_CRT_SECURE_NO_WARNINGS";
|
||||
flags += "/FC /WX /W3 /wd4200 /diagnostics:column /nologo";
|
||||
flags += "/GF /Gm- /Oi";
|
||||
@@ -166,12 +163,6 @@ int main(int argc, char **argv) {
|
||||
else IO_Printf("%-50s - ERROR\n", "hello_world");
|
||||
}
|
||||
|
||||
if (ShouldRun("sandbox")) {
|
||||
bool result = sandbox();
|
||||
if (result) IO_Printf("%-50s - OK\n", "sandbox");
|
||||
else IO_Printf("%-50s - ERROR\n", "sandbox");
|
||||
}
|
||||
|
||||
if (ShouldRun("create_raylib_window")) {
|
||||
bool result = create_raylib_window();
|
||||
if (result) IO_Printf("%-50s - OK\n", "create_raylib_window");
|
||||
@@ -184,27 +175,28 @@ int main(int argc, char **argv) {
|
||||
else IO_Printf("%-50s - ERROR\n", "add_instrumentation");
|
||||
}
|
||||
|
||||
if (ShouldRun("wasm_playground") && UseClang) {
|
||||
bool build_wasm = false;
|
||||
if (build_wasm && ShouldRun("wasm_playground") && UseClang) {
|
||||
OS_MakeDir("wasm_playground");
|
||||
int result = Run("clang --target=wasm32 -mbulk-memory -Oz -Wno-writable-strings --no-standard-libraries -Wl,--strip-all -Wl,--import-memory -Wl,--no-entry -o wasm_playground/playground.wasm ../src/wasm_playground/wasm_main.c -DOS_WASM=1");
|
||||
|
||||
S8_String index = OS_ReadFile(scratch, "../src/wasm_playground/index.html");
|
||||
S8_String index = OS_ReadFile(Perm, "../src/wasm_playground/index.html");
|
||||
S8_List programs = S8_MakeEmptyList();
|
||||
|
||||
OS_SetWorkingDir("wasm_playground"); // so that RegisterDir("../../pkgs") works
|
||||
for (OS_FileIter it = OS_IterateFiles(scratch, "../../src/wasm_playground/"); OS_IsValid(it); OS_Advance(&it)) {
|
||||
for (OS_FileIter it = OS_IterateFiles(Perm, "../../src/wasm_playground/"); OS_IsValid(it); OS_Advance(&it)) {
|
||||
if (S8_EndsWith(it.filename, ".lc", false)) {
|
||||
RunTestFile({TestKind_File, it.absolute_path, it.filename, "not_needed", true});
|
||||
|
||||
S8_String file = OS_ReadFile(scratch, it.absolute_path);
|
||||
file = S8_ReplaceAll(scratch, file, S8_Lit("\\"), S8_Lit("\\\\"), true);
|
||||
S8_AddF(scratch, &programs, "`%.*s`,\n", S8_Expand(file));
|
||||
S8_String file = OS_ReadFile(Perm, it.absolute_path);
|
||||
file = S8_ReplaceAll(Perm, file, S8_Lit("\\"), S8_Lit("\\\\"), true);
|
||||
S8_AddF(Perm, &programs, "`%.*s`,\n", S8_Expand(file));
|
||||
}
|
||||
}
|
||||
OS_SetWorkingDir("..");
|
||||
|
||||
S8_String programs_string = S8_Merge(scratch, programs);
|
||||
S8_String new_index = S8_ReplaceAll(scratch, index, "<InsertPrograms>", programs_string, false);
|
||||
S8_String programs_string = S8_Merge(Perm, programs);
|
||||
S8_String new_index = S8_ReplaceAll(Perm, index, "<InsertPrograms>", programs_string, false);
|
||||
|
||||
OS_WriteFile("wasm_playground/playground.html", new_index);
|
||||
OS_CopyFile("../src/wasm_playground/run_server.bat", "wasm_playground/run_server.bat", true);
|
||||
@@ -225,13 +217,13 @@ int main(int argc, char **argv) {
|
||||
else IO_Printf("%-50s - ERROR\n", "add_source_location_macro");
|
||||
}
|
||||
|
||||
Array<Process> processes = {MA_GetAllocator(scratch)};
|
||||
Array<Process> processes = {MA_GetAllocator(Perm)};
|
||||
if (ShouldRun("compilation")) {
|
||||
//
|
||||
// Test if things compile in C and C++ mode on all available compilers
|
||||
//
|
||||
S8_String working_dir = PushDir("targets");
|
||||
Array<S8_String> files = {MA_GetAllocator(scratch)};
|
||||
Array<S8_String> files = {MA_GetAllocator(Perm)};
|
||||
|
||||
files.add("../../../tests/compilation/test_compile_packed.c");
|
||||
files.add("../../../tests/compilation/test_compile_packed_cpp.c");
|
||||
@@ -249,12 +241,12 @@ int main(int argc, char **argv) {
|
||||
if (UseCL) {
|
||||
S8_String cc = "cl";
|
||||
|
||||
Array<S8_String> flags = {MA_GetAllocator(scratch)};
|
||||
Array<S8_String> flags = {MA_GetAllocator(Perm)};
|
||||
flags += "/Zi -D_CRT_SECURE_NO_WARNINGS";
|
||||
flags += "/FC /WX /W3 /wd4200 /diagnostics:column /nologo";
|
||||
flags += Fmt("/Fe:%.*s /Fd:%.*s.pdb", S8_Expand(exe), S8_Expand(name_no_ext));
|
||||
|
||||
Array<S8_String> link = {MA_GetAllocator(scratch)};
|
||||
Array<S8_String> link = {MA_GetAllocator(Perm)};
|
||||
link += "/link /incremental:no";
|
||||
|
||||
S8_String dir = Fmt("%.*s_cl_debug_" OS_NAME, S8_Expand(name_no_ext));
|
||||
@@ -265,7 +257,7 @@ int main(int argc, char **argv) {
|
||||
if (UseClang) {
|
||||
S8_String cc = "clang";
|
||||
|
||||
Array<S8_String> flags = {MA_GetAllocator(scratch)};
|
||||
Array<S8_String> flags = {MA_GetAllocator(Perm)};
|
||||
flags += "-g -Wno-write-strings";
|
||||
flags += "-fdiagnostics-absolute-paths";
|
||||
flags += "-fsanitize=address";
|
||||
@@ -281,7 +273,7 @@ int main(int argc, char **argv) {
|
||||
if (UseGCC) {
|
||||
S8_String cc = "gcc";
|
||||
|
||||
Array<S8_String> flags = {MA_GetAllocator(scratch)};
|
||||
Array<S8_String> flags = {MA_GetAllocator(Perm)};
|
||||
flags += "-g -Wno-write-strings";
|
||||
flags += "-fsanitize=address";
|
||||
if (is_cpp) flags += "-std=c++11";
|
||||
|
||||
@@ -37,12 +37,12 @@ bool add_instrumentation() {
|
||||
}
|
||||
|
||||
LC_String code = LC_GenerateUnityBuild();
|
||||
LC_LangEnd(lang);
|
||||
|
||||
S8_String path = "examples/add_instrumentation/add_instrumentation.c";
|
||||
OS_MakeDir("examples");
|
||||
OS_MakeDir("examples/add_instrumentation");
|
||||
OS_WriteFile(path, code);
|
||||
LC_LangEnd(lang);
|
||||
if (!UseCL) return true;
|
||||
|
||||
S8_String cmd = Fmt("cl %.*s -Zi -std:c11 -nologo -FC -Fd:examples/add_instrumentation/a.pdb -Fe:examples/add_instrumentation/add_instrumentation.exe %.*s", S8_Expand(path), S8_Expand(RaylibLIB));
|
||||
|
||||
@@ -34,10 +34,9 @@ bool add_source_location_macro() {
|
||||
}
|
||||
|
||||
LC_String code = LC_GenerateUnityBuild();
|
||||
LC_LangEnd(lang);
|
||||
|
||||
OS_MakeDir("examples/add_source_location_macro");
|
||||
OS_WriteFile("examples/add_source_location_macro/add_source_location_macro.c", code);
|
||||
LC_LangEnd(lang);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -16,10 +16,10 @@ bool hello_world() {
|
||||
OS_MakeDir("examples/hello_world");
|
||||
LC_ParseAndResolve(name);
|
||||
LC_String code = LC_GenerateUnityBuild();
|
||||
LC_LangEnd(lang);
|
||||
|
||||
S8_String path = "examples/hello_world/hello_world.c";
|
||||
OS_WriteFile(path, code);
|
||||
LC_LangEnd(lang);
|
||||
if (UseCL) {
|
||||
S8_String cmd = Fmt("cl %.*s -nologo -FC -Fd:examples/hello_world/hello_world.pdb -Fe:examples/hello_world/hello_world.exe", S8_Expand(path));
|
||||
if (Run(cmd) != 0) return false;
|
||||
|
||||
@@ -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); };
|
||||
|
||||
LC_RegisterPackageDir("../pkgs");
|
||||
LC_RegisterPackageDir("../examples");
|
||||
LC_RegisterPackageDir("../examples/text_editor");
|
||||
|
||||
LC_Intern name = LC_ILit("text_editor");
|
||||
LC_Intern name = LC_ILit("entry_point");
|
||||
LC_ParseAndResolve(name);
|
||||
if (L->errors) return false;
|
||||
|
||||
@@ -26,7 +26,7 @@ bool text_editor() {
|
||||
OS_WriteFile(path, code);
|
||||
|
||||
if (!UseCL) return true;
|
||||
S8_String cmd = Fmt("cl %.*s -Zi -std:c11 -nologo -FC -Fd:examples/text_editor/a.pdb -Fe:examples/text_editor/text_editor.exe %.*s", S8_Expand(path), S8_Expand(RaylibLIB));
|
||||
S8_String cmd = Fmt("cl %.*s ../src/core/core.c -Zi -std:c11 -nologo -FC -Fd:examples/text_editor/a.pdb -Fe:examples/text_editor/text_editor.exe %.*s", S8_Expand(path), S8_Expand(RaylibLIB));
|
||||
int errcode = Run(cmd);
|
||||
if (errcode != 0) return false;
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
F32_Max :: proc(a: f32, b: f32): f32 {
|
||||
if a > b return a;
|
||||
return b;
|
||||
}
|
||||
|
||||
F32_Min :: proc(a: f32, b: f32): f32 {
|
||||
if a > b return b;
|
||||
return a;
|
||||
}
|
||||
|
||||
F32_Clamp :: proc(val: f32, min: f32, max: f32): f32 {
|
||||
if (val > max) return max;
|
||||
if (val < min) return min;
|
||||
return val;
|
||||
}
|
||||
|
||||
GetRectSize :: proc(rect: Rect2P): Vector2 {
|
||||
result: Vector2 = {rect.max.x - rect.min.x, rect.max.y - rect.min.y};
|
||||
return result;
|
||||
@@ -36,7 +20,7 @@ GetRectX :: proc(rect: Rect2P): f32 {
|
||||
|
||||
CutLeft :: proc(r: *Rect2P, value: f32): Rect2P {
|
||||
minx := r.min.x;
|
||||
r.min.x = F32_Min(r.max.x, r.min.x + value);
|
||||
r.min.x = MinFloat(r.max.x, r.min.x + value);
|
||||
return :Rect2P{
|
||||
{ minx, r.min.y},
|
||||
{r.min.x, r.max.y},
|
||||
@@ -45,7 +29,7 @@ CutLeft :: proc(r: *Rect2P, value: f32): Rect2P {
|
||||
|
||||
CutRight :: proc(r: *Rect2P, value: f32): Rect2P {
|
||||
maxx := r.max.x;
|
||||
r.max.x = F32_Max(r.max.x - value, r.min.x);
|
||||
r.max.x = MaxFloat(r.max.x - value, r.min.x);
|
||||
return :Rect2P{
|
||||
{r.max.x, r.min.y},
|
||||
{ maxx, r.max.y},
|
||||
@@ -54,7 +38,7 @@ CutRight :: proc(r: *Rect2P, value: f32): Rect2P {
|
||||
|
||||
CutBottom :: proc(r: *Rect2P, value: f32): Rect2P { // Y is down
|
||||
maxy := r.max.y;
|
||||
r.max.y = F32_Max(r.min.y, r.max.y - value);
|
||||
r.max.y = MaxFloat(r.min.y, r.max.y - value);
|
||||
return :Rect2P{
|
||||
{r.min.x, r.max.y},
|
||||
{r.max.x, maxy},
|
||||
@@ -63,7 +47,7 @@ CutBottom :: proc(r: *Rect2P, value: f32): Rect2P { // Y is down
|
||||
|
||||
CutTop :: proc(r: *Rect2P, value: f32): Rect2P { // Y is down
|
||||
miny := r.min.y;
|
||||
r.min.y = F32_Min(r.min.y + value, r.max.y);
|
||||
r.min.y = MinFloat(r.min.y + value, r.max.y);
|
||||
return :Rect2P{
|
||||
{r.min.x, miny},
|
||||
{r.max.x, r.min.y},
|
||||
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;
|
||||
}
|
||||
|
||||
ClampInt :: proc(val: int, min: int, max: int): int {
|
||||
result := val;
|
||||
if (val < min) result = min;
|
||||
if (val > max) result = max;
|
||||
return result;
|
||||
}
|
||||
|
||||
MinInt :: proc(a: int, b: int): int {
|
||||
result := a;
|
||||
if (a > b) result = b;
|
||||
return result;
|
||||
}
|
||||
|
||||
MaxInt :: proc(a: int, b: int): int {
|
||||
result := b;
|
||||
if (a > b) result = a;
|
||||
return result;
|
||||
}
|
||||
|
||||
AdjustUTF8PosUnsafe :: proc(buffer: *Buffer, pos: int, direction: int = 1): int {
|
||||
for pos >= 0 && pos < buffer.len && IsUTF8ContinuationByte(buffer.data[pos]) {
|
||||
pos += direction;
|
||||
@@ -53,10 +34,25 @@ AdjustUTF8PosUnsafe :: proc(buffer: *Buffer, pos: int, direction: int = 1): int
|
||||
return pos;
|
||||
}
|
||||
|
||||
GetBufferEnd :: proc(buffer: *Buffer): int {
|
||||
result := MaxInt(0, buffer.len - 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
GetBufferEndRange :: proc(buffer: *Buffer): Range {
|
||||
result := GetBufferEnd(buffer);
|
||||
return {result, result};
|
||||
}
|
||||
|
||||
GetEntireBufferRange :: proc(buffer: *Buffer): Range {
|
||||
result: Range = {0, GetBufferEnd(buffer)};
|
||||
return result;
|
||||
}
|
||||
|
||||
AdjustUTF8Pos :: proc(buffer: *Buffer, pos: int, direction: int = 1): int {
|
||||
assert(direction == 1 || direction == -1);
|
||||
pos = AdjustUTF8PosUnsafe(buffer, pos, direction);
|
||||
pos = ClampInt(pos, 0, buffer.len - 1);
|
||||
pos = ClampInt(pos, 0, GetBufferEnd(buffer));
|
||||
if (buffer.data) assert(!IsUTF8ContinuationByte(buffer.data[pos]));
|
||||
return pos;
|
||||
}
|
||||
@@ -150,8 +146,7 @@ GetStringFromBuffer :: proc(buffer: *Buffer, range: Range): String {
|
||||
}
|
||||
|
||||
AddText :: proc(buffer: *Buffer, text: String) {
|
||||
end_of_buffer: Range = {buffer.len - 1, buffer.len - 1};
|
||||
ReplaceText(buffer, end_of_buffer, text);
|
||||
ReplaceText(buffer, GetBufferEndRange(buffer), text);
|
||||
}
|
||||
|
||||
FindLineOfPos :: proc(buffer: *Buffer, pos: int): LineInfo {
|
||||
@@ -223,7 +218,7 @@ SeekOnWordBoundary :: proc(buffer: *Buffer, pos: int, direction: int = GO_FORWAR
|
||||
seek_whitespace := standing_on_whitespace == false;
|
||||
seek_word := standing_on_whitespace;
|
||||
|
||||
end := buffer.len - 1;
|
||||
end := GetBufferEnd(buffer);
|
||||
if (direction == GO_BACKWARD) end = 0;
|
||||
|
||||
result := end;
|
||||
@@ -1,14 +1,45 @@
|
||||
/*
|
||||
- Ctrl+C
|
||||
- Ctrl+V
|
||||
- Ctrl+X
|
||||
- Windows
|
||||
- Multiple buffers at the same time
|
||||
*/
|
||||
import "raylib";
|
||||
import "std_types";
|
||||
import "raylib";
|
||||
import "libc";
|
||||
|
||||
import "core";
|
||||
|
||||
Inited := false;
|
||||
TeBuffer: Buffer;
|
||||
|
||||
FocusedWindow: *Window;
|
||||
WindowStack: [8]Window;
|
||||
WindowStackCount: int;
|
||||
|
||||
UpdateTextEditor :: proc(rect: Rect2P, font: Font, font_size: float, font_spacing: float) {
|
||||
if !Inited {
|
||||
Inited = true;
|
||||
file_content := LoadFileText("C:/Work/language/examples/text_editor/entry_point/entry_point.lc");
|
||||
AddText(&TeBuffer, {file_content, :int(strlen(file_content))});
|
||||
UnloadFileText(file_content);
|
||||
|
||||
AddWindow({buffer = &TeBuffer});
|
||||
AddWindow({buffer = &TeBuffer});
|
||||
FocusedWindow = &WindowStack[0];
|
||||
}
|
||||
ComputeWindowRects(rect);
|
||||
UpdateAndDrawWindows(font, font_size);
|
||||
}
|
||||
|
||||
WindowFlags_DrawScrollbar :: 1;
|
||||
|
||||
Window :: struct {
|
||||
flags: u64;
|
||||
buffer: *Buffer;
|
||||
|
||||
cursor: Selection;
|
||||
scroll: Vector2;
|
||||
mouse_scrolling: bool;
|
||||
mouse_selecting: bool;
|
||||
|
||||
rect: Rect2P;
|
||||
}
|
||||
|
||||
Selection :: struct {
|
||||
a: int;
|
||||
b: int;
|
||||
@@ -19,19 +50,6 @@ GetRange :: proc(s: Selection): Range {
|
||||
return result;
|
||||
}
|
||||
|
||||
Window :: struct {
|
||||
buffer: *Buffer;
|
||||
cursor: Selection;
|
||||
scroll: Vector2;
|
||||
mouse_scrolling: bool;
|
||||
|
||||
rect: Rect2P;
|
||||
}
|
||||
|
||||
FocusedWindow: *Window;
|
||||
WindowStack: [8]Window;
|
||||
WindowStackCount: int;
|
||||
|
||||
AddWindow :: proc(window: Window) {
|
||||
if (WindowStackCount + 1 >= 8) return;
|
||||
|
||||
@@ -45,6 +63,7 @@ ComputeWindowRects :: proc(screen_rect: Rect2P) {
|
||||
}
|
||||
|
||||
UpdateAndDrawWindows :: proc(font: Font, font_size: float) {
|
||||
SetMouseCursor(MOUSE_CURSOR_DEFAULT);
|
||||
for i := 0; i < WindowStackCount; i += 1 {
|
||||
window: *Window = &WindowStack[i];
|
||||
UpdateAndDrawWindow(window, font, font_size);
|
||||
@@ -54,9 +73,11 @@ UpdateAndDrawWindows :: proc(font: Font, font_size: float) {
|
||||
UpdateAndDrawWindow :: proc(w: *Window, font: Font, font_size: float) {
|
||||
initial_cursor: Selection = w.cursor;
|
||||
text_window_rect := w.rect;
|
||||
bar := CutRight(&text_window_rect, 10);
|
||||
bar_rect := CutRight(&text_window_rect, 10);
|
||||
horizontal_bar_rect := CutBottom(&text_window_rect, 10);
|
||||
// line_numbers_rect := CutLeft(&text_window_rect, Monosize.x * 4);
|
||||
|
||||
buffer_end_vpos := CalculateVisualPos(w.buffer, w.buffer.len - 1);
|
||||
buffer_end_vpos := CalculateVisualPos(w.buffer, GetBufferEnd(w.buffer));
|
||||
buffer_end_wpos := CalculateWorldPosUnscrolled(buffer_end_vpos);
|
||||
|
||||
if CheckCollisionPointRec(GetMousePosition(), Rect2PToRectangle(w.rect)) {
|
||||
@@ -68,7 +89,6 @@ UpdateAndDrawWindow :: proc(w: *Window, font: Font, font_size: float) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if w == FocusedWindow {
|
||||
if IsKeyPressed(KEY_LEFT) || IsKeyPressedRepeat(KEY_LEFT) {
|
||||
if IsKeyDown(KEY_LEFT_SHIFT) {
|
||||
@@ -226,6 +246,12 @@ UpdateAndDrawWindow :: proc(w: *Window, font: Font, font_size: float) {
|
||||
}
|
||||
}
|
||||
|
||||
// @todo: buffer.len abstract
|
||||
if IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_A) {
|
||||
w.cursor.a = 0;
|
||||
w.cursor.b = GetBufferEnd(w.buffer);
|
||||
}
|
||||
|
||||
if IsKeyPressed(KEY_PAGE_DOWN) || IsKeyPressedRepeat(KEY_PAGE_DOWN) {
|
||||
vpos := CalculateVisualPos(w.buffer, w.cursor.b);
|
||||
move_by := :int(roundf(GetRectY(text_window_rect) / Monosize.y));
|
||||
@@ -304,6 +330,7 @@ UpdateAndDrawWindow :: proc(w: *Window, font: Font, font_size: float) {
|
||||
if CheckCollisionPointRec(mouse_p, Rect2PToRectangle(w.rect)) {
|
||||
if CheckCollisionPointRec(mouse_p, Rect2PToRectangle(text_window_rect)) && !w.mouse_scrolling {
|
||||
if IsMouseButtonPressed(MOUSE_BUTTON_LEFT) {
|
||||
w.mouse_selecting = true;
|
||||
p := Vector2Add(mouse_p, w.scroll);
|
||||
p = Vector2Subtract(p, text_window_rect.min);
|
||||
p = Vector2Divide(p, Monosize);
|
||||
@@ -311,26 +338,30 @@ UpdateAndDrawWindow :: proc(w: *Window, font: Font, font_size: float) {
|
||||
y := :int(floorf(p.y));
|
||||
w.cursor.a = CalculatePosFromVisualPos(w.buffer, {x, y});
|
||||
w.cursor.b = w.cursor.a;
|
||||
} else if IsMouseButtonDown(MOUSE_BUTTON_LEFT) {
|
||||
p := Vector2Add(mouse_p, w.scroll);
|
||||
p = Vector2Subtract(p, text_window_rect.min);
|
||||
p = Vector2Divide(p, Monosize);
|
||||
x := :int(floorf(p.x));
|
||||
y := :int(floorf(p.y));
|
||||
w.cursor.b = CalculatePosFromVisualPos(w.buffer, {x, y});
|
||||
}
|
||||
SetMouseCursor(MOUSE_CURSOR_IBEAM);
|
||||
} else {
|
||||
SetMouseCursor(MOUSE_CURSOR_DEFAULT);
|
||||
|
||||
if IsMouseButtonPressed(MOUSE_BUTTON_LEFT) {
|
||||
w.mouse_scrolling = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if w.mouse_scrolling {
|
||||
mouse_scroll_marker_normalized := (mouse_p.y - w.rect.min.y) / GetRectY(bar);
|
||||
if w.mouse_selecting && IsMouseButtonDown(MOUSE_BUTTON_LEFT) {
|
||||
SetMouseCursor(MOUSE_CURSOR_DEFAULT);
|
||||
p := Vector2Add(mouse_p, w.scroll);
|
||||
p = Vector2Subtract(p, text_window_rect.min);
|
||||
p = Vector2Divide(p, Monosize);
|
||||
x := :int(floorf(p.x));
|
||||
y := :int(floorf(p.y));
|
||||
w.cursor.b = CalculatePosFromVisualPos(w.buffer, {x, y});
|
||||
} else {
|
||||
w.mouse_selecting = false;
|
||||
}
|
||||
|
||||
if IsFlagSet(w.flags, WindowFlags_DrawScrollbar) && w.mouse_scrolling {
|
||||
mouse_scroll_marker_normalized := (mouse_p.y - w.rect.min.y) / GetRectY(bar_rect);
|
||||
w.scroll.y = mouse_scroll_marker_normalized * buffer_end_wpos.y;
|
||||
|
||||
if IsMouseButtonReleased(MOUSE_BUTTON_LEFT) w.mouse_scrolling = false;
|
||||
@@ -362,22 +393,28 @@ UpdateAndDrawWindow :: proc(w: *Window, font: Font, font_size: float) {
|
||||
}
|
||||
}
|
||||
|
||||
BeginScissorMode(:int(text_window_rect.min.x), :int(text_window_rect.min.y), :int(GetRectX(text_window_rect)), :int(GetRectY(text_window_rect)));
|
||||
BeginScissorMode(:int(w.rect.min.x), :int(w.rect.min.y), :int(GetRectX(w.rect)), :int(GetRectY(w.rect)));
|
||||
|
||||
// Draw text
|
||||
// Draw text and line numbers
|
||||
{
|
||||
FONT_SPACING :: 1;
|
||||
|
||||
// DrawRect(line_numbers_rect, LIGHTGRAY);
|
||||
miny = ClampInt(miny, 0, w.buffer.lines.len - 1);
|
||||
maxy = ClampInt(maxy, 0, w.buffer.lines.len - 1);
|
||||
for y := miny; y <= maxy; y += 1 {
|
||||
line := w.buffer.lines.data[y];
|
||||
line_range := w.buffer.lines.data[y];
|
||||
|
||||
string := AllocStringFromBuffer(w.buffer, line, null_terminate = true);
|
||||
string := AllocStringFromBuffer(w.buffer, line_range, null_terminate = true);
|
||||
defer free(string.str);
|
||||
|
||||
pos := CalculateWorldPos(w.scroll, {0, y});
|
||||
pos_adjusted_by_buffer := Vector2Add(pos, text_window_rect.min);
|
||||
FONT_SPACING :: 1;
|
||||
DrawTextEx(font, string.str, pos_adjusted_by_buffer, font_size, FONT_SPACING, BLACK);
|
||||
|
||||
// line_number_pos: Vector2 = {w.rect.min.x, pos_adjusted_by_buffer.y};
|
||||
// line_number_string := TextFormat("%d", y);
|
||||
// DrawTextEx(font, line_number_string, line_number_pos, font_size, FONT_SPACING, GRAY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,7 +428,7 @@ UpdateAndDrawWindow :: proc(w: *Window, font: Font, font_size: float) {
|
||||
world_pos_adjusted_by_buffer := Vector2Add(world_pos, text_window_rect.min);
|
||||
|
||||
rect := Rect2PSize(world_pos_adjusted_by_buffer.x, world_pos_adjusted_by_buffer.y, Monosize.x, Monosize.y);
|
||||
DrawRect(rect, {0, 255, 0, 40});
|
||||
DrawRect(rect, {0, 92, 222, 40});
|
||||
|
||||
pos.x += 1;
|
||||
if iter.item == '\n' {
|
||||
@@ -418,55 +455,18 @@ UpdateAndDrawWindow :: proc(w: *Window, font: Font, font_size: float) {
|
||||
|
||||
|
||||
// Draw bar
|
||||
{
|
||||
DrawRect(bar, LIGHTGRAY);
|
||||
if IsFlagSet(w.flags, WindowFlags_DrawScrollbar) {
|
||||
DrawRect(bar_rect, LIGHTGRAY);
|
||||
DrawRect(horizontal_bar_rect, LIGHTGRAY);
|
||||
|
||||
scroll_start_normalized := :f32(w.scroll.y) / :f32(buffer_end_wpos.y);
|
||||
scroll_start := scroll_start_normalized * GetRectSize(bar).y;
|
||||
CutTop(&bar, scroll_start);
|
||||
marker := CutTop(&bar, 20);
|
||||
scroll_start := scroll_start_normalized * GetRectSize(bar_rect).y;
|
||||
CutTop(&bar_rect, scroll_start);
|
||||
marker := CutTop(&bar_rect, 20);
|
||||
DrawRect(marker, GRAY);
|
||||
}
|
||||
}
|
||||
|
||||
InvalidCodepath :: proc() {
|
||||
assert(:*char("invalid codepath") == :*char(""));
|
||||
}
|
||||
|
||||
|
||||
main :: proc(): int {
|
||||
InitWindow(800, 600, "TextEditor");
|
||||
SetWindowState(FLAG_WINDOW_RESIZABLE | FLAG_WINDOW_MAXIMIZED);
|
||||
SetTargetFPS(60);
|
||||
|
||||
font_size: float = 14;
|
||||
font_spacing: float = 1;
|
||||
font: Font = LoadFontEx("C:/Windows/Fonts/consola.ttf", :int(font_size), nil, 0);
|
||||
|
||||
glyph_info: GlyphInfo = GetGlyphInfo(font, 'A');
|
||||
size := MeasureTextEx(font, "A", font_size, font_spacing);
|
||||
Monosize = {:float(glyph_info.image.width), size.y};
|
||||
|
||||
buffer: Buffer;
|
||||
file_content := LoadFileText("C:/Work/language/examples/text_editor/main.lc");
|
||||
AddText(&buffer, {file_content, :int(strlen(file_content))});
|
||||
UnloadFileText(file_content);
|
||||
|
||||
AddWindow({buffer = &buffer});
|
||||
AddWindow({buffer = &buffer});
|
||||
FocusedWindow = &WindowStack[0];
|
||||
|
||||
for !WindowShouldClose() {
|
||||
screen_size: Vector2 = {:f32(GetScreenWidth()), :f32(GetScreenHeight())};
|
||||
screen_rect := Rect2PSize(0, 0, screen_size.x, screen_size.y);
|
||||
ComputeWindowRects(screen_rect);
|
||||
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(RAYWHITE);
|
||||
UpdateAndDrawWindows(font, font_size);
|
||||
EndDrawing();
|
||||
if w != FocusedWindow {
|
||||
DrawRect(w.rect, {0,0,0,20});
|
||||
}
|
||||
CloseWindow();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1045,9 +1045,9 @@ LC_FUNCTION void LC_ResolveProcBodiesPass(void); // The Parse an
|
||||
LC_FUNCTION void LC_FindUnusedLocalsAndRemoveUnusedGlobalDeclsPass(void); // Extended pass that you can execute once you have resolved all packages
|
||||
|
||||
// These three functions are used to implement LC_FindUnusedLocalsAndRemoveUnusedGlobalDeclsPass
|
||||
LC_FUNCTION LC_Map LC_CountDeclRefs(LC_Arena *arena);
|
||||
LC_FUNCTION void LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits);
|
||||
LC_FUNCTION void LC_ErrorOnUnreferencedLocalsPass(LC_Map *map_of_visits);
|
||||
LC_FUNCTION void LC_CountDeclRefs(LC_Arena *arena, LC_Map *map, LC_AST *ast);
|
||||
LC_FUNCTION LC_Decl *LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits);
|
||||
LC_FUNCTION void LC_ErrorOnUnreferencedLocalsPass(LC_Map *map_of_visits);
|
||||
|
||||
// Notes
|
||||
LC_FUNCTION void LC_DeclareNote(LC_Intern intern);
|
||||
@@ -6855,16 +6855,15 @@ LC_FUNCTION LC_Operand LC_ResolveExprEx(LC_AST *n) {
|
||||
} break;
|
||||
|
||||
case LC_ASTKind_ExprField: {
|
||||
bool first_part_executed = false;
|
||||
bool resolved_import = false;
|
||||
|
||||
LC_Operand op = {0};
|
||||
if (n->efield.left->kind == LC_ASTKind_ExprIdent) {
|
||||
LC_AST *nf = n->efield.left;
|
||||
LC_Operand LC_PROP_ERROR(op_name, nf, LC_ResolveName(nf, nf->eident.name));
|
||||
|
||||
// LC_Match (Package.) and fold (Package.Other) into just (Other)
|
||||
if (op_name.decl->kind == LC_DeclKind_Import) {
|
||||
first_part_executed = true;
|
||||
resolved_import = true;
|
||||
nf->eident.resolved_decl = op_name.decl;
|
||||
nf->type = L->tvoid;
|
||||
|
||||
@@ -6872,7 +6871,7 @@ LC_FUNCTION LC_Operand LC_ResolveExprEx(LC_AST *n) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!first_part_executed) {
|
||||
if (!resolved_import) {
|
||||
LC_ASTKind left_kind = n->efield.left->kind;
|
||||
LC_PROP_ERROR(op, n, LC_ResolveExpr(n->efield.left));
|
||||
|
||||
@@ -6882,8 +6881,17 @@ LC_FUNCTION LC_Operand LC_ResolveExprEx(LC_AST *n) {
|
||||
LC_PROP_ERROR(op, n, LC_ResolveNameInScope(n, type->decl));
|
||||
LC_ASSERT(n, op.decl->kind == LC_DeclKind_Var);
|
||||
result.flags |= LC_OPF_LValue | LC_OPF_Const;
|
||||
result.val = op.decl->val;
|
||||
} else {
|
||||
result.val = op.decl->val;
|
||||
// @copy_paste from ExprIdent
|
||||
if (op.decl->kind == LC_DeclKind_Const) {
|
||||
result.flags |= LC_OPF_UTConst | LC_OPF_Const;
|
||||
SetConstVal(n, result.val);
|
||||
} else {
|
||||
result.flags |= LC_OPF_LValue | LC_OPF_Const;
|
||||
}
|
||||
}
|
||||
result.val = op.decl->val;
|
||||
} break;
|
||||
|
||||
case LC_ASTKind_ExprCall: {
|
||||
@@ -9891,20 +9899,16 @@ LC_FUNCTION void WalkAndCountDeclRefs(LC_ASTWalker *ctx, LC_AST *n) {
|
||||
}
|
||||
}
|
||||
|
||||
LC_FUNCTION LC_Map LC_CountDeclRefs(LC_Arena *arena) {
|
||||
LC_Map map = {arena};
|
||||
LC_MapReserve(&map, 512);
|
||||
|
||||
LC_AST *package = LC_GetPackageByName(L->first_package);
|
||||
LC_ASTWalker walker = LC_GetDefaultWalker(arena, WalkAndCountDeclRefs);
|
||||
walker.user_data = (void *)↦
|
||||
walker.visit_notes = true;
|
||||
LC_WalkAST(&walker, package);
|
||||
|
||||
return map;
|
||||
LC_FUNCTION void LC_CountDeclRefs(LC_Arena *arena, LC_Map *map, LC_AST *ast) {
|
||||
LC_ASTWalker walker = LC_GetDefaultWalker(arena, WalkAndCountDeclRefs);
|
||||
walker.user_data = (void *)map;
|
||||
walker.visit_notes = true;
|
||||
LC_WalkAST(&walker, ast);
|
||||
}
|
||||
|
||||
LC_FUNCTION void LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits) {
|
||||
LC_FUNCTION LC_Decl *LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits) {
|
||||
LC_Decl *first_removed_decl = NULL;
|
||||
LC_Decl *last_removed_decl = NULL;
|
||||
for (LC_ASTRef *it = L->ordered_packages.first; it; it = it->next) {
|
||||
for (LC_Decl *decl = it->ast->apackage.ext->first_ordered; decl;) {
|
||||
intptr_t ref_count = (intptr_t)LC_MapGetP(map_of_visits, decl);
|
||||
@@ -9913,9 +9917,11 @@ LC_FUNCTION void LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits) {
|
||||
decl = decl->next;
|
||||
if (ref_count == 0 && remove->foreign_name != LC_ILit("main")) {
|
||||
LC_DLLRemove(it->ast->apackage.ext->first_ordered, it->ast->apackage.ext->last_ordered, remove);
|
||||
LC_DLLAdd(first_removed_decl, last_removed_decl, remove);
|
||||
}
|
||||
}
|
||||
}
|
||||
return first_removed_decl;
|
||||
}
|
||||
|
||||
LC_FUNCTION void LC_ErrorOnUnreferencedLocalsPass(LC_Map *map_of_visits) {
|
||||
@@ -9939,9 +9945,16 @@ LC_FUNCTION void LC_FindUnusedLocalsAndRemoveUnusedGlobalDeclsPass(void) {
|
||||
if (L->errors) return;
|
||||
LC_TempArena check = LC_BeginTemp(L->arena);
|
||||
|
||||
LC_Map map = LC_CountDeclRefs(check.arena);
|
||||
LC_AST *package = LC_GetPackageByName(L->first_package);
|
||||
LC_Map map = {check.arena};
|
||||
LC_MapReserve(&map, 512);
|
||||
|
||||
LC_CountDeclRefs(check.arena, &map, package);
|
||||
LC_Decl *first_removed_decl = LC_RemoveUnreferencedGlobalDeclsPass(&map);
|
||||
for (LC_Decl *it = first_removed_decl; it; it = it->next) {
|
||||
LC_CountDeclRefs(check.arena, &map, it->ast);
|
||||
}
|
||||
LC_ErrorOnUnreferencedLocalsPass(&map);
|
||||
LC_RemoveUnreferencedGlobalDeclsPass(&map);
|
||||
|
||||
LC_EndTemp(check);
|
||||
}
|
||||
|
||||
@@ -16,20 +16,16 @@ LC_FUNCTION void WalkAndCountDeclRefs(LC_ASTWalker *ctx, LC_AST *n) {
|
||||
}
|
||||
}
|
||||
|
||||
LC_FUNCTION LC_Map LC_CountDeclRefs(LC_Arena *arena) {
|
||||
LC_Map map = {arena};
|
||||
LC_MapReserve(&map, 512);
|
||||
|
||||
LC_AST *package = LC_GetPackageByName(L->first_package);
|
||||
LC_ASTWalker walker = LC_GetDefaultWalker(arena, WalkAndCountDeclRefs);
|
||||
walker.user_data = (void *)↦
|
||||
walker.visit_notes = true;
|
||||
LC_WalkAST(&walker, package);
|
||||
|
||||
return map;
|
||||
LC_FUNCTION void LC_CountDeclRefs(LC_Arena *arena, LC_Map *map, LC_AST *ast) {
|
||||
LC_ASTWalker walker = LC_GetDefaultWalker(arena, WalkAndCountDeclRefs);
|
||||
walker.user_data = (void *)map;
|
||||
walker.visit_notes = true;
|
||||
LC_WalkAST(&walker, ast);
|
||||
}
|
||||
|
||||
LC_FUNCTION void LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits) {
|
||||
LC_FUNCTION LC_Decl *LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits) {
|
||||
LC_Decl *first_removed_decl = NULL;
|
||||
LC_Decl *last_removed_decl = NULL;
|
||||
for (LC_ASTRef *it = L->ordered_packages.first; it; it = it->next) {
|
||||
for (LC_Decl *decl = it->ast->apackage.ext->first_ordered; decl;) {
|
||||
intptr_t ref_count = (intptr_t)LC_MapGetP(map_of_visits, decl);
|
||||
@@ -38,9 +34,11 @@ LC_FUNCTION void LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits) {
|
||||
decl = decl->next;
|
||||
if (ref_count == 0 && remove->foreign_name != LC_ILit("main")) {
|
||||
LC_DLLRemove(it->ast->apackage.ext->first_ordered, it->ast->apackage.ext->last_ordered, remove);
|
||||
LC_DLLAdd(first_removed_decl, last_removed_decl, remove);
|
||||
}
|
||||
}
|
||||
}
|
||||
return first_removed_decl;
|
||||
}
|
||||
|
||||
LC_FUNCTION void LC_ErrorOnUnreferencedLocalsPass(LC_Map *map_of_visits) {
|
||||
@@ -64,9 +62,16 @@ LC_FUNCTION void LC_FindUnusedLocalsAndRemoveUnusedGlobalDeclsPass(void) {
|
||||
if (L->errors) return;
|
||||
LC_TempArena check = LC_BeginTemp(L->arena);
|
||||
|
||||
LC_Map map = LC_CountDeclRefs(check.arena);
|
||||
LC_AST *package = LC_GetPackageByName(L->first_package);
|
||||
LC_Map map = {check.arena};
|
||||
LC_MapReserve(&map, 512);
|
||||
|
||||
LC_CountDeclRefs(check.arena, &map, package);
|
||||
LC_Decl *first_removed_decl = LC_RemoveUnreferencedGlobalDeclsPass(&map);
|
||||
for (LC_Decl *it = first_removed_decl; it; it = it->next) {
|
||||
LC_CountDeclRefs(check.arena, &map, it->ast);
|
||||
}
|
||||
LC_ErrorOnUnreferencedLocalsPass(&map);
|
||||
LC_RemoveUnreferencedGlobalDeclsPass(&map);
|
||||
|
||||
LC_EndTemp(check);
|
||||
}
|
||||
@@ -1001,9 +1001,9 @@ LC_FUNCTION void LC_ResolveProcBodiesPass(void); // The Parse an
|
||||
LC_FUNCTION void LC_FindUnusedLocalsAndRemoveUnusedGlobalDeclsPass(void); // Extended pass that you can execute once you have resolved all packages
|
||||
|
||||
// These three functions are used to implement LC_FindUnusedLocalsAndRemoveUnusedGlobalDeclsPass
|
||||
LC_FUNCTION LC_Map LC_CountDeclRefs(LC_Arena *arena);
|
||||
LC_FUNCTION void LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits);
|
||||
LC_FUNCTION void LC_ErrorOnUnreferencedLocalsPass(LC_Map *map_of_visits);
|
||||
LC_FUNCTION void LC_CountDeclRefs(LC_Arena *arena, LC_Map *map, LC_AST *ast);
|
||||
LC_FUNCTION LC_Decl *LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits);
|
||||
LC_FUNCTION void LC_ErrorOnUnreferencedLocalsPass(LC_Map *map_of_visits);
|
||||
|
||||
// Notes
|
||||
LC_FUNCTION void LC_DeclareNote(LC_Intern intern);
|
||||
|
||||
@@ -690,16 +690,15 @@ LC_FUNCTION LC_Operand LC_ResolveExprEx(LC_AST *n) {
|
||||
} break;
|
||||
|
||||
case LC_ASTKind_ExprField: {
|
||||
bool first_part_executed = false;
|
||||
bool resolved_import = false;
|
||||
|
||||
LC_Operand op = {0};
|
||||
if (n->efield.left->kind == LC_ASTKind_ExprIdent) {
|
||||
LC_AST *nf = n->efield.left;
|
||||
LC_Operand LC_PROP_ERROR(op_name, nf, LC_ResolveName(nf, nf->eident.name));
|
||||
|
||||
// LC_Match (Package.) and fold (Package.Other) into just (Other)
|
||||
if (op_name.decl->kind == LC_DeclKind_Import) {
|
||||
first_part_executed = true;
|
||||
resolved_import = true;
|
||||
nf->eident.resolved_decl = op_name.decl;
|
||||
nf->type = L->tvoid;
|
||||
|
||||
@@ -707,7 +706,7 @@ LC_FUNCTION LC_Operand LC_ResolveExprEx(LC_AST *n) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!first_part_executed) {
|
||||
if (!resolved_import) {
|
||||
LC_ASTKind left_kind = n->efield.left->kind;
|
||||
LC_PROP_ERROR(op, n, LC_ResolveExpr(n->efield.left));
|
||||
|
||||
@@ -717,8 +716,17 @@ LC_FUNCTION LC_Operand LC_ResolveExprEx(LC_AST *n) {
|
||||
LC_PROP_ERROR(op, n, LC_ResolveNameInScope(n, type->decl));
|
||||
LC_ASSERT(n, op.decl->kind == LC_DeclKind_Var);
|
||||
result.flags |= LC_OPF_LValue | LC_OPF_Const;
|
||||
result.val = op.decl->val;
|
||||
} else {
|
||||
result.val = op.decl->val;
|
||||
// @copy_paste from ExprIdent
|
||||
if (op.decl->kind == LC_DeclKind_Const) {
|
||||
result.flags |= LC_OPF_UTConst | LC_OPF_Const;
|
||||
SetConstVal(n, result.val);
|
||||
} else {
|
||||
result.flags |= LC_OPF_LValue | LC_OPF_Const;
|
||||
}
|
||||
}
|
||||
result.val = op.decl->val;
|
||||
} break;
|
||||
|
||||
case LC_ASTKind_ExprCall: {
|
||||
|
||||
@@ -118,7 +118,7 @@ MA_API void * MA__PushSizeNonZeroed(MA_Arena *a, size_t size);
|
||||
MA_API void * MA__PushSize(MA_Arena *arena, size_t size);
|
||||
MA_API char * MA__PushStringCopy(MA_Arena *arena, char *p, size_t size);
|
||||
MA_API void * MA__PushCopy(MA_Arena *arena, void *p, size_t size);
|
||||
MA_API MA_Temp MA_BeginTemp(MA_Arena *arena);
|
||||
MA_API MA_Temp MA_BeginTemp(MA_Arena *arena);
|
||||
MA_API void MA_EndTemp(MA_Temp checkpoint);
|
||||
|
||||
MA_API void MA_PopToPos(MA_Arena *arena, size_t pos);
|
||||
|
||||
@@ -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_Intern name = LC_InternStrLen(package.str, (int)package.len);
|
||||
LC_ASTRefList packages = LC_ParseAndResolve(name);
|
||||
LC_Intern name = LC_InternStrLen(package.str, (int)package.len);
|
||||
LC_ParseAndResolve(name);
|
||||
if (lang->errors) return 1;
|
||||
|
||||
LC_String code = LC_GenerateUnityBuild(packages);
|
||||
LC_String code = LC_GenerateUnityBuild();
|
||||
(void)code;
|
||||
}
|
||||
@@ -31,10 +31,10 @@ int main(int argc, char **argv) {
|
||||
LC_RegisterPackageDir(it->string.str);
|
||||
}
|
||||
|
||||
LC_Intern name = LC_InternStrLen(package.str, (int)package.len);
|
||||
LC_ASTRefList packages = LC_ParseAndResolve(name);
|
||||
LC_Intern name = LC_InternStrLen(package.str, (int)package.len);
|
||||
LC_ParseAndResolve(name);
|
||||
if (lang->errors) return 1;
|
||||
|
||||
LC_String code = LC_GenerateUnityBuild(packages);
|
||||
LC_String code = LC_GenerateUnityBuild();
|
||||
(void)code;
|
||||
}
|
||||
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
|
||||
|
||||
def bindgen_enum(decl):
|
||||
r = ""
|
||||
r += decl["name"] + " :: typedef int;\n"
|
||||
for item in decl["items"]:
|
||||
r += item["name"]
|
||||
@@ -209,7 +210,7 @@ def bindgen_func(decl):
|
||||
if i != len(decl["params"]) - 1 or vargs:
|
||||
r += ", "
|
||||
i += 1
|
||||
if vargs: r += ".."
|
||||
if vargs: r += "..."
|
||||
r += ")"
|
||||
decl_type = decl["type"]
|
||||
return_type = decl_type[:decl_type.index('(')].strip()
|
||||
|
||||
@@ -41,10 +41,10 @@ int main(int argc, char **argv) {
|
||||
LC_RegisterPackageDir(path_to_package.str);
|
||||
S8_For(it, dirs) { LC_RegisterPackageDir(it->string.str); }
|
||||
|
||||
LC_Intern name = LC_InternStrLen(package.str, (int)package.len);
|
||||
LC_ASTRefList packages = LC_ParseAndResolve(name);
|
||||
LC_Intern name = LC_InternStrLen(package.str, (int)package.len);
|
||||
LC_ParseAndResolve(name);
|
||||
if (lang->errors) return 1;
|
||||
|
||||
S8_String code = LC_GenerateUnityBuild(packages);
|
||||
S8_String code = LC_GenerateUnityBuild();
|
||||
OS_WriteFile(S8_Lit("output.c"), code);
|
||||
}
|
||||
Reference in New Issue
Block a user