Refresh the repo

This commit is contained in:
Krzosa Karol
2026-03-20 08:35:18 +01:00
parent 771e9b59b3
commit 6e18bb6641
77 changed files with 27788 additions and 27766 deletions

44
.gitignore vendored
View File

@@ -1,23 +1,23 @@
*.exe *.exe
*.ilk *.ilk
*.pdb *.pdb
*.txt *.txt
*.4c *.4c
*.bin *.bin
*.rdbg *.rdbg
*.out *.out
*.c *.c
*.lib *.lib
*.o *.o
*.10x *.10x
*.obj *.obj
*.exp *.exp
*.dll *.dll
*.sublime-* *.sublime-*
tests/ tests/
backup* backup*
start.bat start.bat
__pycache__ __pycache__
build/examples/arms_race build/examples/arms_race
raylib.py raylib.py

226
README.md
View File

@@ -1,22 +1,43 @@
# The Core Language # The Core Language
A statically typed systems programming language that **you shouldn't use**. Core is an experimental systems programming language and compiler I built as one of my first "full" language projects.
I mark it as complete, it's pretty buggy but I had a lot of fun making it.
Learned a lot about language design and implementation, very worthwhile experience.
If you are intersted in programming languages, checkout bottom of the readme (there are useful resources there!).
The language is usable,
it lacks a macro system/generics for full convenience. It can be combined with C preprocessor
or python but where is fun in that?
Generics seem easy but I wanted something more powerful with compile time tree rewriting capabilities
but thats complicated, I dont have good design for that. :(
It is intentionally kept here as a learning artifact: useful to read, fun to tinker with, and definitely not production-ready.
The basic premise of the language is simplicity and debuggability, ## What this project is
reinforcing already useful ideas from C,C++,Go,Odin,Jai and shaving off round edges.
## Simple drawing to window example - A compiler written in C++
- A language with `.core` source files
- A C code generator backend (Core -> C)
- A small standard-module set in `modules/`
- A collection of examples in `examples/`
``` odin The compiler aims for simple syntax, explicit behavior, and debuggable output.
## Current status
- Archived hobby project / historical snapshot
- Works in many cases, but has known bugs and rough edges
- Best viewed as a language implementation study, not a stable toolchain
- I have made modifications over time and have not recently re-verified a clean build, so the project may not build out of the box
If you are new to compilers, this repo can still be valuable as a real-world "first serious compiler" codebase.
## Language highlights
- Static typing with strict checks
- Untyped compile-time constants (with big-int support in constant evaluation)
- Order-independent declarations
- Modules via `#import`
- Conditional loading (for example OS-specific modules)
- Slices, arrays, structs, unions, enums
- Multiple return values
- Operator overloading
- Runtime type information (`Type`, `GetTypeInfo`, `Any`)
## Tiny syntax taste
```core
#import "Multimedia.core" #import "Multimedia.core"
main :: (): int main :: (): int
@@ -25,118 +46,111 @@ main :: (): int
if Mu.key[Key.Escape].down if Mu.key[Key.Escape].down
Mu.quit = true Mu.quit = true
for y := 0, y < Mu.window.y, y+=1 for y := 0, y < Mu.window.y, y += 1
for x := 0, x < Mu.window.x, x+=1 for x := 0, x < Mu.window.x, x += 1
Mu.screen[x + y*Mu.window.x] = 0xFFFFFF00 Mu.screen[x + y * Mu.window.x] = 0xFFFFFF00
return 0
``` ```
## Features For more examples, see:
* **Debuggers**(Visual Studio, Remedybg) **fully work** with the language, you can step through the program - `examples/language_basics.core`
* **No external dependencies**, you just setup clang and call build.bat - `examples/arrays_and_slices.core`
* Compiles to C code, in the future it will also compile to bytecode and hopefully a raw x64 executable - `examples/operator_overloading.core`
* Very strict Go like type system with untyped literals - `examples/runtime_type_information.core`
* **Order independent declarations**
* Module system
* Tree shaking (unused code is not compiled)
* **Windows and Linux**(only tested on Ubuntu) support
* Conditional compilation
* Runtime type reflection
* Typesafe variadic arguments
* Operator overloading
* Slices
* Multiple return values
## What's missing ? ## Compiler pipeline
- [x] Typechecking - very strict typesystem, inspired by Go, no implicit conversions outside of special types like void or Any. At a high level:
- [x] Constant evaluation and constant folding - Folding and precomputing every expression that can be calculated at compile time.
- [x] Untyped types - Context dependent type assignment of constant expressions, this is a feature I really loved in Go, it makes constants work very well with a very strict type system and it makes errors like overflow of constants in C due to bad size specifier impossible
- [x] Infinite precision integers in constants using big ints! No more overflows or underflows (at least at compile time).
- [x] Module system 1. Lex + parse `.core` source into AST
- [x] Lazy evaluation of modules (unused code is not compiled or typechecked) 2. Resolve symbols and types
- [x] Import module, load project file distinction 3. Generate C code (`generated_main.c`)
- [x] Linking to libraries through importing a module, module calls ```#link``` and that is added to linked libraries. 4. Optionally compile generated C with `clang`
- [x] Order independent declarations - The ordering of functions in code files or modules does not matter, compiler figures all that stuff out for you. "main" can be wherever you want it to be and all functions should be available without problems One design goal was debugger friendliness, so generated C includes line synchronization for stepping through source.
- [x] Synchronize generated C code with original source using line directives so that debuggers work ## Building the compiler
- [x] Fix overshoots when debugger goes to brace in c code
- [x] Expressions ### Windows
- [x] Compounds with named fields and numbered fields
- [x] Functions calls with named arguments
- [x] All the standard binary, unary expressions
- [x] Pointer arithmetic and pointer as array
- [x] Dot access expression needs a redesign because it doesn't handle expressions after the dot, requires identifiers
- [ ] Casting might need a redesign not sure. From '->' to 'cast', and maybe more options like Odin ```transmute```.
- [x] Runtime reflection ```bat
- [x] Package of type and pointer which enables dynamic typing build.bat
- [x] Types are values holding type ids, this way we can do if typeof(value) == S64 ;; blah ```
- [x] Typesafe variadic arguments using []Any slice (no more var args!)
- [x] Any semantics that make it easy to use (automatic unpacking to pointer and type)
- [x] Optional type information dump which allows an application to recursively serialize the data. Something you would need special tools for in C++.
- [ ] Is the design of this correct? That's a lot of data.
- [ ] Builtin data structures This builds the compiler executable in `build/`.
- [x] Arrays
- [x] Slices
- [ ] Dynamic arrays. (Do we want this?)
- [ ] Hash tables. (Do we want this?)
- [x] Multiple return values ### Linux
- [ ] Polymorphism `build_unix.sh` exists, but the repo layout changed over time. If it fails, build manually:
- [x] C like void type
- [x] Dynamic typing using Any and operator overloading
- [ ] Generics aka compile time polymorphism aka parametric polymorphism
- [ ] Something akin to inheritence
- [ ] Something akin to C unions or Rust's enums
- [x] Operator overloading ```bash
- [x] Binary operators clang src/language/core_main.cpp -O0 -Wall -Wno-unused-function -fno-exceptions -fdiagnostics-absolute-paths -g -o core.out
- [x] Unary operators ```
- [x] Bulletproof
- [ ] Assignment expressions?
- [x] Conditional compilation, you can include files based on a pattern: ## Running it
- [x] "$os_multimedia.core" expands to "win32_multimedia.core" or "unix_multimedia.core" depending on the platform.
- [x] Platforms Compile one source file to C:
- [x] Conditional compilation
- [x] Windows
- [x] Fully working
- [x] Multimedia library
- [x] Linux (Only tested on ubuntu)
- [x] Paths
- [x] Reading files
- [x] Listing files
- [x] Virtual memory
- [ ] Multimedia library (maybe using SDL)
- [ ] Language constructs ```bash
- [x] Standard constructs like if, for loop etc. ./core.out examples/language_basics.core
- [ ] Jai like using statement ```
- [ ] Defer statement
- [ ] Unions (or something like unions)
- [ ] Unnamed blocks
## Building or on Windows:
1. Install **Visual Studio** and **Clang** ```bat
1. Run **build.bat** build\main.exe examples\language_basics.core
```
## Resources This produces `generated_main.c`.
Stuff that helped me a lot programming the compiler. Hopefully they also will be helpful to you! Then compile the generated C yourself (example):
* https://bitwise.handmade.network/ - series by Per Vognsen where he actually creates a C like language, very helpful, very hands on! ```bash
* https://hero.handmade.network/episode/code/day206/ - this episode of handmade hero started me on the entire compiler journey a long, long time ago. clang generated_main.c -Wall -Wno-unused-function -Wno-parentheses-equality -g -o a.out
* https://www.youtube.com/watch?v=TH9VCN6UkyQ&list=PLmV5I2fxaiCKfxMBrNsU1kgKJXD3PkyxO - I have rewatched this playlist many this, searching for keywords and ideas. Jonathan Blow's compiler was a big inspiration of mine when learning programming languages. ```
* A Retargetable C Compiler: Design and Implementation by Christopher W. Fraser and David R. Hanson - sometimes looked at this as a reference to figure stuff out. Very helpful resource on compiler construction, the way it's written reads more like documentation but you use what you have.
* https://github.com/JoshuaManton/sif - looked at this as a reference from time to time, author seems like a Jonathan Blow fan so it was a good resource informed by similar resources as I used. There is also a test mode:
* https://github.com/c3lang/c3c - I sometimes looked at C3 compiler as a reference, the author also let me use his big int library he wrote sometime in the past! Thanks a lot!
* https://go.dev/blog/constants - article on golang type system, untyped types, constants that kind of stuff. ```bash
* https://github.com/gingerbill/odin - I sometimes peeked at the compiler to figure stuff out when I was confused about stuff. Also we get a free code indexing and syntax highlighting using odin sublime text plugin ! :D ./core.out -testing
```
which iterates through `examples/` (and `tests/` if present), compiles, and runs them.
## Repository map
- `src/language/` - compiler front/mid/back-end implementation
- `src/base/` - memory, strings, containers, utilities
- `src/os/` - OS abstraction layer (Windows/Linux)
- `modules/` - language modules and platform bindings
- `examples/` - sample Core programs
- `tools/meta.py` - meta tables used to generate token/keyword boilerplate
## Known rough edges
- Project paths changed over time; some scripts may need adjustment
- Windows support is more mature than Linux in some areas
- No polished package manager or full modern tooling around the language
- Feature set is incomplete (for example, no finished generics system)
## Why keep this repo public?
Because complete-but-imperfect projects are useful. This codebase captures:
- early language design decisions
- practical compiler architecture tradeoffs
- how a transpile-to-C strategy can speed up experimentation
If you are building your own language, you may find useful ideas here (and just as many cautionary tales).
## Learning resources that inspired this project
- https://bitwise.handmade.network/
- https://hero.handmade.network/episode/code/day206/
- https://www.youtube.com/watch?v=TH9VCN6UkyQ&list=PLmV5I2fxaiCKfxMBrNsU1kgKJXD3PkyxO
- A Retargetable C Compiler: Design and Implementation (Fraser/Hanson)
- https://github.com/c3lang/c3c
- https://go.dev/blog/constants
- https://github.com/gingerbill/odin

View File

@@ -1,10 +1,14 @@
@echo off @echo off
call "..\misc\compile_setup.bat"
mkdir build
bld --dont_compile_core cd build
cd build
core_main.exe rtsgame/main.core cl ../src/language/core_main.cpp -Zi -nologo -W3 -wd4200 -wd4267 -wd4244 -diagnostics:column -Fe:main.exe user32.lib
rem core_main.exe examples/unions.core
bld --dont_compile_core --link=vendor/raylib/windows/raylibdll.lib cd ..
rem build\generated_main.exe
cd .. rem cd build\pathfind_visualizer
rem call build.bat
rem cd ..\..

View File

@@ -1,249 +0,0 @@
#import "raylib.core"
#import "LibC.core"
A :: #import "array.core"
MAP :: #load "map.core"
sqrtf :: #foreign (value: F32): F32
V2I :: struct
x: int
y: int
ANI_SetTile :: struct
set: bool
p: V2I
t: F32
WinX := 1280
WinY := 720
MouseX := 0
MouseY := 0
MouseP: Vector2
Mode := 0
RectX :: 16
RectY :: 16
Dt: F32
ANI_SetTiles: A.Array(ANI_SetTile)
MouseSelecting := false
MouseSelectionPivot: Vector2
MouseSelectionBox: Rectangle
MouseSelectedActors: A.Array(*MAP.Actor) // @todo: ids
main :: (): int
MAP.Init()
// InitAudioDevice()
// sound := LoadSound("catune - Pass the town, and to the C.mp3")
// SetMasterVolume(0.01)
// PlaySound(sound)
InitWindow(WinX, WinY, "Testing")
SetTargetFPS(60)
orange := ORANGE
orange.a = 255/2
brown := BROWN
brown.a = 255/2
actor_color := DARKGREEN
actor_color.a = 255/2
past_actor_color := BLUE
past_actor_color.a = 255/2
target_color := RED
target_color.a = 255/2
COLOR_SelectionBox := GREEN
COLOR_SelectionBox.a = 255/2
COLOR_Selected := COLOR_SelectionBox
testing := 0
for !WindowShouldClose()
defer ;; testing += 1
WinX = GetScreenWidth()
WinY = GetScreenHeight()
MouseX = GetMouseX()
MouseY = GetMouseY()
MouseP = GetMousePosition()
Dt = GetFrameTime()
map := &MAP.CurrentMap
MouseSelecting = false
if IsMouseButtonDown(MOUSE_BUTTON_LEFT)
MouseSelecting = true
if IsMouseButtonPressed(MOUSE_BUTTON_LEFT)
MouseSelectionPivot = MouseP
MouseSelectionBox = {
MouseSelectionPivot.x,
MouseSelectionPivot.y,
MouseP.x - MouseSelectionPivot.x,
MouseP.y - MouseSelectionPivot.y
}
if MouseSelectionBox.width < 0
MouseSelectionBox.x += MouseSelectionBox.width
MouseSelectionBox.width = -MouseSelectionBox.width
if MouseSelectionBox.height < 0
MouseSelectionBox.y += MouseSelectionBox.height
MouseSelectionBox.height = -MouseSelectionBox.height
if IsKeyPressed(KEY_F1)
Mode = 0
if IsKeyPressed(KEY_F2)
Mode = 1
if IsKeyPressed(KEY_F3)
for i := 0, i < map.actors.len, i += 1
it := map.actors.data + i
MAP.MoveTowardsTarget(it)
MAP.PathFindUpdate(map)
if IsKeyPressed(KEY_F4)
MAP.RandomizeActors()
BeginDrawing()
ClearBackground(RAYWHITE)
map_rectangle := Rectangle{0, 0, map.x->F32 * RectX, map.y->F32 * RectY}
DrawRectangleRec(map_rectangle, LIGHTGRAY)
for x := 0, x < map.x, x += 1
for y := 0, y < map.y, y += 1
it := map.data + (x + y*map.x)
r := Rectangle{x->F32 * RectX, y->F32 * RectY, RectX, RectY}
r2 := Rectangle{r.x + 1, r.y + 1, r.width - 2, r.height - 2}
colliding := CheckCollisionPointRec(MouseP, r)
color := RAYWHITE
if *it == 1 ;; color = GRAY
if Mode == 0
if colliding && IsMouseButtonDown(MOUSE_BUTTON_LEFT)
A.Add(&ANI_SetTiles, {true, {x,y}})
if colliding && IsMouseButtonDown(MOUSE_BUTTON_RIGHT)
A.Add(&ANI_SetTiles, {false, {x,y}})
if colliding == true ;; color = {a = 100}
DrawRectangleRec(r2, color)
for tile_i := 0, tile_i < ANI_SetTiles.len, tile_i += 1
tile_it := ANI_SetTiles.data + tile_i
remove := false
t := tile_it.t
if tile_it.set == false
t = 1 - t
x := tile_it.p.x->F32 * RectX + 1
y := tile_it.p.y->F32 * RectY + 1
w: F32 = (RectX - 2)
h: F32 = (RectY - 2)
wt := w * t
ht := h * t
wd := w - wt
hd := h - ht
r := Rectangle{x + wd/2, y + hd/2, wt, ht}
DrawRectangleRec(r, GRAY)
if tile_it.t > 1
map_tile := map.data + (tile_it.p.x + tile_it.p.y*map.x)
if tile_it.set ;; *map_tile |= MAP.TILE_BLOCKER
else ;; *map_tile &= ~MAP.TILE_BLOCKER
remove = true
tile_it.t += Dt*8
if remove
A.UnorderedRemove(&ANI_SetTiles, tile_it)
tile_i -= 1
for i := 0, i < map.actors.len, i += 1
actor_it := map.actors.data + i
target_r := MAP.Rect(actor_it.target_p)
main_p := MAP.Circle(actor_it.p)
DrawCircleV(main_p, RectX/2, actor_color)
DrawRectangleRec(target_r, target_color)
smaller_the_further: F32 = 0
for tile_i := actor_it.tiles_visited.len - 1, tile_i >= 0, tile_i -= 1
tile_it := actor_it.tiles_visited.data + tile_i
p := MAP.Circle({tile_it.x, tile_it.y})
DrawCircleV(p, RectX/2 - smaller_the_further, past_actor_color)
smaller_the_further += 0.5
for path_i := 0, path_i < actor_it.open_paths.len, path_i += 1
path_it := actor_it.open_paths.data + path_i
path_r := MAP.Rect(path_it.p)
DrawRectangleRec(path_r, orange)
s := TextFormat("%d", sqrtf(path_it.value_to_sort_by->F32)->int)
DrawText(s, path_r.x->int, path_r.y->int, 1, RAYWHITE)
for path_i := 0, path_i < actor_it.close_paths.len, path_i += 1
path_it := actor_it.close_paths.data + path_i
path_r := MAP.Rect(path_it.p)
DrawRectangleRec(path_r, brown)
for path_i := 0, path_i < actor_it.history.len, path_i += 1
path_it := actor_it.history.data + path_i
p0 := MAP.Circle(path_it.came_from)
p1 := MAP.Circle(path_it.p)
DrawLineEx(p0, p1, 5, LIGHTGRAY)
DrawCircleV(p0, 4, LIGHTGRAY)
DrawCircleV(p1, 4, LIGHTGRAY)
if Mode == 1
for actor_i := 0, actor_i < MouseSelectedActors.len, actor_i += 1
actor_it := MouseSelectedActors.data[actor_i]
actor_box := MAP.Rect(actor_it.p)
DrawRectangleRec(actor_box, COLOR_Selected)
if IsMouseButtonPressed(MOUSE_BUTTON_RIGHT)
p := MAP.ScreenToMap(MouseP)
MAP.SetTargetP(actor_it, p)
if MouseSelecting
A.Reset(&MouseSelectedActors)
for actor_i := 0, actor_i < map.actors.len, actor_i += 1
actor_it := map.actors.data + actor_i
actor_box := MAP.Rect(actor_it.p)
if CheckCollisionRecs(actor_box, MouseSelectionBox)
A.Add(&MouseSelectedActors, actor_it)
DrawRectangleRec(MouseSelectionBox, COLOR_SelectionBox)
menu_open := false
if menu_open
text_size := 24
text_p := 4
text_y := WinY - text_size
DrawText("Space :: PathFind", text_p, text_y, text_size, GRAY)
text_y -= text_size
DrawText("F4 :: Randomize actors", text_p, text_y, text_size, GRAY)
text_y -= text_size
DrawText("F3 :: Simulate actors", text_p, text_y, text_size, GRAY)
text_y -= text_size
text: *char = "Mode(F1) :: Block placing"
if Mode == 1 ;; text = "Mode(F2) :: Actor placing"
DrawText(text, text_p, text_y, text_size, GRAY)
text_y -= text_size
EndDrawing()
return 0

View File

@@ -1,213 +0,0 @@
CurrentMap: Map
PATH_SEARCHING :: 0
PATH_REACHED :: 1
PATH_UNREACHABLE :: 2
TILE_BLOCKER :: 1
TILE_ACTOR_IS_STANDING :: 2
Tile :: int
Map :: struct
data: *Tile
x: int
y: int
actors: A.Array(Actor)
Actor :: struct
p: V2I
target_p: V2I
map: *Map
open_paths: A.Array(Path)
close_paths: A.Array(Path)
tiles_visited: A.Array(V2I)
history: A.Array(Path)
Path :: struct
value_to_sort_by: int // distance from target
p: V2I
came_from: V2I
Rect :: (p: V2I): Rectangle
result := Rectangle{p.x->F32 * RectX, p.y->F32 * RectY, RectX, RectY}
return result
Circle :: (p: V2I): Vector2
result := Vector2{p.x->F32 * RectX + RectX/2, p.y->F32 * RectY + RectY/2}
return result
ScreenToMap :: (p: Vector2): V2I
p0 := p.x / RectX
p1 := p.y / RectY
result := V2I{p0->int, p1->int}
return result
AddActor :: (map: *Map, p: V2I): *Actor
A.Add(&map.actors, {p, p, map})
Assert(map.data[p.x + p.y * map.x] == 0)
map.data[p.x + p.y * map.x] |= TILE_ACTOR_IS_STANDING
actor := A.GetLast(&CurrentMap.actors)
return actor
ActorSetP :: (actor: *Actor, p: V2I)
map := actor.map
new_tile := map.data + p.x + p.y * map.x
if *new_tile != 0 ;; return
tile := map.data + actor.p.x + actor.p.y * map.x
Assert((*tile & TILE_ACTOR_IS_STANDING) != 0)
*tile &= ~TILE_ACTOR_IS_STANDING
*new_tile |= TILE_ACTOR_IS_STANDING
actor.p = p
A.Reset(&actor.tiles_visited)
A.Reset(&actor.history)
A.Reset(&actor.open_paths)
A.Reset(&actor.close_paths)
SetTargetP :: (s: *Actor, p: V2I)
s.target_p = p
A.Reset(&s.tiles_visited)
A.Reset(&s.history)
A.Reset(&s.open_paths)
A.Reset(&s.close_paths)
GetRandomP :: (m: *Map): V2I
result: V2I = {GetRandomValue(0, CurrentMap.x - 1), GetRandomValue(0, CurrentMap.y - 1)}
return result
GetRandomUnblockedP :: (m: *Map): V2I
for i := 0, i < 128, i += 1
p := GetRandomP(m)
if m.data[p.x + p.y * m.x] == 0
return p
Assert(false, "Invalid codepath")
return {}
Init :: ()
CurrentMap.x = WinX / RectX
CurrentMap.y = WinY / RectY
bytes := sizeof(Tile) * CurrentMap.x->U64 * CurrentMap.y->U64
CurrentMap.data = malloc(bytes)
memset(CurrentMap.data, 0, bytes)
actor := AddActor(&CurrentMap, GetRandomUnblockedP(&CurrentMap))
actor.target_p = GetRandomUnblockedP(&CurrentMap)
actor2 := AddActor(&CurrentMap, GetRandomUnblockedP(&CurrentMap))
actor2.target_p = GetRandomUnblockedP(&CurrentMap)
RandomizeActors :: ()
map := &CurrentMap
for i := 0, i < map.actors.len, i += 1
it := map.actors.data + i
p := GetRandomUnblockedP(&CurrentMap)
ActorSetP(it, p)
it.target_p = GetRandomUnblockedP(&CurrentMap)
InsertOpenPath :: (s: *Actor, p: V2I, came_from: V2I, ignore_blocks: bool = false)
if p.x < 0 || p.x >= s.map.x ;; return
if p.y < 0 || p.y >= s.map.y ;; return
if ignore_blocks == false && s.map.data[p.x + p.y * s.map.x] != 0 ;; return
for i := 0, i < s.close_paths.len, i += 1
it := s.close_paths.data + i
if it.p.x == p.x && it.p.y == p.y ;; return
for i := 0, i < s.open_paths.len, i += 1
it := s.open_paths.data + i
if it.p.x == p.x && it.p.y == p.y ;; return
dx := s.target_p.x - p.x
dy := s.target_p.y - p.y
d := dx*dx + dy*dy
A.InsertSortedDecreasing(&s.open_paths, {d, p, came_from})
GetCloseP :: (s: *Actor, p: V2I): *Path
for i := 0, i < s.close_paths.len, i += 1
it := s.close_paths.data + i
if it.p.x == p.x && it.p.y == p.y ;; return it
Assert(false, "Invalid codepath")
return 0
RecomputeHistory :: (s: *Actor)
if s.close_paths.len > 1
A.Reset(&s.history)
it := A.GetLast(&s.close_paths)
A.Add(&s.history, *it)
for i := 0,,i += 1
if it.p.x == s.p.x && it.p.y == s.p.y ;; break
if i > 512
A.Reset(&s.history)
break
it = GetCloseP(s, it.came_from)
A.Add(&s.history, *it)
A.Pop(&s.history)
MoveTowardsTarget :: (s: *Actor)
tile := s.map.data + s.p.x + s.p.y * s.map.x
if s.history.len > 0
step := A.Pop(&s.history)
new_tile := s.map.data + step.p.x + step.p.y * s.map.x
if *new_tile == 0
A.Add(&s.tiles_visited, s.p)
s.p = step.p
*tile &= ~TILE_ACTOR_IS_STANDING
*new_tile |= TILE_ACTOR_IS_STANDING
PathFindUpdate :: (map: *Map)
for actor_i := 0, actor_i < map.actors.len, actor_i += 1
s := map.actors.data + actor_i
for i := 0, i < s.history.len, i += 1
it := s.history.data + i
tile := s.map.data[it.p.x + it.p.y * s.map.x]
if tile != 0
A.Reset(&s.open_paths)
A.Reset(&s.close_paths)
A.Reset(&s.history)
break
PathFind(s)
PathFindStep :: (s: *Actor, compute_history: bool = true): bool
if s.open_paths.len == 0
// Reset if we didnt find solution
if s.close_paths.len != 0
last := A.GetLast(&s.close_paths)
reached_target := last.p.x == s.target_p.x && last.p.y == s.target_p.y
if reached_target == false
A.Reset(&s.open_paths)
A.Reset(&s.close_paths)
A.Reset(&s.history)
InsertOpenPath(s, s.p, s.p, ignore_blocks = true)
if s.close_paths.len != 0
last := A.GetLast(&s.close_paths)
reached_target := last.p.x == s.target_p.x && last.p.y == s.target_p.y
if reached_target
return true
it := A.Pop(&s.open_paths)
A.Add(&s.close_paths, it)
for y := -1, y <= 1, y += 1
for x := -1, x <= 1, x += 1
if x == 0 && y == 0 ;; continue
p := V2I{it.p.x + x, it.p.y + y}
InsertOpenPath(s, p, it.p)
if compute_history ;; RecomputeHistory(s)
return false
PathFind :: (s: *Actor)
for i := 0, i < 32, i += 1
done := PathFindStep(s, false)
if done ;; break
RecomputeHistory(s)

View File

@@ -1,3 +1,3 @@
#!/bin/bash #!/bin/bash
clang core_main.cpp -O0 -Wall -Wno-unused-function -fno-exceptions -fdiagnostics-absolute-paths -g -o core.out clang core_main.cpp -O0 -Wall -Wno-unused-function -fno-exceptions -fdiagnostics-absolute-paths -g -o core.out

View File

@@ -1,293 +1,293 @@
/* EXTRA CREDITS (bottom of README.md on github) /* EXTRA CREDITS (bottom of README.md on github)
* https://bitwise.handmade.network/ - series by Per Vognsen where he actually creates a C like language, very helpful, very hands on! * https://bitwise.handmade.network/ - series by Per Vognsen where he actually creates a C like language, very helpful, very hands on!
* https://hero.handmade.network/episode/code/day206/ - this episode of handmade hero started me on the entire compiler journey a long, long time ago. * https://hero.handmade.network/episode/code/day206/ - this episode of handmade hero started me on the entire compiler journey a long, long time ago.
* https://www.youtube.com/watch?v=TH9VCN6UkyQ&list=PLmV5I2fxaiCKfxMBrNsU1kgKJXD3PkyxO - I have rewatched this playlist many this, searching for keywords and ideas. Jonathan Blow's compiler was a big inspiration of mine when learning programming languages. * https://www.youtube.com/watch?v=TH9VCN6UkyQ&list=PLmV5I2fxaiCKfxMBrNsU1kgKJXD3PkyxO - I have rewatched this playlist many this, searching for keywords and ideas. Jonathan Blow's compiler was a big inspiration of mine when learning programming languages.
* A Retargetable C Compiler: Design and Implementation by Christopher W. Fraser and David R. Hanson - sometimes looked at this as a reference to figure stuff out. Very helpful resource on compiler construction, the way it's written reads more like documentation but you use what you have. * A Retargetable C Compiler: Design and Implementation by Christopher W. Fraser and David R. Hanson - sometimes looked at this as a reference to figure stuff out. Very helpful resource on compiler construction, the way it's written reads more like documentation but you use what you have.
* https://github.com/JoshuaManton/sif - looked at this as a reference from time to time, author seems like a Jonathan Blow fan so it was a good resource informed by similar resources as I used. * https://github.com/JoshuaManton/sif - looked at this as a reference from time to time, author seems like a Jonathan Blow fan so it was a good resource informed by similar resources as I used.
* https://github.com/c3lang/c3c - I sometimes looked at C3 compiler as a reference, the author also let me use his big int library he wrote sometime in the past! Thanks a lot! * https://github.com/c3lang/c3c - I sometimes looked at C3 compiler as a reference, the author also let me use his big int library he wrote sometime in the past! Thanks a lot!
* https://go.dev/blog/constants - article on golang type system, untyped types, constants that kind of stuff. * https://go.dev/blog/constants - article on golang type system, untyped types, constants that kind of stuff.
* https://github.com/gingerbill/odin - I sometimes peeked at the compiler to figure stuff out when I was confused about stuff. Also we get a free code indexing and syntax highlighting using odin sublime text plugin ! :D * https://github.com/gingerbill/odin - I sometimes peeked at the compiler to figure stuff out when I was confused about stuff. Also we get a free code indexing and syntax highlighting using odin sublime text plugin ! :D
*/ */
// //
// #1 // #1
// //
// * Inspired by: Per Vognsen(Ion), Jonathan Blow(Jai) // * Inspired by: Per Vognsen(Ion), Jonathan Blow(Jai)
// * Standard programming constructs // * Standard programming constructs
// * No forward declarations needed // * No forward declarations needed
// * Named function arguments // * Named function arguments
// * Enum values are nicely namespaced // * Enum values are nicely namespaced
#import "Multimedia.core" #import "Multimedia.core"
main :: (): int main :: (): int
StartMultimedia(title = "Hello people!") StartMultimedia(title = "Hello people!")
DrawYellowFill() DrawYellowFill()
DrawCoolGradient() DrawCoolGradient()
DrawCircleWithGradient() DrawCircleWithGradient()
AnimateTransmorphingCircle() AnimateTransmorphingCircle()
RaymarchSphere() RaymarchSphere()
DrawYellowFill :: () DrawYellowFill :: ()
for y := 0, y < Mu.window.y, y+=1 for y := 0, y < Mu.window.y, y+=1
for x := 0, x < Mu.window.x, x+=1 for x := 0, x < Mu.window.x, x+=1
Mu.screen[x + y*Mu.window.x] = 0xFFFFFF00 Mu.screen[x + y*Mu.window.x] = 0xFFFFFF00
for UpdateMultimedia() for UpdateMultimedia()
if Mu.key[Key.Escape].down if Mu.key[Key.Escape].down
Mu.key[Key.Escape].down = false Mu.key[Key.Escape].down = false
break break
// //
// #2 // #2
// //
// * Modules // * Modules
// * User names the imports // * User names the imports
// * Aliasing // * Aliasing
// * Operator overloads // * Operator overloads
F :: #import "MathF32.core" F :: #import "MathF32.core"
V3 :: #import "MathVec3.core" V3 :: #import "MathVec3.core"
V2 :: #import "MathVec2.core" V2 :: #import "MathVec2.core"
Vec3 :: V3.Vec3 Vec3 :: V3.Vec3
DrawCoolGradient :: () DrawCoolGradient :: ()
for y := 0, y < Mu.window.y, y+=1 for y := 0, y < Mu.window.y, y+=1
for x := 0, x < Mu.window.x, x+=1 for x := 0, x < Mu.window.x, x+=1
// Normalize to range {0, 1} // Normalize to range {0, 1}
uv := V2.Vec2{x->F32, y->F32} / Mu.window.sizef uv := V2.Vec2{x->F32, y->F32} / Mu.window.sizef
// Move to range {-1, 1} // Move to range {-1, 1}
uv = uv*2->F32 - 1->F32 uv = uv*2->F32 - 1->F32
Assert(uv.x >= -1 && uv.x <= 1) Assert(uv.x >= -1 && uv.x <= 1)
Assert(uv.y >= -1 && uv.y <= 1) Assert(uv.y >= -1 && uv.y <= 1)
color := Vec3{uv.x, uv.y, 1} color := Vec3{uv.x, uv.y, 1}
Mu.screen[x + y*Mu.window.x] = V3.ConvertToARGB(color) Mu.screen[x + y*Mu.window.x] = V3.ConvertToARGB(color)
for UpdateMultimedia() for UpdateMultimedia()
if Mu.key[Key.Escape].down if Mu.key[Key.Escape].down
Mu.key[Key.Escape].down = false Mu.key[Key.Escape].down = false
break break
// //
// #3 // #3
// //
// * The ';;' operator // * The ';;' operator
// * The ';' operator // * The ';' operator
// * Compound expressions, named parameters! // * Compound expressions, named parameters!
DrawCircleWithGradient :: () DrawCircleWithGradient :: ()
default_color := V3.ConvertToARGB({x = 1, y = 1, z = 1}) default_color := V3.ConvertToARGB({x = 1, y = 1, z = 1})
ratio := Mu.window.sizef.x / Mu.window.sizef.y ratio := Mu.window.sizef.x / Mu.window.sizef.y
for y := 0, y < Mu.window.y, y+=1 for y := 0, y < Mu.window.y, y+=1
for x := 0, x < Mu.window.x, x+=1 for x := 0, x < Mu.window.x, x+=1
// Normalize to range {0, 1} // Normalize to range {0, 1}
uv := V2.Vec2{x->F32, y->F32} / Mu.window.sizef uv := V2.Vec2{x->F32, y->F32} / Mu.window.sizef
// Move to range {-1, 1} // Move to range {-1, 1}
uv = uv*2->F32 - 1->F32 uv = uv*2->F32 - 1->F32
uv.x *= ratio uv.x *= ratio
if uv.x*uv.x + uv.y*uv.y < 0.5 if uv.x*uv.x + uv.y*uv.y < 0.5
color := Vec3{uv.x, uv.y, 1} color := Vec3{uv.x, uv.y, 1}
Mu.screen[x + y*Mu.window.x] = V3.ConvertToARGB(color) Mu.screen[x + y*Mu.window.x] = V3.ConvertToARGB(color)
else;; Mu.screen[x + y*Mu.window.x] = default_color else;; Mu.screen[x + y*Mu.window.x] = default_color
for UpdateMultimedia() for UpdateMultimedia()
if Mu.key[Key.Escape].down if Mu.key[Key.Escape].down
Mu.key[Key.Escape].down = false Mu.key[Key.Escape].down = false
break break
// //
// #4 // #4
// //
AnimateTransmorphingCircle :: () AnimateTransmorphingCircle :: ()
for UpdateMultimedia() for UpdateMultimedia()
if Mu.key[Key.Escape].down if Mu.key[Key.Escape].down
Mu.key[Key.Escape].down = false Mu.key[Key.Escape].down = false
break break
default_color := V3.ConvertToARGB({x = 1, y = 1, z = 1}) default_color := V3.ConvertToARGB({x = 1, y = 1, z = 1})
ratio := Mu.window.sizef.x / Mu.window.sizef.y ratio := Mu.window.sizef.x / Mu.window.sizef.y
for y := 0, y < Mu.window.y, y+=1 for y := 0, y < Mu.window.y, y+=1
for x := 0, x < Mu.window.x, x+=1 for x := 0, x < Mu.window.x, x+=1
// Normalize to range {0, 1} // Normalize to range {0, 1}
uv := V2.Vec2{x->F32, y->F32} / Mu.window.sizef uv := V2.Vec2{x->F32, y->F32} / Mu.window.sizef
// Move to range {-1, 1} // Move to range {-1, 1}
uv = uv*2->F32 - 1->F32 uv = uv*2->F32 - 1->F32
uv.x *= ratio uv.x *= ratio
if F.Cos(Mu.time.total->F32)*uv.x*uv.x + F.Sin(Mu.time.total->F32)*uv.y*uv.y < 0.5 if F.Cos(Mu.time.total->F32)*uv.x*uv.x + F.Sin(Mu.time.total->F32)*uv.y*uv.y < 0.5
color := Vec3{uv.x, uv.y, 1} color := Vec3{uv.x, uv.y, 1}
Mu.screen[x + y*Mu.window.x] = V3.ConvertToARGB(color) Mu.screen[x + y*Mu.window.x] = V3.ConvertToARGB(color)
else ;; Mu.screen[x + y*Mu.window.x] = default_color else ;; Mu.screen[x + y*Mu.window.x] = default_color
// //
// #5 // #5
// //
Epsilon :: 0.00001 Epsilon :: 0.00001
SphereSDF :: (pos: Vec3): F32 SphereSDF :: (pos: Vec3): F32
result := V3.Length(pos) - 1.0 result := V3.Length(pos) - 1.0
return result return result
RaymarchSphere :: () RaymarchSphere :: ()
for UpdateMultimedia() for UpdateMultimedia()
if Mu.key[Key.Escape].down if Mu.key[Key.Escape].down
Mu.key[Key.Escape].down = false Mu.key[Key.Escape].down = false
break break
up := Vec3{0, 1, 0} up := Vec3{0, 1, 0}
forward := Vec3{0, 0, -1} forward := Vec3{0, 0, -1}
side := V3.Normalize(V3.Cross(forward, up)) side := V3.Normalize(V3.Cross(forward, up))
LightPos := Vec3{2,4,2} LightPos := Vec3{2,4,2}
LightPos.x = F.Cos(Mu.time.total->F32)*4 LightPos.x = F.Cos(Mu.time.total->F32)*4
LightPos.y = F.Sin(Mu.time.total->F32)*4 LightPos.y = F.Sin(Mu.time.total->F32)*4
ambient_color := Vec3{0.2,0.2,0.2} ambient_color := Vec3{0.2,0.2,0.2}
diffuse_color := Vec3{0.7,0.2,0.2} diffuse_color := Vec3{0.7,0.2,0.2}
eye := Vec3{0, 0, 2} eye := Vec3{0, 0, 2}
light_intensity :: 1.2->F32 light_intensity :: 1.2->F32
Xf := 1 / Mu.window.sizef.x Xf := 1 / Mu.window.sizef.x
Yf := 1 / Mu.window.sizef.y Yf := 1 / Mu.window.sizef.y
ratio := Mu.window.sizef.x / Mu.window.sizef.y ratio := Mu.window.sizef.x / Mu.window.sizef.y
for y := 0, y < Mu.window.y, y+=1 for y := 0, y < Mu.window.y, y+=1
for x := 0, x < Mu.window.x, x+=1 for x := 0, x < Mu.window.x, x+=1
uv := Vec3{x->F32 * Xf * 2 - 1, y->F32 * Yf * 2 - 1, 1.0} uv := Vec3{x->F32 * Xf * 2 - 1, y->F32 * Yf * 2 - 1, 1.0}
uv.x *= ratio uv.x *= ratio
dir := V3.Normalize(Vec3{V3.Dot(side, uv), V3.Dot(up, uv), V3.Dot(forward, uv)}) dir := V3.Normalize(Vec3{V3.Dot(side, uv), V3.Dot(up, uv), V3.Dot(forward, uv)})
t: F32 t: F32
end: F32 = 100.0 end: F32 = 100.0
hit := true hit := true
p: Vec3 p: Vec3
for i := 0, i < 255, i+=1 for i := 0, i < 255, i+=1
p = eye + dir*t p = eye + dir*t
distance := SphereSDF(p) distance := SphereSDF(p)
if distance < Epsilon if distance < Epsilon
break break
t += distance t += distance
if distance >= end if distance >= end
hit = false hit = false
break break
if hit if hit
normal := V3.Normalize(Vec3{ normal := V3.Normalize(Vec3{
SphereSDF({p.x + Epsilon, p.y, p.z}) - SphereSDF({p.x - Epsilon, p.y, p.z}), SphereSDF({p.x + Epsilon, p.y, p.z}) - SphereSDF({p.x - Epsilon, p.y, p.z}),
SphereSDF({p.x, p.y + Epsilon, p.z}) - SphereSDF({p.x, p.y - Epsilon, p.z}), SphereSDF({p.x, p.y + Epsilon, p.z}) - SphereSDF({p.x, p.y - Epsilon, p.z}),
SphereSDF({p.x, p.y, p.z + Epsilon}) - SphereSDF({p.x, p.y, p.z - Epsilon}), SphereSDF({p.x, p.y, p.z + Epsilon}) - SphereSDF({p.x, p.y, p.z - Epsilon}),
}) })
light_to_point := V3.Normalize(LightPos - p) light_to_point := V3.Normalize(LightPos - p)
ambient :: 0.2->F32 ambient :: 0.2->F32
diffuse := V3.Dot(normal, light_to_point) diffuse := V3.Dot(normal, light_to_point)
color := ambient_color*ambient->F32 color := ambient_color*ambient->F32
if diffuse > Epsilon if diffuse > Epsilon
color = color + diffuse_color*diffuse color = color + diffuse_color*diffuse
color = color * light_intensity color = color * light_intensity
// Gamma correction // Gamma correction
color.x = F.SquareRoot(color.x) color.x = F.SquareRoot(color.x)
color.y = F.SquareRoot(color.y) color.y = F.SquareRoot(color.y)
color.z = F.SquareRoot(color.z) color.z = F.SquareRoot(color.z)
Mu.screen[x + y*Mu.window.x] = V3.ConvertToARGB(color) Mu.screen[x + y*Mu.window.x] = V3.ConvertToARGB(color)
else;; Mu.screen[x + y*Mu.window.x] = 0 else;; Mu.screen[x + y*Mu.window.x] = 0

View File

@@ -1,98 +1,98 @@
VariadicArguments :: (string: *char, args: []Any): Any VariadicArguments :: (string: *char, args: []Any): Any
return args[0] return args[0]
AnyArguments :: (values: []Any) AnyArguments :: (values: []Any)
for values for values
Assert(it.type == int) Assert(it.type == int)
Assert(*(values[0].data->*int) == 10) Assert(*(values[0].data->*int) == 10)
Assert(*(values[1].data->*int) == 20) Assert(*(values[1].data->*int) == 20)
/** /**
* C++ version 0.4 char* style "itoa": * C++ version 0.4 char* style "itoa":
* Written by Lukás Chmela * Written by Lukás Chmela
* Released under GPLv3. * Released under GPLv3.
*/ */
IntegerToString :: (value: int, result: *U8, base: int): *U8 IntegerToString :: (value: int, result: *U8, base: int): *U8
// check that the base if valid // check that the base if valid
if (base < 2) || (base > 36) if (base < 2) || (base > 36)
*result = 0 // ' *result = 0 // '
return result return result
ptr := result ptr := result
ptr1 := result ptr1 := result
tmp_char: U8 tmp_char: U8
tmp_value: int tmp_value: int
str := "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" str := "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"
for value != 0 for value != 0
tmp_value = value tmp_value = value
value /= base value /= base
*ptr++ = str[35 + (tmp_value - value * base)] *ptr++ = str[35 + (tmp_value - value * base)]
// Apply negative sign // Apply negative sign
if tmp_value < 0 if tmp_value < 0
*ptr++ = '-' *ptr++ = '-'
*ptr-- = 0 *ptr-- = 0
for ptr1 < ptr for ptr1 < ptr
tmp_char = *ptr tmp_char = *ptr
*ptr-- = *ptr1 *ptr-- = *ptr1
*ptr1++ = tmp_char *ptr1++ = tmp_char
return result return result
StringToDouble :: (s: String): F64 StringToDouble :: (s: String): F64
sign: F64 = 1.0 sign: F64 = 1.0
i := 0 i := 0
if s[i] == '-' if s[i] == '-'
sign = -1 sign = -1
i += 1 i += 1
elif s[i] == '+' elif s[i] == '+'
i += 1 i += 1
for , i < Len(s), i+= 1 for , i < Len(s), i+= 1
pass // BACKUP pass // BACKUP
return 0 return 0
FormatString :: (buffer: *U8, buffer_len: U64, string: String, args: []Any) FormatString :: (buffer: *U8, buffer_len: U64, string: String, args: []Any)
// @todo(krzosa): Add consideration of buffer SIZE! Add some function to handle this OutStr or something // @todo(krzosa): Add consideration of buffer SIZE! Add some function to handle this OutStr or something
arg_counter := 0 arg_counter := 0
out_buffer_len := 0 out_buffer_len := 0
for i := 0, i < Len(string), i+=1 for i := 0, i < Len(string), i+=1
if string[i] == '%' if string[i] == '%'
Assert(arg_counter < Len(args), "Passed too many [%] to the string formating function") Assert(arg_counter < Len(args), "Passed too many [%] to the string formating function")
arg := args[arg_counter++] arg := args[arg_counter++]
if arg.type == int if arg.type == int
value := *(arg.data->*int) value := *(arg.data->*int)
itoa_buff: [64]U8 itoa_buff: [64]U8
p := IntegerToString(value, &itoa_buff[0], 10) p := IntegerToString(value, &itoa_buff[0], 10)
for *p != 0 for *p != 0
buffer[out_buffer_len++] = *p++ buffer[out_buffer_len++] = *p++
else;; Assert(false) else;; Assert(false)
else else
buffer[out_buffer_len++] = string[i] buffer[out_buffer_len++] = string[i]
main :: (): int main :: (): int
a := 10 a := 10
b := 20 b := 20
values := []Any{a, b} values := []Any{a, b}
for values for values
Assert(it.type == int) Assert(it.type == int)
AnyArguments({a,b}) AnyArguments({a,b})
c := VariadicArguments("Test", args = {a+b,b}) c := VariadicArguments("Test", args = {a+b,b})
Assert(*(c.data->*int) == 30) Assert(*(c.data->*int) == 30)
d := VariadicArguments("Test", {b,a}) d := VariadicArguments("Test", {b,a})
Assert(*(d.data->*int) == b) Assert(*(d.data->*int) == b)
Assert(*(values[0].data->*int) == 10) Assert(*(values[0].data->*int) == 10)
Assert(*(values[1].data->*int) == 20) Assert(*(values[1].data->*int) == 20)
buf: [128]U8 buf: [128]U8
FormatString(&buf[0], Len(buf), "Test % %", {32, 156}) FormatString(&buf[0], Len(buf), "Test % %", {32, 156})
return 0 return 0

View File

@@ -1,55 +1,55 @@
/* /*
Static arrays are exactly like c arrays, difference is Static arrays are exactly like c arrays, difference is
we can easily then get a slice of that array. we can easily then get a slice of that array.
Slices are static arrays + length, they simplify array handling. Slices are static arrays + length, they simplify array handling.
This allows us to pass an array into a function easily, then that function This allows us to pass an array into a function easily, then that function
can still access that length information easily. can still access that length information easily.
Passing a pointer to array + length is a common pattern in C. So it would Passing a pointer to array + length is a common pattern in C. So it would
be nice if handling of that was simplified. be nice if handling of that was simplified.
*/ */
main :: (): int main :: (): int
static_array: [8]int static_array: [8]int
// We can get size of array using Length builtin // We can get size of array using Length builtin
#Assert(Len(static_array) == 8) #Assert(Len(static_array) == 8)
// Accessing values is like in C // Accessing values is like in C
// Variables are zeroed by default // Variables are zeroed by default
Assert(static_array[1] == 0) Assert(static_array[1] == 0)
element2 := static_array[2] element2 := static_array[2]
element0: int = static_array[0] element0: int = static_array[0]
Assert(element0 == 0 && element2 == 0) Assert(element0 == 0 && element2 == 0)
// We can loop through arrays // We can loop through arrays
// this implicitly defines 'it' variable // this implicitly defines 'it' variable
for static_array for static_array
*it = 1 *it = 1
// We set all variables to 1 so // We set all variables to 1 so
Assert(static_array[6] == 1) Assert(static_array[6] == 1)
// This is how slice is defined, no [] index in between brackets // This is how slice is defined, no [] index in between brackets
// slice is array pointer + length // slice is array pointer + length
// Other then that it works exactly like regular array // Other then that it works exactly like regular array
slice: []int = static_array slice: []int = static_array
// We can't do a compile time Assert anymore // We can't do a compile time Assert anymore
Assert(Len(slice) == 8) Assert(Len(slice) == 8)
Assert(slice[4] == 1) Assert(slice[4] == 1)
// After we loop and reassign slice values // After we loop and reassign slice values
// old static_array gets changed // old static_array gets changed
// //
// In this example, operator ';;' is used // In this example, operator ';;' is used
// it inserts a new line, allows to write this // it inserts a new line, allows to write this
// example in a single line // example in a single line
for slice;; *it = 2 for slice;; *it = 2
Assert(static_array[2] == 2) Assert(static_array[2] == 2)
return 0 return 0

View File

@@ -1,40 +1,40 @@
// We can bind module to a name // We can bind module to a name
M :: #import "Multimedia.core" M :: #import "Multimedia.core"
// You can bind struct to a name // You can bind struct to a name
MU :: M.MU MU :: M.MU
// We can bind a lambda to a name // We can bind a lambda to a name
Start :: M.StartMultimedia Start :: M.StartMultimedia
Update :: M.UpdateMultimedia Update :: M.UpdateMultimedia
// Other example of binding a lambda to a name // Other example of binding a lambda to a name
SomeOtherLambda :: () ;; pass SomeOtherLambda :: () ;; pass
AliasOf :: SomeOtherLambda AliasOf :: SomeOtherLambda
// We can bind a simple type to name, this type is // We can bind a simple type to name, this type is
// exactly the same as int, typechecker doesn't complain // exactly the same as int, typechecker doesn't complain
NewInt :: int NewInt :: int
// We can force it to complain using a '#strict' directive // We can force it to complain using a '#strict' directive
// this makes a new type that requires casting, good for ids // this makes a new type that requires casting, good for ids
// and stuff like that, normal int operations still work! // and stuff like that, normal int operations still work!
StrictInt :: #strict int StrictInt :: #strict int
SomeStruct :: struct ;; a: int SomeStruct :: struct ;; a: int
StructAlias :: SomeStruct StructAlias :: SomeStruct
main :: (): int main :: (): int
some_struct: SomeStruct = {a = 10} some_struct: SomeStruct = {a = 10}
struct_alias: StructAlias = some_struct struct_alias: StructAlias = some_struct
Assert(struct_alias.a == 10) Assert(struct_alias.a == 10)
#Assert(SomeStruct == StructAlias) #Assert(SomeStruct == StructAlias)
#Assert(NewInt == int) #Assert(NewInt == int)
#Assert(StrictInt != int) #Assert(StrictInt != int)
Start(x = 1280, y = 720) Start(x = 1280, y = 720)
Update() Update()
return 0 return 0

View File

@@ -1,76 +1,76 @@
#import "Base.core" #import "Base.core"
#import "Arena.core" #import "Arena.core"
#import "KERNEL32.core" #import "KERNEL32.core"
#import "GDI32.core" #import "GDI32.core"
#import "USER32.core" #import "USER32.core"
WinMain :: (hInstance: HINSTANCE, hPrevInstance: HINSTANCE, lpCmdLine: LPSTR, nShowCmd: int): int WinMain :: (hInstance: HINSTANCE, hPrevInstance: HINSTANCE, lpCmdLine: LPSTR, nShowCmd: int): int
screen_size_x: int = 1280 screen_size_x: int = 1280
screen_size_y: int = 720 screen_size_y: int = 720
arena: Arena arena: Arena
window_name := StringToString16(&arena, "Have a wonderful day!") window_name := StringToString16(&arena, "Have a wonderful day!")
w := WNDCLASSW{ w := WNDCLASSW{
lpfnWndProc = WindowProc, lpfnWndProc = WindowProc,
hInstance = hInstance, hInstance = hInstance,
lpszClassName = window_name.str, lpszClassName = window_name.str,
} }
Assert(RegisterClassW(&w) != 0) Assert(RegisterClassW(&w) != 0)
window := CreateWindowExW( window := CreateWindowExW(
dwExStyle = 0, hWndParent = 0, hMenu = 0, lpParam = 0, dwExStyle = 0, hWndParent = 0, hMenu = 0, lpParam = 0,
X = CW_USEDEFAULT, Y = CW_USEDEFAULT, nWidth = screen_size_x, nHeight = screen_size_y, X = CW_USEDEFAULT, Y = CW_USEDEFAULT, nWidth = screen_size_x, nHeight = screen_size_y,
lpClassName = window_name.str, lpClassName = window_name.str,
lpWindowName = window_name.str, lpWindowName = window_name.str,
dwStyle = WS_OVERLAPPEDWINDOW, dwStyle = WS_OVERLAPPEDWINDOW,
hInstance = hInstance hInstance = hInstance
) )
Assert(window != 0) Assert(window != 0)
ShowWindow(window, nShowCmd) ShowWindow(window, nShowCmd)
window_dc := GetDC(window) window_dc := GetDC(window)
header_size: U32 = sizeof(BITMAPINFOHEADER) header_size: U32 = sizeof(BITMAPINFOHEADER)
Assert(header_size == 40) Assert(header_size == 40)
bminfo := BITMAPINFO{ bminfo := BITMAPINFO{
BITMAPINFOHEADER{ BITMAPINFOHEADER{
biSize = header_size, biSize = header_size,
biWidth = screen_size_x->LONG, biWidth = screen_size_x->LONG,
biHeight = screen_size_y->LONG, biHeight = screen_size_y->LONG,
biPlanes = 1, biPlanes = 1,
biBitCount = 32, biBitCount = 32,
biCompression = BI_RGB, biCompression = BI_RGB,
biXPelsPerMeter = 1, biXPelsPerMeter = 1,
biYPelsPerMeter = 1, biYPelsPerMeter = 1,
} }
} }
pixels: *U32 pixels: *U32
bitmap_dib := CreateDIBSection(window_dc, &bminfo, DIB_RGB_COLORS, (&pixels)->**void, 0, 0) bitmap_dib := CreateDIBSection(window_dc, &bminfo, DIB_RGB_COLORS, (&pixels)->**void, 0, 0)
bitmap_hdc := CreateCompatibleDC(window_dc) bitmap_hdc := CreateCompatibleDC(window_dc)
for AppIsRunning for AppIsRunning
msg: MSG msg: MSG
for PeekMessageW(&msg, window, 0, 0, PM_REMOVE) > 0 for PeekMessageW(&msg, window, 0, 0, PM_REMOVE) > 0
TranslateMessage(&msg) TranslateMessage(&msg)
DispatchMessageW(&msg) DispatchMessageW(&msg)
for y := 0->int, y < screen_size_y, y+=1 for y := 0->int, y < screen_size_y, y+=1
for x := 0->int, x < screen_size_x, x+=1 for x := 0->int, x < screen_size_x, x+=1
pixels[x + y*screen_size_x] = 0xFFFF0000 pixels[x + y*screen_size_x] = 0xFFFF0000
SelectObject(bitmap_hdc, bitmap_dib) SelectObject(bitmap_hdc, bitmap_dib)
BitBlt(window_dc, 0, 0, screen_size_x, screen_size_y, bitmap_hdc, 0, 0, SRCCOPY) BitBlt(window_dc, 0, 0, screen_size_x, screen_size_y, bitmap_hdc, 0, 0, SRCCOPY)
Sleep(100) Sleep(100)
if CStringCompare(lpCmdLine, "testing") if CStringCompare(lpCmdLine, "testing")
return 0 return 0
return 0 return 0
AppIsRunning := true AppIsRunning := true
WindowProc :: (hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM): LRESULT WindowProc :: (hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM): LRESULT
if msg == WM_DESTROY if msg == WM_DESTROY
PostQuitMessage(0) PostQuitMessage(0)
AppIsRunning = false AppIsRunning = false
return 0 return 0
else;; return DefWindowProcW(hwnd, msg, wparam, lparam) else;; return DefWindowProcW(hwnd, msg, wparam, lparam)

View File

@@ -1,55 +1,55 @@
/* /*
Language enables implementing dynamic typing using operator overloads and Language enables implementing dynamic typing using operator overloads and
the Any type. Any type is a bundle of typeid and a pointer to value. the Any type. Any type is a bundle of typeid and a pointer to value.
Current semantics of the Any dictate that values that get assigned to Current semantics of the Any dictate that values that get assigned to
Any values, they get implicitly converted to a pointer and a type. Any values, they get implicitly converted to a pointer and a type.
a: Any = 10 // This sentence allocates 10 on the stack a: Any = 10 // This sentence allocates 10 on the stack
a: Any = a + 10 // This also allocates on stack a: Any = a + 10 // This also allocates on stack
a: Any = a // Does not allocate, takes pointer to a a: Any = a // Does not allocate, takes pointer to a
a: Any = array[1] // Does not allocate, takes pointer to value in array a: Any = array[1] // Does not allocate, takes pointer to value in array
The general picture you can take from this is that if we are referencing The general picture you can take from this is that if we are referencing
something it will take a pointer to it. something it will take a pointer to it.
If the operation results in a new value it will allocate the result on stack If the operation results in a new value it will allocate the result on stack
and make a pointer out of it. Have to be mindful of the lifetime. and make a pointer out of it. Have to be mindful of the lifetime.
*/ */
storage: [32]int storage: [32]int
len : int len : int
"+" :: (a: Any, b: Any): Any "+" :: (a: Any, b: Any): Any
result: Any = storage[len++] result: Any = storage[len++]
if a.type == int && b.type == int if a.type == int && b.type == int
*(result.data->*int) = *(a.data->*int) + *(b.data->*int) *(result.data->*int) = *(a.data->*int) + *(b.data->*int)
return result return result
"+" :: (a: Any, b: int): Any "+" :: (a: Any, b: int): Any
result: Any = storage[len++] result: Any = storage[len++]
if a.type == int if a.type == int
*(result.data->*int) = *(a.data->*int) + b *(result.data->*int) = *(a.data->*int) + b
return result return result
"==" :: (a: Any, b: int): bool "==" :: (a: Any, b: int): bool
result := false result := false
if a.type == int if a.type == int
result = *(a.data->*int) == b result = *(a.data->*int) == b
return result return result
"==" :: (a: Any, b: Any): bool "==" :: (a: Any, b: Any): bool
result := false result := false
if a.type == int && b.type == int if a.type == int && b.type == int
result = *(a.data->*int) == *(b.data->*int) result = *(a.data->*int) == *(b.data->*int)
return result return result
main :: (): int main :: (): int
a: Any = 10 a: Any = 10
b: Any = 20 b: Any = 20
c := a + b c := a + b
Assert(c.type == int && c == 30) Assert(c.type == int && c == 30)
Assert(a+b+a==c+(5+5)) Assert(a+b+a==c+(5+5))
return 0 return 0

View File

@@ -1,103 +1,103 @@
main :: (): int main :: (): int
// Language has a bunch of standard builtin types: // Language has a bunch of standard builtin types:
// Signed integer types // Signed integer types
s64val: S64 = 0 s64val: S64 = 0
s32val: S32 = 0 s32val: S32 = 0
s16val: S16 = 0 s16val: S16 = 0
s8val : S8 = 0 s8val : S8 = 0
intval: int = 0 intval: int = 0
// Unsigned integer types = U64, U32, U16, U8, // Unsigned integer types = U64, U32, U16, U8,
u64val: U64 = 0 u64val: U64 = 0
u32val: U32 = 0 u32val: U32 = 0
u16val: U16 = 0 u16val: U16 = 0
u8val : U8 = 0 u8val : U8 = 0
// Floating point types = F64, F32 // Floating point types = F64, F32
f64val: F64 = 0 f64val: F64 = 0
f32val: F32 = 0 f32val: F32 = 0
// String type = String // String type = String
string_val: String = "String type" string_val: String = "String type"
cstring_val: *char = "CString type" cstring_val: *char = "CString type"
// This is how we can assign variables // This is how we can assign variables
// There is no need for prefixes, compiler figures // There is no need for prefixes, compiler figures
// out the format by itself // out the format by itself
signed_variable: S32 = 10 signed_variable: S32 = 10
unsigned_variable: U32 = 10 unsigned_variable: U32 = 10
// We can also tell the compiler to infer the type // We can also tell the compiler to infer the type
this_is_s64_by_default := 10 this_is_s64_by_default := 10
this_is_f32_by_default := 10.1251 this_is_f32_by_default := 10.1251
this_is_string_by_default := "Thing" this_is_string_by_default := "Thing"
// Reassigning values is exactly like in other languages // Reassigning values is exactly like in other languages
this_is_s64_by_default = 20 this_is_s64_by_default = 20
this_is_string_by_default = "Other_Thing" this_is_string_by_default = "Other_Thing"
this_is_f32_by_default = 15.1255 this_is_f32_by_default = 15.1255
// @todo: Add type_of operator!!! // @todo: Add type_of operator!!!
// Assert(type_of(this_is_string_by_default) == String) // Assert(type_of(this_is_string_by_default) == String)
// Assert(type_of(this_is_s64_by_default) == S64) // Assert(type_of(this_is_s64_by_default) == S64)
// There are also constant bindings in the language. // There are also constant bindings in the language.
// You can bind all sorts of constants to names this way. // You can bind all sorts of constants to names this way.
INT_VALUE :: 10 INT_VALUE :: 10
FLOAT_VALUE :: 124.125 FLOAT_VALUE :: 124.125
// For constants we can mix and match different types // For constants we can mix and match different types
COMBINE_VALUE :: INT_VALUE + FLOAT_VALUE COMBINE_VALUE :: INT_VALUE + FLOAT_VALUE
// When it comes to runtime variables it's a bit different // When it comes to runtime variables it's a bit different
// To do this we need a cast // To do this we need a cast
combining_types := this_is_s64_by_default->F32 + this_is_f32_by_default combining_types := this_is_s64_by_default->F32 + this_is_f32_by_default
// Compound statements // Compound statements
// Struct is at the bottom of the file! // Struct is at the bottom of the file!
data1 := Data{ data1 := Data{
a = 1, a = 1,
d = 2 d = 2
} }
data2: Data = { data2: Data = {
a = 4, a = 4,
b = 2, b = 2,
} }
size0 := sizeof(Data) size0 := sizeof(Data)
size1 := sizeof(data1) size1 := sizeof(data1)
align0 := alignof(Data) align0 := alignof(Data)
align1 := alignof(data1) align1 := alignof(data1)
type0 := typeof(Data) type0 := typeof(Data)
type1 := typeof(data1) type1 := typeof(data1)
Assert(s64val == 0 && s32val == 0 && s16val == 0 && s8val == 0 && intval == 0 && u64val == 0 && u32val == 0 && u16val == 0 && u8val == 0 && f64val == 0 && f32val == 0) Assert(s64val == 0 && s32val == 0 && s16val == 0 && s8val == 0 && intval == 0 && u64val == 0 && u32val == 0 && u16val == 0 && u8val == 0 && f64val == 0 && f32val == 0)
Assert(string_val[0] == 'S') Assert(string_val[0] == 'S')
Assert(cstring_val[0] == 'C') Assert(cstring_val[0] == 'C')
Assert(signed_variable == 10 && unsigned_variable == 10) Assert(signed_variable == 10 && unsigned_variable == 10)
Assert(INT_VALUE == 10) Assert(INT_VALUE == 10)
Assert(FLOAT_VALUE == 124.125) Assert(FLOAT_VALUE == 124.125)
Assert(this_is_f32_by_default == 15.1255) Assert(this_is_f32_by_default == 15.1255)
Assert(combining_types == 15.1255 + 20) Assert(combining_types == 15.1255 + 20)
Assert(data1.a == 1) Assert(data1.a == 1)
Assert(data1.b == 0) Assert(data1.b == 0)
Assert(data1.c == 0) Assert(data1.c == 0)
Assert(data1.d == 2) Assert(data1.d == 2)
Assert(data2.a == 4) Assert(data2.a == 4)
Assert(data2.b == 2) Assert(data2.b == 2)
Assert(data2.c == 0) Assert(data2.c == 0)
Assert(data2.d == 0) Assert(data2.d == 0)
Assert(size0 == size1) Assert(size0 == size1)
Assert(align0 == align1) Assert(align0 == align1)
Assert(type0 == type1) Assert(type0 == type1)
Assert(typeof(data2) == Data) Assert(typeof(data2) == Data)
return 0 return 0
Data :: struct Data :: struct
a: S64 a: S64
b: S32 b: S32
c: S32 c: S32
d: S32 d: S32

View File

@@ -1,26 +1,26 @@
Vec3 :: struct;; x: F32; y: F32; z: F32 Vec3 :: struct;; x: F32; y: F32; z: F32
// We can define operator overloads for arbitrary types // We can define operator overloads for arbitrary types
// these are just regular lambdas/functions // these are just regular lambdas/functions
"+" :: (a: Vec3, b: Vec3): Vec3 "+" :: (a: Vec3, b: Vec3): Vec3
return {a.x+b.x, a.y+b.y, a.z+b.z} return {a.x+b.x, a.y+b.y, a.z+b.z}
// We can make a one liner out of these using ';;' operator // We can make a one liner out of these using ';;' operator
// which functions as a new line with indent // which functions as a new line with indent
"-" :: (a: Vec3, b: Vec3): Vec3 ;; return {a.x-b.x, a.y-b.y, a.z-b.z} "-" :: (a: Vec3, b: Vec3): Vec3 ;; return {a.x-b.x, a.y-b.y, a.z-b.z}
"-" :: (a: Vec3): Vec3 ;; return {-a.x, -a.y, -a.z} "-" :: (a: Vec3): Vec3 ;; return {-a.x, -a.y, -a.z}
main :: (): int main :: (): int
a := Vec3{1,1,1} a := Vec3{1,1,1}
b := Vec3{2,3,4} b := Vec3{2,3,4}
// The expressions are replaced with the defined lambdas // The expressions are replaced with the defined lambdas
c := a + b c := a + b
Assert(c.x == 3 && c.y == 4 && c.z == 5) Assert(c.x == 3 && c.y == 4 && c.z == 5)
d := -c d := -c
Assert(d.x == -3 && d.y == -4 && d.z == -5) Assert(d.x == -3 && d.y == -4 && d.z == -5)
e := c - d e := c - d
Assert(e.x == 6 && e.y == 8 && e.z == 10) Assert(e.x == 6 && e.y == 8 && e.z == 10)
return 0 return 0

View File

@@ -1,74 +1,74 @@
/* /*
Biggest problems with C/C++ are the header files and the fact that Biggest problems with C/C++ are the header files and the fact that
top level declarations are required to be ordered. top level declarations are required to be ordered.
In C++ you simply cannot write code like this: In C++ you simply cannot write code like this:
struct Asset{ struct Asset{
Asset_Tag asset_tag; Asset_Tag asset_tag;
}; };
enum Asset_Tag{ enum Asset_Tag{
ASSET_SOUND, ASSET_SOUND,
ASSET_IMAGE, ASSET_IMAGE,
}; };
Even though it makes more sense to do that, I would rather first learn Even though it makes more sense to do that, I would rather first learn
about what Asset is rather then what tags it can have. C/C++ force on you about what Asset is rather then what tags it can have. C/C++ force on you
an order of declarations that doesn't match what you have in your head. an order of declarations that doesn't match what you have in your head.
The next problem are the header files. Frequently on top of writing code, The next problem are the header files. Frequently on top of writing code,
in C/C++ there is a need to maintain a header file. Header files contain in C/C++ there is a need to maintain a header file. Header files contain
all the forward declarations of the functions that you are implementing. all the forward declarations of the functions that you are implementing.
Problem with this is that if you are changing something, potentially Problem with this is that if you are changing something, potentially
you now need to change that in multiple places. It would be nice if I could you now need to change that in multiple places. It would be nice if I could
write a module that doesn't yet have any concrete spec but the functions write a module that doesn't yet have any concrete spec but the functions
are available everywhere, immediately. On top of that those functions would are available everywhere, immediately. On top of that those functions would
be nicely localized in a single file without thinking about what depends be nicely localized in a single file without thinking about what depends
on what, how to fit it in the stack of includes etc. It would be just nice on what, how to fit it in the stack of includes etc. It would be just nice
to tell the compiler to solve all those issues for us. to tell the compiler to solve all those issues for us.
*/ */
// We can have main at the top level, this is something // We can have main at the top level, this is something
// that is sometimes pretty tricky in C++ // that is sometimes pretty tricky in C++
main :: (): int main :: (): int
// Even though Asset is beneath main, this still works // Even though Asset is beneath main, this still works
// this feature is even nicer when we think about modules etc. // this feature is even nicer when we think about modules etc.
asset1 := make_sound() asset1 := make_sound()
asset2 := make_sound() asset2 := make_sound()
asset1.next_asset = &asset2 asset1.next_asset = &asset2
return 0 return 0
// @todo: This does not work // @todo: This does not work
// asset := []Asset{make_sound(), make_sound()} // asset := []Asset{make_sound(), make_sound()}
// asset[0].next_sound = &asset[1] // asset[0].next_sound = &asset[1]
// Recursion is a pain point for this kinds of algorithms // Recursion is a pain point for this kinds of algorithms
// As can be seen here it works very nicely // As can be seen here it works very nicely
make_sound :: (should_exit_recursion: bool = false): Asset make_sound :: (should_exit_recursion: bool = false): Asset
if should_exit_recursion == true if should_exit_recursion == true
asset: Asset asset: Asset
asset.tag = Asset_Tag.Sound asset.tag = Asset_Tag.Sound
return asset return asset
return make_sound(true) return make_sound(true)
Asset :: struct Asset :: struct
tag: Asset_Tag tag: Asset_Tag
// Pointers to self work as expected // Pointers to self work as expected
// this is always a pain point for these kinds of // this is always a pain point for these kinds of
// algorithms // algorithms
next_asset: *Asset next_asset: *Asset
// enum #flag assigns default values differently from normal enums. // enum #flag assigns default values differently from normal enums.
// It assigns a unique bit of a value to each enumeration. // It assigns a unique bit of a value to each enumeration.
// Default values go: 1, 2, 4, 8, 16, 32, 64 // Default values go: 1, 2, 4, 8, 16, 32, 64
Asset_Tag :: enum #flag Asset_Tag :: enum #flag
Sound Sound
Image Image
Text Text

Submodule examples/pathfind_visualizer added at caff4aaa2e

View File

@@ -1,92 +1,92 @@
/* @todo /* @todo
QueueAddSLL(list: $List, node: $Node, $first = first, $last = last, $next = next) QueueAddSLL(list: $List, node: $Node, $first = first, $last = last, $next = next)
if list.first == 0 if list.first == 0
list.first = list.last = node list.first = list.last = node
else else
list.last = list.last.next = node list.last = list.last.next = node
*/ */
Array :: struct($T: Type) Array :: struct($T: Type)
data: *T data: *T
len: int len: int
cap: int cap: int
Tuple :: struct($A: Type, $B: Type) Tuple :: struct($A: Type, $B: Type)
a: A a: A
b: B b: B
Triple :: struct($A: Type, $B: Type, $C: Type) Triple :: struct($A: Type, $B: Type, $C: Type)
a: A a: A
b: B b: B
c: C c: C
Variant :: union($A: Type, $B: Type, $C: Type) Variant :: union($A: Type, $B: Type, $C: Type)
a: A a: A
b: B b: B
c: C c: C
MakeArray :: (a: *int, count: int): Array(int) MakeArray :: (a: *int, count: int): Array(int)
result := Array(int) { result := Array(int) {
data = a, data = a,
len = count, len = count,
cap = count cap = count
} }
return result return result
MultipleArgs :: (): Tuple(int, F32) MultipleArgs :: (): Tuple(int, F32)
return {32, 32} return {32, 32}
PolyLambda :: ($T: Type = *int): T PolyLambda :: ($T: Type = *int): T
return 0 return 0
PolyType :: (a: $T): T PolyType :: (a: $T): T
return a return a
GetCount :: (a: int): int GetCount :: (a: int): int
return a return a
C :: #import "LibC.core" C :: #import "LibC.core"
Add :: (arr: *Array($T), val: T) Add :: (arr: *Array($T), val: T)
if arr.cap == 0 if arr.cap == 0
arr.cap = 16 arr.cap = 16
arr.data = C.malloc(sizeof(T)->U64 * arr.cap->U64) arr.data = C.malloc(sizeof(T)->U64 * arr.cap->U64)
arr.data[arr.len++] = val arr.data[arr.len++] = val
main :: (argc: int, argv: **char): int main :: (argc: int, argv: **char): int
buff: *int buff: *int
array: Array(S64) array: Array(S64)
second_array: Array(int) second_array: Array(int)
third_array: Array(int) third_array: Array(int)
fourth: Array(F32) fourth: Array(F32)
fifth: Array(F32) fifth: Array(F32)
sixth: Array(Array(F32)) sixth: Array(Array(F32))
seventh: Variant(int, F32, S64) seventh: Variant(int, F32, S64)
test_a := int test_a := int
test := *int test := *int
Assert(test_a != test) Assert(test_a != test)
// c := MakeArray(buff, GetCount(GetCount(32))) // c := MakeArray(buff, GetCount(GetCount(32)))
a, b := MultipleArgs() a, b := MultipleArgs()
Assert(a == 32 && b == 32) Assert(a == 32 && b == 32)
Add(&array, 32) Add(&array, 32)
Add(&second_array, 32) Add(&second_array, 32)
Add(&third_array, 32) Add(&third_array, 32)
Add(&fourth, 32) Add(&fourth, 32)
Add(&fifth, 32) Add(&fifth, 32)
Add(&sixth, {}) Add(&sixth, {})
value := PolyLambda(**int) value := PolyLambda(**int)
PolyType_r1 := PolyType(10) PolyType_r1 := PolyType(10)
PolyType_r2 := PolyType(int) PolyType_r2 := PolyType(int)
PolyType_r3 := PolyType(test) PolyType_r3 := PolyType(test)
PolyType_r4 := PolyType(test_a) PolyType_r4 := PolyType(test_a)
PolyType_r5 := PolyType(sixth) PolyType_r5 := PolyType(sixth)
PolyType_r6 := PolyType(seventh) PolyType_r6 := PolyType(seventh)
return 0 return 0

View File

@@ -1,15 +1,15 @@
MA :: #import "Arena.core" MA :: #import "Arena.core"
PushStruct :: (a: *MA.Arena, $K: Type, $T: Type): *T PushStruct :: (a: *MA.Arena, $K: Type, $T: Type): *T
size := sizeof(T) size := sizeof(T)
result := MA.PushSize(a, size->U64) result := MA.PushSize(a, size->U64)
return result->*T return result->*T
main :: (argc: int, argv: **char): int main :: (argc: int, argv: **char): int
arena: MA.Arena arena: MA.Arena
a: *int = PushStruct(&arena, int, int) a: *int = PushStruct(&arena, int, int)
b: *F32 = PushStruct(&arena, int, F32) b: *F32 = PushStruct(&arena, int, F32)
padding := sizeof(int) padding := sizeof(int)
Assert(arena.len->int == (sizeof(int) + sizeof(F32) + padding)) Assert(arena.len->int == (sizeof(int) + sizeof(F32) + padding))
return 0 return 0

View File

@@ -1,210 +1,210 @@
F :: #import "MathF32.core" F :: #import "MathF32.core"
V3 :: #import "MathVec3.core"; Vec3 :: V3.Vec3 V3 :: #import "MathVec3.core"; Vec3 :: V3.Vec3
V2 :: #import "MathVec2.core"; Vec2 :: V2.Vec2 V2 :: #import "MathVec2.core"; Vec2 :: V2.Vec2
Epsilon :: 0.00001 Epsilon :: 0.00001
Screen : *U32 Screen : *U32
X : int X : int
Y : int Y : int
TotalTime: F64 TotalTime: F64
LightPos := Vec3{2,4,2} LightPos := Vec3{2,4,2}
SphereSDF :: (pos: Vec3): F32 SphereSDF :: (pos: Vec3): F32
result := V3.Length(pos) - 1.0 result := V3.Length(pos) - 1.0
return result return result
Raymarcher_Update :: () Raymarcher_Update :: ()
up := Vec3{0, 1, 0} up := Vec3{0, 1, 0}
forward := Vec3{0, 0, -1} forward := Vec3{0, 0, -1}
side := V3.Normalize(V3.Cross(forward, up)) side := V3.Normalize(V3.Cross(forward, up))
LightPos.x = F.Cos(TotalTime->F32)*4 LightPos.x = F.Cos(TotalTime->F32)*4
LightPos.y = F.Sin(TotalTime->F32)*4 LightPos.y = F.Sin(TotalTime->F32)*4
ambient_color := Vec3{0.2,0.2,0.2} ambient_color := Vec3{0.2,0.2,0.2}
diffuse_color := Vec3{0.7,0.2,0.2} diffuse_color := Vec3{0.7,0.2,0.2}
specular_color := Vec3{1,1,1} specular_color := Vec3{1,1,1}
eye := Vec3{0, 0, 2} eye := Vec3{0, 0, 2}
light_intensity :: 1.2->F32 light_intensity :: 1.2->F32
Xf := 1 / X->F32 Xf := 1 / X->F32
Yf := 1 / Y->F32 Yf := 1 / Y->F32
ratio := X->F32 / Y->F32 ratio := X->F32 / Y->F32
for y := 0, y < Y, y+=1 for y := 0, y < Y, y+=1
for x := 0, x < X, x+=1 for x := 0, x < X, x+=1
uv := Vec3{x->F32 * Xf * 2 - 1, y->F32 * Yf * 2 - 1, 1.0} uv := Vec3{x->F32 * Xf * 2 - 1, y->F32 * Yf * 2 - 1, 1.0}
uv.x *= ratio uv.x *= ratio
dir := V3.Normalize(Vec3{V3.Dot(side, uv), V3.Dot(up, uv), V3.Dot(forward, uv)}) dir := V3.Normalize(Vec3{V3.Dot(side, uv), V3.Dot(up, uv), V3.Dot(forward, uv)})
t: F32 t: F32
end: F32 = 100.0 end: F32 = 100.0
hit := true hit := true
p: Vec3 p: Vec3
for i := 0, i < 255, i+=1 for i := 0, i < 255, i+=1
p = eye + dir*t p = eye + dir*t
distance := SphereSDF(p) distance := SphereSDF(p)
if distance < Epsilon if distance < Epsilon
break break
t += distance t += distance
if distance >= end if distance >= end
hit = false hit = false
break break
if hit if hit
normal := V3.Normalize(Vec3{ normal := V3.Normalize(Vec3{
SphereSDF({p.x + Epsilon, p.y, p.z}) - SphereSDF({p.x - Epsilon, p.y, p.z}), SphereSDF({p.x + Epsilon, p.y, p.z}) - SphereSDF({p.x - Epsilon, p.y, p.z}),
SphereSDF({p.x, p.y + Epsilon, p.z}) - SphereSDF({p.x, p.y - Epsilon, p.z}), SphereSDF({p.x, p.y + Epsilon, p.z}) - SphereSDF({p.x, p.y - Epsilon, p.z}),
SphereSDF({p.x, p.y, p.z + Epsilon}) - SphereSDF({p.x, p.y, p.z - Epsilon}), SphereSDF({p.x, p.y, p.z + Epsilon}) - SphereSDF({p.x, p.y, p.z - Epsilon}),
}) })
light_to_point := V3.Normalize(LightPos - p) light_to_point := V3.Normalize(LightPos - p)
eye_to_point := V3.Normalize(eye - p) eye_to_point := V3.Normalize(eye - p)
reflected_light := V3.Normalize(V3.Reflect(V3.Negate(light_to_point), normal)) reflected_light := V3.Normalize(V3.Reflect(V3.Negate(light_to_point), normal))
ambient :: 0.2->F32 ambient :: 0.2->F32
diffuse := V3.Dot(normal, light_to_point) diffuse := V3.Dot(normal, light_to_point)
color := ambient_color*ambient->F32 color := ambient_color*ambient->F32
if diffuse > Epsilon if diffuse > Epsilon
color = color + diffuse_color*diffuse color = color + diffuse_color*diffuse
specular := V3.Dot(reflected_light, eye_to_point) specular := V3.Dot(reflected_light, eye_to_point)
if specular > Epsilon if specular > Epsilon
specular = specular*specular*specular*specular specular = specular*specular*specular*specular
color = color + specular_color*specular*0.2->F32 color = color + specular_color*specular*0.2->F32
color = color * light_intensity color = color * light_intensity
// Gamma correction // Gamma correction
color.x = F.SquareRoot(color.x) color.x = F.SquareRoot(color.x)
color.y = F.SquareRoot(color.y) color.y = F.SquareRoot(color.y)
color.z = F.SquareRoot(color.z) color.z = F.SquareRoot(color.z)
Screen[x + y*X] = V3.ConvertToARGB(color) Screen[x + y*X] = V3.ConvertToARGB(color)
else;; Screen[x + y*X] = 0 else;; Screen[x + y*X] = 0
///////////////////////////////////// /////////////////////////////////////
// //
// Windows specific code // Windows specific code
// //
#import "Base.core" #import "Base.core"
#import "Arena.core" #import "Arena.core"
#import "OS$OS.core" #import "OS$OS.core"
#import "KERNEL32.core" #import "KERNEL32.core"
#import "GDI32.core" #import "GDI32.core"
#import "USER32.core" #import "USER32.core"
#import "WINMM.core" #import "WINMM.core"
AppIsRunning := true AppIsRunning := true
WindowProc :: (hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM): LRESULT WindowProc :: (hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM): LRESULT
if msg == WM_DESTROY if msg == WM_DESTROY
PostQuitMessage(0) PostQuitMessage(0)
AppIsRunning = false AppIsRunning = false
return 0 return 0
else;; return DefWindowProcW(hwnd, msg, wparam, lparam) else;; return DefWindowProcW(hwnd, msg, wparam, lparam)
WinMain :: (hInstance: HINSTANCE, hPrevInstance: HINSTANCE, lpCmdLine: LPSTR, nShowCmd: int): int WinMain :: (hInstance: HINSTANCE, hPrevInstance: HINSTANCE, lpCmdLine: LPSTR, nShowCmd: int): int
if good_scheduling := false, timeBeginPeriod(1) == TIMERR_NOERROR if good_scheduling := false, timeBeginPeriod(1) == TIMERR_NOERROR
good_scheduling = true good_scheduling = true
dpi_aware_set := SetProcessDPIAware() dpi_aware_set := SetProcessDPIAware()
Assert(dpi_aware_set != 0) Assert(dpi_aware_set != 0)
arena: Arena arena: Arena
window_name := StringToString16(&arena, "Have a wonderful day! 你好世界 ") window_name := StringToString16(&arena, "Have a wonderful day! 你好世界 ")
w := WNDCLASSW{ w := WNDCLASSW{
lpfnWndProc = WindowProc, lpfnWndProc = WindowProc,
hInstance = hInstance, hInstance = hInstance,
lpszClassName = window_name.str, lpszClassName = window_name.str,
} }
Assert(RegisterClassW(&w) != 0) Assert(RegisterClassW(&w) != 0)
screen_size: V2.Vec2I = {1280, 720} screen_size: V2.Vec2I = {1280, 720}
window := CreateWindowExW( window := CreateWindowExW(
dwExStyle = 0, hWndParent = 0, hMenu = 0, lpParam = 0, dwExStyle = 0, hWndParent = 0, hMenu = 0, lpParam = 0,
X = CW_USEDEFAULT, Y = CW_USEDEFAULT, nWidth = screen_size.x->int, nHeight = screen_size.y->int, X = CW_USEDEFAULT, Y = CW_USEDEFAULT, nWidth = screen_size.x->int, nHeight = screen_size.y->int,
lpClassName = window_name.str, lpClassName = window_name.str,
lpWindowName = window_name.str, lpWindowName = window_name.str,
dwStyle = WS_OVERLAPPEDWINDOW, dwStyle = WS_OVERLAPPEDWINDOW,
hInstance = hInstance hInstance = hInstance
) )
Assert(window != 0) Assert(window != 0)
ShowWindow(window, nShowCmd) ShowWindow(window, nShowCmd)
window_dc := GetDC(window) window_dc := GetDC(window)
bitmap := CreateBitmap(screen_size) bitmap := CreateBitmap(screen_size)
requested_time_per_frame: F64 = 1.0 / 60.0 requested_time_per_frame: F64 = 1.0 / 60.0
frame_start_time := Time() frame_start_time := Time()
frame_number: int frame_number: int
for AppIsRunning for AppIsRunning
msg: MSG msg: MSG
for PeekMessageW(&msg, window, 0, 0, PM_REMOVE) > 0 for PeekMessageW(&msg, window, 0, 0, PM_REMOVE) > 0
TranslateMessage(&msg) TranslateMessage(&msg)
DispatchMessageW(&msg) DispatchMessageW(&msg)
Screen = bitmap.data; X = bitmap.size.x; Y = bitmap.size.y Screen = bitmap.data; X = bitmap.size.x; Y = bitmap.size.y
Raymarcher_Update() Raymarcher_Update()
SelectObject(bitmap.hdc, bitmap.dib) SelectObject(bitmap.hdc, bitmap.dib)
BitBlt(window_dc, 0, 0, (bitmap.size.x)->int, (bitmap.size.y)->int, bitmap.hdc, 0, 0, SRCCOPY) BitBlt(window_dc, 0, 0, (bitmap.size.x)->int, (bitmap.size.y)->int, bitmap.hdc, 0, 0, SRCCOPY)
frame_time := Time() - frame_start_time frame_time := Time() - frame_start_time
frame_number += 1 frame_number += 1
TotalTime += frame_time TotalTime += frame_time
if frame_time < requested_time_per_frame if frame_time < requested_time_per_frame
if good_scheduling if good_scheduling
time_to_sleep := (requested_time_per_frame - frame_time) * 1000 time_to_sleep := (requested_time_per_frame - frame_time) * 1000
if time_to_sleep > 0 if time_to_sleep > 0
time_to_sleep_dword := time_to_sleep->DWORD time_to_sleep_dword := time_to_sleep->DWORD
// @check if time_to_sleep_dword truncates down // @check if time_to_sleep_dword truncates down
Sleep(time_to_sleep_dword) Sleep(time_to_sleep_dword)
new_frame_time := Time() new_frame_time := Time()
for new_frame_time < requested_time_per_frame for new_frame_time < requested_time_per_frame
new_frame_time = Time() - frame_start_time new_frame_time = Time() - frame_start_time
frame_time = new_frame_time frame_time = new_frame_time
if CStringCompare(lpCmdLine, "testing") if CStringCompare(lpCmdLine, "testing")
return 0 return 0
return 0 return 0
Windows_Bitmap :: struct Windows_Bitmap :: struct
size: V2.Vec2I size: V2.Vec2I
data: *U32 data: *U32
hdc: HDC hdc: HDC
dib: HBITMAP dib: HBITMAP
CreateBitmap :: (size: V2.Vec2I, bottom_up: bool = true): Windows_Bitmap CreateBitmap :: (size: V2.Vec2I, bottom_up: bool = true): Windows_Bitmap
result: Windows_Bitmap = {size = size} result: Windows_Bitmap = {size = size}
if bottom_up == false if bottom_up == false
result.size.y = -result.size.y result.size.y = -result.size.y
header_size: U32 = sizeof(BITMAPINFOHEADER) header_size: U32 = sizeof(BITMAPINFOHEADER)
Assert(header_size == 40) Assert(header_size == 40)
bminfo := BITMAPINFO{ bminfo := BITMAPINFO{
BITMAPINFOHEADER{ BITMAPINFOHEADER{
biSize = header_size, biSize = header_size,
biWidth = size.x->LONG, biWidth = size.x->LONG,
biHeight = size.y->LONG, biHeight = size.y->LONG,
biPlanes = 1, biPlanes = 1,
biBitCount = 32, biBitCount = 32,
biCompression = BI_RGB, biCompression = BI_RGB,
biXPelsPerMeter = 1, biXPelsPerMeter = 1,
biYPelsPerMeter = 1, biYPelsPerMeter = 1,
} }
} }
hdc := GetDC(0) hdc := GetDC(0)
result.dib = CreateDIBSection(hdc, &bminfo, DIB_RGB_COLORS, (&result.data)->**void, 0, 0) result.dib = CreateDIBSection(hdc, &bminfo, DIB_RGB_COLORS, (&result.data)->**void, 0, 0)
result.hdc = CreateCompatibleDC(hdc) result.hdc = CreateCompatibleDC(hdc)
return result return result

View File

@@ -1,65 +1,65 @@
main :: (): int main :: (): int
// Let's say we have a type // Let's say we have a type
some_type := S64 some_type := S64
// this function call allows us to get extensive type information // this function call allows us to get extensive type information
// about this type. For example this information allows us to walk // about this type. For example this information allows us to walk
// the type tree, pretty print all values in that type, along with their sizes. // the type tree, pretty print all values in that type, along with their sizes.
// Other use cases allow us to do a type safe printf // Other use cases allow us to do a type safe printf
type_info: *Type_Info = GetTypeInfo(some_type) type_info: *Type_Info = GetTypeInfo(some_type)
// It can be null, requiring the type information would be a bit unwise // It can be null, requiring the type information would be a bit unwise
// this is a lot of data // this is a lot of data
if !type_info if !type_info
return 1 return 1
if type_info.type == S64 if type_info.type == S64
// We can use sizeof and alignof operators // We can use sizeof and alignof operators
// to figure out the type alignment and it's size // to figure out the type alignment and it's size
Assert(type_info.size == sizeof(S64)) Assert(type_info.size == sizeof(S64))
Assert(type_info.align == alignof(S64)) Assert(type_info.align == alignof(S64))
else;; Assert(false, "We expected S64 here! What a boomer!") else;; Assert(false, "We expected S64 here! What a boomer!")
// //
// @todo: This should work // @todo: This should work
// //
// any_thing: Any = 10 // any_thing: Any = 10
// //
// Any type allows us to combine a value pointer and // Any type allows us to combine a value pointer and
// it's corresponding type_id // it's corresponding type_id
// //
value_to_be_wrapped := 10 value_to_be_wrapped := 10
any_value: Any = value_to_be_wrapped any_value: Any = value_to_be_wrapped
if any_value.type == int if any_value.type == int
*(any_value.data->*int) = 20 *(any_value.data->*int) = 20
else ;; Assert(false, "No bueno") else ;; Assert(false, "No bueno")
Assert(*(any_value.data->*int) == 20) Assert(*(any_value.data->*int) == 20)
letter := GetFirstLetterOfType(value_to_be_wrapped) letter := GetFirstLetterOfType(value_to_be_wrapped)
Assert(letter == 'I') Assert(letter == 'I')
return 0 return 0
GetFirstLetterOfType :: (a: Any): U8 GetFirstLetterOfType :: (a: Any): U8
type_info := GetTypeInfo(a.type) type_info := GetTypeInfo(a.type)
if !type_info if !type_info
return '-' return '-'
result: U8 result: U8
switch type_info.kind switch type_info.kind
Type_Info_Kind.S64, Type_Info_Kind.S32, Type_Info_Kind.S16, Type_Info_Kind.S8, Type_Info_Kind.INT Type_Info_Kind.S64, Type_Info_Kind.S32, Type_Info_Kind.S16, Type_Info_Kind.S8, Type_Info_Kind.INT
result = 'I' result = 'I'
Type_Info_Kind.U64, Type_Info_Kind.U32, Type_Info_Kind.U16, Type_Info_Kind.U8 Type_Info_Kind.U64, Type_Info_Kind.U32, Type_Info_Kind.U16, Type_Info_Kind.U8
result = 'U' result = 'U'
Type_Info_Kind.F64 Type_Info_Kind.F64
result = 'F' result = 'F'
Type_Info_Kind.POINTER Type_Info_Kind.POINTER
result = '*' result = '*'
default;; result = '-' default;; result = '-'
return result return result

View File

@@ -1,48 +1,48 @@
main :: (): int main :: (): int
// Types can be evaluated at compile time for equality // Types can be evaluated at compile time for equality
#Assert(int == int) #Assert(int == int)
#Assert(int != char) #Assert(int != char)
#Assert(*char == *char) #Assert(*char == *char)
// They can also be evaluated at runtime, they basically get // They can also be evaluated at runtime, they basically get
// replaced with type ids, which are just unique integers assigned // replaced with type ids, which are just unique integers assigned
// to each type // to each type
Assert(int == int) Assert(int == int)
Assert(int != char) Assert(int != char)
Assert(*char == *char) Assert(*char == *char)
// We can assign types to compile time variable constants // We can assign types to compile time variable constants
New_Type :: int New_Type :: int
// This is a loose association // This is a loose association
thing: int = 10 thing: int = 10
new_type_thing: New_Type = thing new_type_thing: New_Type = thing
#Assert(New_Type == int) #Assert(New_Type == int)
// to force typechecker to treat$ // to force typechecker to treat$
// both of these types as different we need to add a #strict directive // both of these types as different we need to add a #strict directive
Strict_Type :: #strict int Strict_Type :: #strict int
// new_strict_type_thing: Strict_Type = thing // This produces a compile time type error // new_strict_type_thing: Strict_Type = thing // This produces a compile time type error
// But this works // But this works
strict_thing: Strict_Type = 10 strict_thing: Strict_Type = 10
#Assert(Strict_Type != int) #Assert(Strict_Type != int)
// If we want to use those types together we need to cast // If we want to use those types together we need to cast
Assert(new_type_thing + strict_thing->int != 0) Assert(new_type_thing + strict_thing->int != 0)
// We can also assign types to runtime variables, there is a special type for that // We can also assign types to runtime variables, there is a special type for that
some_type: Type = int some_type: Type = int
some_type_implicit := char some_type_implicit := char
// These can be checked for equality using ifs and switches // These can be checked for equality using ifs and switches
if some_type == char if some_type == char
pass pass
elif some_type_implicit == char elif some_type_implicit == char
pass pass
return 0 return 0

View File

@@ -1,40 +1,40 @@
U :: union U :: union
a: F64 a: F64
b: F32 b: F32
C :: struct C :: struct
a: int a: int
b: int b: int
main :: (argc: int, argv: **char): int main :: (argc: int, argv: **char): int
memes: U memes: U
memes.b = 10 memes.b = 10
Assert(memes.b == 10) Assert(memes.b == 10)
Assert(memes.a != 0) Assert(memes.a != 0)
compound: U = {b = 10.0} compound: U = {b = 10.0}
Assert(compound.b == 10) Assert(compound.b == 10)
t := U t := U
ti := GetTypeInfo(t) ti := GetTypeInfo(t)
Assert(ti.size == sizeof(U)) Assert(ti.size == sizeof(U))
for ti.struct_members for ti.struct_members
Assert(it.offset == 0) Assert(it.offset == 0)
ti_it := GetTypeInfo(it.type) ti_it := GetTypeInfo(it.type)
Assert(ti_it.size != 0) Assert(ti_it.size != 0)
/* @reproduction @todo /* @reproduction @todo
``` ```
examples/unions.core - Error! Couldn't infer type of compound expression examples/unions.core - Error! Couldn't infer type of compound expression
c = {10} c = {10}
``` ```
c: C c: C
c = {10} c = {10}
*/ */
return 0 return 0

View File

@@ -1,12 +1,12 @@
#import "Multimedia.core" #import "Multimedia.core"
main :: (): int main :: (): int
StartMultimedia(title = "Hello people!") StartMultimedia(title = "Hello people!")
for UpdateMultimedia() for UpdateMultimedia()
if Mu.key[Key.Escape].down ;; Mu.quit = true if Mu.key[Key.Escape].down ;; Mu.quit = true
for y := 0, y < Mu.window.y, y+=1 for y := 0, y < Mu.window.y, y+=1
for x := 0, x < Mu.window.x, x+=1 for x := 0, x < Mu.window.x, x+=1
Mu.screen[x + y*Mu.window.x] = 0xFFFFFF00 Mu.screen[x + y*Mu.window.x] = 0xFFFFFF00
return 0 return 0

View File

@@ -1,2 +0,0 @@
cloc *.hpp *.cpp *.py *.h
git rev-list --all --count

View File

@@ -1,50 +1,50 @@
OS :: #import "OS$OS.core" OS :: #import "OS$OS.core"
Base :: #import "Base.core" Base :: #import "Base.core"
ArenaDI: U64 ArenaDI: U64
ADDITIONAL_COMMIT_SIZE :: 1024*1024 ADDITIONAL_COMMIT_SIZE :: 1024*1024
DEFAULT_RESERVE_SIZE :: 1024*1024*1024 DEFAULT_RESERVE_SIZE :: 1024*1024*1024
DEFAULT_ALIGNMENT :: 8 DEFAULT_ALIGNMENT :: 8
Arena :: struct Arena :: struct
di: U64 // @debug_id di: U64 // @debug_id
memory: OS.Memory memory: OS.Memory
alignment: U64 alignment: U64
len: U64 len: U64
Init :: (a: *Arena) Init :: (a: *Arena)
a.memory = OS.Reserve(DEFAULT_RESERVE_SIZE) a.memory = OS.Reserve(DEFAULT_RESERVE_SIZE)
a.alignment = DEFAULT_ALIGNMENT a.alignment = DEFAULT_ALIGNMENT
a.di = ArenaDI++ a.di = ArenaDI++
FromBuffer :: (buffer: []U8): Arena FromBuffer :: (buffer: []U8): Arena
a: Arena a: Arena
a.memory.reserve = Len(buffer)->U64 a.memory.reserve = Len(buffer)->U64
a.memory.commit = Len(buffer)->U64 a.memory.commit = Len(buffer)->U64
a.alignment = DEFAULT_ALIGNMENT a.alignment = DEFAULT_ALIGNMENT
a.di = ArenaDI++ a.di = ArenaDI++
return a return a
PushSize :: (a: *Arena, size: Base.SizeU): *void PushSize :: (a: *Arena, size: Base.SizeU): *void
generous_size := size + a.alignment generous_size := size + a.alignment
if a.len + generous_size > a.memory.commit if a.len + generous_size > a.memory.commit
if a.memory.reserve == 0 if a.memory.reserve == 0
Init(a) Init(a)
result := OS.Commit(&a.memory, generous_size + ADDITIONAL_COMMIT_SIZE) result := OS.Commit(&a.memory, generous_size + ADDITIONAL_COMMIT_SIZE)
Assert(result == true) Assert(result == true)
a.len = Base.AlignUp(a.len, a.alignment) a.len = Base.AlignUp(a.len, a.alignment)
Assert(a.memory.reserve > a.len + a.memory.commit) Assert(a.memory.reserve > a.len + a.memory.commit)
result: *void = a.memory.data + a.len result: *void = a.memory.data + a.len
a.len += size a.len += size
return result return result
Release :: (a: *Arena) Release :: (a: *Arena)
OS.Release(&a.memory) OS.Release(&a.memory)
PushArray :: (a: *Arena, count: int, $T: Type): *T PushArray :: (a: *Arena, count: int, $T: Type): *T
result := PushSize(a, sizeof(T) * count->U64) result := PushSize(a, sizeof(T) * count->U64)
return result->*T return result->*T
PushStruct :: (a: *Arena, $T: Type): *T PushStruct :: (a: *Arena, $T: Type): *T
result := PushSize(a, sizeof(T)) result := PushSize(a, sizeof(T))
return result->*T return result->*T

View File

@@ -1,124 +1,124 @@
#import "Arena.core" #import "Arena.core"
OS :: #import "OS$OS.core" OS :: #import "OS$OS.core"
SizeU :: U64 SizeU :: U64
ClampTopSizeU :: (val: SizeU, max: SizeU): SizeU ClampTopSizeU :: (val: SizeU, max: SizeU): SizeU
if val > max if val > max
return max return max
return val return val
Getalignoffset :: (size: SizeU, align: SizeU): SizeU Getalignoffset :: (size: SizeU, align: SizeU): SizeU
mask := align - 1 mask := align - 1
val := size & mask val := size & mask
if val != 0 if val != 0
val = align - val val = align - val
return val return val
AlignUp :: (size: SizeU, align: SizeU): SizeU AlignUp :: (size: SizeU, align: SizeU): SizeU
result := size + Getalignoffset(size, align) result := size + Getalignoffset(size, align)
return result return result
ZeroMemory :: (p: *void, size: SizeU) ZeroMemory :: (p: *void, size: SizeU)
pcast := p->*U8 pcast := p->*U8
for i := 0->SizeU, i < size, i++ for i := 0->SizeU, i < size, i++
pcast[i] = 0 pcast[i] = 0
// //
// Unicode // Unicode
// //
QuestionMark16 :: 0x003f QuestionMark16 :: 0x003f
String32 :: struct;; str: *U32; len: int String32 :: struct;; str: *U32; len: int
String16 :: struct;; str: *U16; len: int String16 :: struct;; str: *U16; len: int
Utf8ToUtf32 :: (c: *U8, max_advance: int): Two(U32, int) Utf8ToUtf32 :: (c: *U8, max_advance: int): Two(U32, int)
out_str: U32 out_str: U32
advance: int advance: int
if (c[0] & 0b10000000) == 0 if (c[0] & 0b10000000) == 0
if max_advance >= 1 if max_advance >= 1
c0 := c[0]->U32 c0 := c[0]->U32
out_str = c0 out_str = c0
advance = 1 advance = 1
elif (c[0] & 0b11100000) == 0b11000000 elif (c[0] & 0b11100000) == 0b11000000
if (c[1] & 0b11000000) == 0b10000000 // Continuation byte required if (c[1] & 0b11000000) == 0b10000000 // Continuation byte required
if max_advance >= 2 if max_advance >= 2
c0 := c[0]->U32; c1 := c[1]->U32 c0 := c[0]->U32; c1 := c[1]->U32
out_str = (c0 & 0b00011111) << 6 | (c1 & 0b00111111) out_str = (c0 & 0b00011111) << 6 | (c1 & 0b00111111)
advance = 2 advance = 2
elif (c[0] & 0b11110000) == 0b11100000 elif (c[0] & 0b11110000) == 0b11100000
if (c[1] & 0b11000000) == 0b10000000 && (c[2] & 0b11000000) == 0b10000000 // Two continuation bytes required if (c[1] & 0b11000000) == 0b10000000 && (c[2] & 0b11000000) == 0b10000000 // Two continuation bytes required
if max_advance >= 3 if max_advance >= 3
c0 := c[0]->U32; c1 := c[1]->U32; c2 := c[2]->U32 c0 := c[0]->U32; c1 := c[1]->U32; c2 := c[2]->U32
out_str = (c0 & 0b00001111) << 12 | (c1 & 0b00111111) << 6 | (c2 & 0b00111111) out_str = (c0 & 0b00001111) << 12 | (c1 & 0b00111111) << 6 | (c2 & 0b00111111)
advance = 3 advance = 3
elif (c[0] & 0b11111000) == 0b11110000 elif (c[0] & 0b11111000) == 0b11110000
if (c[1] & 0b11000000) == 0b10000000 && (c[2] & 0b11000000) == 0b10000000 && (c[3] & 0b11000000) == 0b10000000 // Three continuation bytes required if (c[1] & 0b11000000) == 0b10000000 && (c[2] & 0b11000000) == 0b10000000 && (c[3] & 0b11000000) == 0b10000000 // Three continuation bytes required
if max_advance >= 4 if max_advance >= 4
c0 := c[0]->U32; c1 := c[1]->U32; c2 := c[2]->U32; c3 := c[3]->U32 c0 := c[0]->U32; c1 := c[1]->U32; c2 := c[2]->U32; c3 := c[3]->U32
out_str = (c0 & 0b00001111) << 18 | (c1 & 0b00111111) << 12 | (c2 & 0b00111111) << 6 | (c3 & 0b00111111) out_str = (c0 & 0b00001111) << 18 | (c1 & 0b00111111) << 12 | (c2 & 0b00111111) << 6 | (c3 & 0b00111111)
advance = 4 advance = 4
return {out_str, advance} return {out_str, advance}
Utf32ToUtf16 :: (codepoint: U32): Two([2]U16, int) Utf32ToUtf16 :: (codepoint: U32): Two([2]U16, int)
result: Two([2]U16, int) result: Two([2]U16, int)
if codepoint < 0x10000 if codepoint < 0x10000
result.a[0] = codepoint->U16 result.a[0] = codepoint->U16
result.b = 1 result.b = 1
elif codepoint <= 0x10FFFF elif codepoint <= 0x10FFFF
code: U32 = (codepoint - 0x10000) code: U32 = (codepoint - 0x10000)
result.a[0] = (0xD800 | (code >> 10))->U16 result.a[0] = (0xD800 | (code >> 10))->U16
result.a[1] = (0xDC00 | (code & 0x3FF))->U16 result.a[1] = (0xDC00 | (code & 0x3FF))->U16
result.b = 2 result.b = 2
return result return result
StringToString16 :: (arena: *Arena, in: String): String16 StringToString16 :: (arena: *Arena, in: String): String16
in_str := &in[0] in_str := &in[0]
// @Note(Krzosa): Should be more then enough space // @Note(Krzosa): Should be more then enough space
alloc_size := (Len(in)*2)+1 alloc_size := (Len(in)*2)+1
result := String16{str = PushSize(arena, alloc_size->U64)} result := String16{str = PushSize(arena, alloc_size->U64)}
for i := 0, i < Len(in) for i := 0, i < Len(in)
a := Utf8ToUtf32(in_str + i, Len(in) - i) a := Utf8ToUtf32(in_str + i, Len(in) - i)
s32 := a.a s32 := a.a
s32_len := a.b s32_len := a.b
if s32_len != 0 if s32_len != 0
i += s32_len i += s32_len
s16, s16_len := Utf32ToUtf16(s32) s16, s16_len := Utf32ToUtf16(s32)
if s16_len != 0 if s16_len != 0
for j := 0, j < s16_len, j++ for j := 0, j < s16_len, j++
result.str[result.len++] = s16[j] result.str[result.len++] = s16[j]
else else
result.str[result.len++] = QuestionMark16 result.str[result.len++] = QuestionMark16
break break
else else
result.str[result.len++] = QuestionMark16 result.str[result.len++] = QuestionMark16
break break
result.str[result.len] = 0 result.str[result.len] = 0
return result return result
CStringCompare :: (a: *char, b: *char): bool CStringCompare :: (a: *char, b: *char): bool
i := 0 i := 0
for , a[i] != 0, i+=1 for , a[i] != 0, i+=1
if a[i] != b[i] if a[i] != b[i]
return false return false
if a[i] != b[i] if a[i] != b[i]
return false return false
return true return true
TestUnicode :: (arena: *Arena) TestUnicode :: (arena: *Arena)
string := " 豈 更 車 賈 滑 串 句 龜 龜 契 金 喇 奈 懶 癩 羅 蘿 螺 裸 邏 樂 洛 烙 珞 落 酪 駱 亂 卵 欄 爛 蘭 鸞 嵐 濫 藍 襤 拉 臘 蠟 廊 朗 浪 狼 郎 來 冷 勞 擄 櫓 爐 盧 老 蘆 虜 路 露 魯 鷺 碌 祿 綠 菉 錄 鹿 論 壟 弄 籠 聾 牢 磊 賂 雷 壘 屢 樓 淚 漏 累 縷 陋 勒 肋 凜 凌 稜 綾 菱 陵 讀 拏 樂 諾 丹 寧 怒 率 異 北 磻 便 復 不 泌 數 索 參 塞 省 葉 說 殺 辰 沈 拾 若 掠 略 亮 兩 凉 梁 糧 良 諒 量 勵 ..." string := " 豈 更 車 賈 滑 串 句 龜 龜 契 金 喇 奈 懶 癩 羅 蘿 螺 裸 邏 樂 洛 烙 珞 落 酪 駱 亂 卵 欄 爛 蘭 鸞 嵐 濫 藍 襤 拉 臘 蠟 廊 朗 浪 狼 郎 來 冷 勞 擄 櫓 爐 盧 老 蘆 虜 路 露 魯 鷺 碌 祿 綠 菉 錄 鹿 論 壟 弄 籠 聾 牢 磊 賂 雷 壘 屢 樓 淚 漏 累 縷 陋 勒 肋 凜 凌 稜 綾 菱 陵 讀 拏 樂 諾 丹 寧 怒 率 異 北 磻 便 復 不 泌 數 索 參 塞 省 葉 說 殺 辰 沈 拾 若 掠 略 亮 兩 凉 梁 糧 良 諒 量 勵 ..."
string_result := StringToString16(arena, string) string_result := StringToString16(arena, string)
print(string_result) print(string_result)
s32, s32_len := Utf8ToUtf32('A', 1) s32, s32_len := Utf8ToUtf32('A', 1)
assert(s32 == 'A', "Invalid decode") assert(s32 == 'A', "Invalid decode")
s32_2, s32_len_2 := Utf8ToUtf32('ć', 2) s32_2, s32_len_2 := Utf8ToUtf32('ć', 2)
assert(s32_2 == 0x107, "Invalid decode") assert(s32_2 == 0x107, "Invalid decode")
s32_3, s32_len_3 := Utf8ToUtf32('ó', 2) s32_3, s32_len_3 := Utf8ToUtf32('ó', 2)
assert(s32_3 == 0xF3, "Invalid decode") assert(s32_3 == 0xF3, "Invalid decode")

View File

@@ -1,41 +1,41 @@
#import "KERNEL32.core" #import "KERNEL32.core"
#link "gdi32" #link "gdi32"
RBGQUAD :: struct;; rgbBlue: BYTE; rgbGreen: BYTE; rgbRed: BYTE; rgbReserved: BYTE RBGQUAD :: struct;; rgbBlue: BYTE; rgbGreen: BYTE; rgbRed: BYTE; rgbReserved: BYTE
BITMAPINFOHEADER :: struct;; biSize: DWORD; biWidth: LONG; biHeight: LONG; biPlanes: WORD; biBitCount: WORD; biCompression: DWORD; biSizeImage: DWORD; biXPelsPerMeter: LONG; biYPelsPerMeter: LONG; biClrUsed: DWORD; biClrImportant: DWORD BITMAPINFOHEADER :: struct;; biSize: DWORD; biWidth: LONG; biHeight: LONG; biPlanes: WORD; biBitCount: WORD; biCompression: DWORD; biSizeImage: DWORD; biXPelsPerMeter: LONG; biYPelsPerMeter: LONG; biClrUsed: DWORD; biClrImportant: DWORD
BITMAPINFO :: struct;; bmiHeader: BITMAPINFOHEADER; bmiColors: [1]RBGQUAD BITMAPINFO :: struct;; bmiHeader: BITMAPINFOHEADER; bmiColors: [1]RBGQUAD
HGDIOBJ :: HANDLE HGDIOBJ :: HANDLE
BI_RGB :: 0x0000 BI_RGB :: 0x0000
BI_RLE8 :: 0x0001 BI_RLE8 :: 0x0001
BI_RLE4 :: 0x0002 BI_RLE4 :: 0x0002
BI_BITFIELDS :: 0x0003 BI_BITFIELDS :: 0x0003
BI_JPEG :: 0x0004 BI_JPEG :: 0x0004
BI_PNG :: 0x0005 BI_PNG :: 0x0005
BI_CMYK :: 0x000B BI_CMYK :: 0x000B
BI_CMYKRLE8 :: 0x000C BI_CMYKRLE8 :: 0x000C
BI_CMYKRLE4 :: 0x000 BI_CMYKRLE4 :: 0x000
DIB_RGB_COLORS :: 0x00 DIB_RGB_COLORS :: 0x00
SRCCOPY :: 0x00CC0020 /* dest = source */ SRCCOPY :: 0x00CC0020 /* dest = source */
SRCPAINT :: 0x00EE0086 /* dest = source OR dest */ SRCPAINT :: 0x00EE0086 /* dest = source OR dest */
SRCAND :: 0x008800C6 /* dest = source AND dest */ SRCAND :: 0x008800C6 /* dest = source AND dest */
SRCINVERT :: 0x00660046 /* dest = source XOR dest */ SRCINVERT :: 0x00660046 /* dest = source XOR dest */
SRCERASE :: 0x00440328 /* dest = source AND (NOT dest ) */ SRCERASE :: 0x00440328 /* dest = source AND (NOT dest ) */
NOTSRCCOPY :: 0x00330008 /* dest = (NOT source) */ NOTSRCCOPY :: 0x00330008 /* dest = (NOT source) */
NOTSRCERASE :: 0x001100A6 /* dest = (NOT src) AND (NOT dest) */ NOTSRCERASE :: 0x001100A6 /* dest = (NOT src) AND (NOT dest) */
MERGECOPY :: 0x00C000CA /* dest = (source AND pattern) */ MERGECOPY :: 0x00C000CA /* dest = (source AND pattern) */
MERGEPAINT :: 0x00BB0226 /* dest = (NOT source) OR dest */ MERGEPAINT :: 0x00BB0226 /* dest = (NOT source) OR dest */
PATCOPY :: 0x00F00021 /* dest = pattern */ PATCOPY :: 0x00F00021 /* dest = pattern */
PATPAINT :: 0x00FB0A09 /* dest = DPSnoo */ PATPAINT :: 0x00FB0A09 /* dest = DPSnoo */
PATINVERT :: 0x005A0049 /* dest = pattern XOR dest */ PATINVERT :: 0x005A0049 /* dest = pattern XOR dest */
DSTINVERT :: 0x00550009 /* dest = (NOT dest) */ DSTINVERT :: 0x00550009 /* dest = (NOT dest) */
BLACKNESS :: 0x00000042 /* dest = BLACK */ BLACKNESS :: 0x00000042 /* dest = BLACK */
WHITENESS :: 0x00FF0062 /* dest = WHITE */ WHITENESS :: 0x00FF0062 /* dest = WHITE */
CreateDIBSection :: #foreign (hdc: HDC, pbmi: *BITMAPINFO, usage: UINT, ppvBits: **VOID, hSection: HANDLE, offset: DWORD): HBITMAP CreateDIBSection :: #foreign (hdc: HDC, pbmi: *BITMAPINFO, usage: UINT, ppvBits: **VOID, hSection: HANDLE, offset: DWORD): HBITMAP
CreateCompatibleDC :: #foreign (hdc: HDC): HDC CreateCompatibleDC :: #foreign (hdc: HDC): HDC
SelectObject :: #foreign (hdc: HDC, h: HGDIOBJ): HGDIOBJ SelectObject :: #foreign (hdc: HDC, h: HGDIOBJ): HGDIOBJ
BitBlt :: #foreign (hdc: HDC, x: int, y: int, cx: int, cy: int, hdcSrc: HDC, x1: int, y1: int, ro: DWORD): BOOL BitBlt :: #foreign (hdc: HDC, x: int, y: int, cx: int, cy: int, hdcSrc: HDC, x1: int, y1: int, ro: DWORD): BOOL
DeleteDC :: #foreign (hdc: HDC): BOOL DeleteDC :: #foreign (hdc: HDC): BOOL
DeleteObject :: #foreign (ho : HGDIOBJ): BOOL DeleteObject :: #foreign (ho : HGDIOBJ): BOOL

View File

@@ -1,130 +1,130 @@
#link "kernel32" #link "kernel32"
DWORD :: U32 DWORD :: U32
LPCSTR :: *char LPCSTR :: *char
LPSTR :: *char LPSTR :: *char
LPCWSTR :: *U16 LPCWSTR :: *U16
HWND :: *void HWND :: *void
HMENU :: *void HMENU :: *void
HINSTANCE :: *void HINSTANCE :: *void
HBITMAP :: *void HBITMAP :: *void
HDC :: *void HDC :: *void
LPVOID :: *void LPVOID :: *void
SIZE_T :: U64 SIZE_T :: U64
BOOL :: int BOOL :: int
HMODULE :: HANDLE HMODULE :: HANDLE
HANDLE :: *void HANDLE :: *void
VOID :: void VOID :: void
HICON :: HANDLE HICON :: HANDLE
HCURSOR :: HANDLE HCURSOR :: HANDLE
HBRUSH :: HANDLE HBRUSH :: HANDLE
LPDWORD :: *DWORD LPDWORD :: *DWORD
LRESULT :: S64 LRESULT :: S64
WPARAM :: U64 WPARAM :: U64
LPARAM :: S64 LPARAM :: S64
BYTE :: uchar BYTE :: uchar
WORD :: short WORD :: short
LONG :: long LONG :: long
UINT :: uint UINT :: uint
ATOM :: WORD ATOM :: WORD
LARGE_INTEGER :: S64 LARGE_INTEGER :: S64
PLARGE_INTEGER :: *LARGE_INTEGER PLARGE_INTEGER :: *LARGE_INTEGER
LPOVERLAPPED :: *OVERLAPPED LPOVERLAPPED :: *OVERLAPPED
LONG_PTR :: *S64 LONG_PTR :: *S64
ULONG_PTR :: *U64 ULONG_PTR :: *U64
MEM_COMMIT :: 0x00001000 MEM_COMMIT :: 0x00001000
MEM_RESERVE :: 0x00002000 MEM_RESERVE :: 0x00002000
MEM_RESET :: 0x00080000 MEM_RESET :: 0x00080000
MEM_RESET_UNDO :: 0x1000000 MEM_RESET_UNDO :: 0x1000000
MEM_DECOMMIT :: 0x00004000 MEM_DECOMMIT :: 0x00004000
MEM_RELEASE :: 0x00008000 MEM_RELEASE :: 0x00008000
PAGE_NOACCESS :: 1 PAGE_NOACCESS :: 1
PAGE_READONLY :: 2 PAGE_READONLY :: 2
PAGE_READWRITE :: 4 PAGE_READWRITE :: 4
PAGE_WRITECOPY :: 8 PAGE_WRITECOPY :: 8
PAGE_EXECUTE :: 0x10; PAGE_EXECUTE_READ :: 0x20; PAGE_EXECUTE_READWRITE :: 0x40; PAGE_EXECUTE_WRITECOPY :: 0x80 PAGE_EXECUTE :: 0x10; PAGE_EXECUTE_READ :: 0x20; PAGE_EXECUTE_READWRITE :: 0x40; PAGE_EXECUTE_WRITECOPY :: 0x80
VirtualAlloc :: #foreign (lpAddress: LPVOID, dwSize: SIZE_T, flAllocationType: DWORD, flProtect: DWORD): LPVOID VirtualAlloc :: #foreign (lpAddress: LPVOID, dwSize: SIZE_T, flAllocationType: DWORD, flProtect: DWORD): LPVOID
VirtualFree :: #foreign (lpAddress: LPVOID, dwSize: SIZE_T, dwFreeType: DWORD): BOOL VirtualFree :: #foreign (lpAddress: LPVOID, dwSize: SIZE_T, dwFreeType: DWORD): BOOL
HEAP_ZERO_MEMORY :: 0x8; HEAP_NO_SERIALIZE :: 0x1; HEAP_GENERATE_EXCEPTIONS :: 0x4 HEAP_ZERO_MEMORY :: 0x8; HEAP_NO_SERIALIZE :: 0x1; HEAP_GENERATE_EXCEPTIONS :: 0x4
GetProcessHeap :: #foreign (): HANDLE GetProcessHeap :: #foreign (): HANDLE
HeapAlloc :: #foreign (hHeap: HANDLE, dwFlags: DWORD, dwByte: SIZE_T): LPVOID HeapAlloc :: #foreign (hHeap: HANDLE, dwFlags: DWORD, dwByte: SIZE_T): LPVOID
HeapFree :: #foreign (hHeap: HANDLE, dwFlags: DWORD, lpMe: LPVOID): BOOL HeapFree :: #foreign (hHeap: HANDLE, dwFlags: DWORD, lpMe: LPVOID): BOOL
STD_INPUT_HANDLE :: 4294967286//(-10)->DWORD STD_INPUT_HANDLE :: 4294967286//(-10)->DWORD
STD_OUTPUT_HANDLE :: 4294967285//(-11)->DWORD STD_OUTPUT_HANDLE :: 4294967285//(-11)->DWORD
//STD_ERROR_HANDLE :: (-12)->DWORD //STD_ERROR_HANDLE :: (-12)->DWORD
GetStdHandle :: #foreign (nStdHandle: DWORD): HANDLE GetStdHandle :: #foreign (nStdHandle: DWORD): HANDLE
WriteConsoleA :: #foreign (hConsoleOutput: HANDLE,lpBuffer: *VOID,nNumberOfCharsToWrite: DWORD,lpNumberOfCharsWritten: LPDWORD,lpReserve: LPVOID): BOOL WriteConsoleA :: #foreign (hConsoleOutput: HANDLE,lpBuffer: *VOID,nNumberOfCharsToWrite: DWORD,lpNumberOfCharsWritten: LPDWORD,lpReserve: LPVOID): BOOL
WriteConsoleW :: #foreign (hConsoleOutput: HANDLE,lpBuffer: *VOID,nNumberOfCharsToWrite: DWORD,lpNumberOfCharsWritten: LPDWORD,lpReserve: LPVOID): BOOL WriteConsoleW :: #foreign (hConsoleOutput: HANDLE,lpBuffer: *VOID,nNumberOfCharsToWrite: DWORD,lpNumberOfCharsWritten: LPDWORD,lpReserve: LPVOID): BOOL
__debugbreak :: #foreign () __debugbreak :: #foreign ()
GetModuleHandleA :: #foreign (lpModuleName: LPCSTR): HMODULE GetModuleHandleA :: #foreign (lpModuleName: LPCSTR): HMODULE
ExitProcess :: #foreign (uExitCode: UINT) ExitProcess :: #foreign (uExitCode: UINT)
GetLastError :: #foreign (): DWORD GetLastError :: #foreign (): DWORD
QueryPerformanceFrequency :: #foreign (lpFrequency: *LARGE_INTEGER): BOOL QueryPerformanceFrequency :: #foreign (lpFrequency: *LARGE_INTEGER): BOOL
QueryPerformanceCounter :: #foreign (lpFrequency: *LARGE_INTEGER): BOOL QueryPerformanceCounter :: #foreign (lpFrequency: *LARGE_INTEGER): BOOL
Sleep :: #foreign (dwMilliseconds: DWORD) Sleep :: #foreign (dwMilliseconds: DWORD)
OutputDebugStringA :: #foreign (lpOutputString: LPCSTR) OutputDebugStringA :: #foreign (lpOutputString: LPCSTR)
CreateFileW :: #foreign (lpFileName: LPCWSTR, dwDesiredAccess: DWORD, dwShareMode: DWORD, lpSecurityAttributes: LPSECURITY_ATTRIBUTES, dwCreationDisposition: DWORD, dwFlagsAndAttributes: DWORD, hTemplateFile: HANDLE): HANDLE CreateFileW :: #foreign (lpFileName: LPCWSTR, dwDesiredAccess: DWORD, dwShareMode: DWORD, lpSecurityAttributes: LPSECURITY_ATTRIBUTES, dwCreationDisposition: DWORD, dwFlagsAndAttributes: DWORD, hTemplateFile: HANDLE): HANDLE
ReadFile :: #foreign (hFile: HANDLE, lpBuffer: LPVOID, nNumberOfBytesToRead: DWORD, lpNumberOfBytesRead: LPDWORD, lpOverlapped: LPOVERLAPPED): BOOL ReadFile :: #foreign (hFile: HANDLE, lpBuffer: LPVOID, nNumberOfBytesToRead: DWORD, lpNumberOfBytesRead: LPDWORD, lpOverlapped: LPOVERLAPPED): BOOL
CloseHandle :: #foreign (hObject: HANDLE): BOOL CloseHandle :: #foreign (hObject: HANDLE): BOOL
GetFileSizeEx :: #foreign (hFile: HANDLE, lpFileSize: PLARGE_INTEGER) GetFileSizeEx :: #foreign (hFile: HANDLE, lpFileSize: PLARGE_INTEGER)
OVERLAPPED :: struct OVERLAPPED :: struct
Internal: ULONG_PTR Internal: ULONG_PTR
InternalHigh: ULONG_PTR InternalHigh: ULONG_PTR
Pointer: PVOID Pointer: PVOID
hEvent: HANDLE hEvent: HANDLE
LPSECURITY_ATTRIBUTES :: *SECURITY_ATTRIBUTES LPSECURITY_ATTRIBUTES :: *SECURITY_ATTRIBUTES
SECURITY_ATTRIBUTES :: struct SECURITY_ATTRIBUTES :: struct
nLength: DWORD nLength: DWORD
lpSecurityDescriptor: LPVOID lpSecurityDescriptor: LPVOID
bInheritHandle: BOOL bInheritHandle: BOOL
GENERIC_READ :: 0x80000000 GENERIC_READ :: 0x80000000
GENERIC_WRITE :: 0x40000000 GENERIC_WRITE :: 0x40000000
GENERIC_EXECUTE :: 0x20000000 GENERIC_EXECUTE :: 0x20000000
GENERIC_ALL :: 0x10000000 GENERIC_ALL :: 0x10000000
CREATE_NEW :: 1 CREATE_NEW :: 1
CREATE_ALWAYS :: 2 CREATE_ALWAYS :: 2
OPEN_EXISTING :: 3 OPEN_EXISTING :: 3
OPEN_ALWAYS :: 4 OPEN_ALWAYS :: 4
TRUNCATE_EXISTING :: 5 TRUNCATE_EXISTING :: 5
FILE_SHARE_READ :: 0x00000001 FILE_SHARE_READ :: 0x00000001
FILE_SHARE_WRITE :: 0x00000002 FILE_SHARE_WRITE :: 0x00000002
FILE_SHARE_DELETE :: 0x00000004 FILE_SHARE_DELETE :: 0x00000004
// INVALID_HANDLE_VALUE :: ((-1)->LONG_PTR)->HANDLE // INVALID_HANDLE_VALUE :: ((-1)->LONG_PTR)->HANDLE
INVALID_HANDLE_VALUE :: (~(0->U64)) INVALID_HANDLE_VALUE :: (~(0->U64))
FILE_ATTRIBUTE_READONLY :: 0x00000001 FILE_ATTRIBUTE_READONLY :: 0x00000001
FILE_ATTRIBUTE_HIDDEN :: 0x00000002 FILE_ATTRIBUTE_HIDDEN :: 0x00000002
FILE_ATTRIBUTE_SYSTEM :: 0x00000004 FILE_ATTRIBUTE_SYSTEM :: 0x00000004
FILE_ATTRIBUTE_DIRECTORY :: 0x00000010 FILE_ATTRIBUTE_DIRECTORY :: 0x00000010
FILE_ATTRIBUTE_ARCHIVE :: 0x00000020 FILE_ATTRIBUTE_ARCHIVE :: 0x00000020
FILE_ATTRIBUTE_DEVICE :: 0x00000040 FILE_ATTRIBUTE_DEVICE :: 0x00000040
FILE_ATTRIBUTE_NORMAL :: 0x00000080 FILE_ATTRIBUTE_NORMAL :: 0x00000080
FILE_ATTRIBUTE_TEMPORARY :: 0x00000100 FILE_ATTRIBUTE_TEMPORARY :: 0x00000100
FILE_ATTRIBUTE_SPARSE_FILE :: 0x00000200 FILE_ATTRIBUTE_SPARSE_FILE :: 0x00000200
FILE_ATTRIBUTE_REPARSE_POINT :: 0x00000400 FILE_ATTRIBUTE_REPARSE_POINT :: 0x00000400
FILE_ATTRIBUTE_COMPRESSED :: 0x00000800 FILE_ATTRIBUTE_COMPRESSED :: 0x00000800
FILE_ATTRIBUTE_OFFLINE :: 0x00001000 FILE_ATTRIBUTE_OFFLINE :: 0x00001000
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED :: 0x00002000 FILE_ATTRIBUTE_NOT_CONTENT_INDEXED :: 0x00002000
FILE_ATTRIBUTE_ENCRYPTED :: 0x00004000 FILE_ATTRIBUTE_ENCRYPTED :: 0x00004000
FILE_ATTRIBUTE_INTEGRITY_STREAM :: 0x00008000 FILE_ATTRIBUTE_INTEGRITY_STREAM :: 0x00008000
FILE_ATTRIBUTE_VIRTUAL :: 0x00010000 FILE_ATTRIBUTE_VIRTUAL :: 0x00010000
FILE_ATTRIBUTE_NO_SCRUB_DATA :: 0x00020000 FILE_ATTRIBUTE_NO_SCRUB_DATA :: 0x00020000
FILE_ATTRIBUTE_EA :: 0x00040000 FILE_ATTRIBUTE_EA :: 0x00040000
FILE_ATTRIBUTE_PINNED :: 0x00080000 FILE_ATTRIBUTE_PINNED :: 0x00080000
FILE_ATTRIBUTE_UNPINNED :: 0x00100000 FILE_ATTRIBUTE_UNPINNED :: 0x00100000
FILE_ATTRIBUTE_RECALL_ON_OPEN :: 0x00040000 FILE_ATTRIBUTE_RECALL_ON_OPEN :: 0x00040000
FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS :: 0x00400000 FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS :: 0x00400000

View File

@@ -1,60 +1,60 @@
/* /*
Any :: struct Any :: struct
data: *void data: *void
type: Type type: Type
Type_Info_Kind :: enum Type_Info_Kind :: enum
S64 // FIRST_NUMERIC S64 // FIRST_NUMERIC
S32 S32
S16 S16
S8 S8
INT INT
CHAR CHAR
U64 U64
U32 U32
U16 U16
U8 U8
F32 F32
F64 F64
POINTER POINTER
BOOL // LAST_NUMERIC BOOL // LAST_NUMERIC
STRING STRING
VOID VOID
ARRAY ARRAY
LAMBDA LAMBDA
STRUCT STRUCT
UNION UNION
ENUM ENUM
TYPE TYPE
SLICE SLICE
TUPLE TUPLE
Type_Info_Struct_Member :: struct Type_Info_Struct_Member :: struct
name: String name: String
type: Type type: Type
offset: S64 offset: S64
Type_Info :: struct Type_Info :: struct
kind: Type_Info_Kind kind: Type_Info_Kind
size: S64 size: S64
align: S64 align: S64
is_unsigned: bool is_unsigned: bool
type: Type type: Type
base_type: Type base_type: Type
array_size: S64 array_size: S64
struct_members: *Type_Info_Struct_Member struct_members: *Type_Info_Struct_Member
struct_member_count: S64 struct_member_count: S64
lambda_arguments: *Type_Info lambda_arguments: *Type_Info
lambda_argument_count: S64 lambda_argument_count: S64
lambda_return: Type lambda_return: Type
type_infos_len: S64 #foreign type_infos_len: S64 #foreign
type_infos : *Type_Info #foreign type_infos : *Type_Info #foreign
GetTypeInfo :: (type: Type): *Type_Info GetTypeInfo :: (type: Type): *Type_Info
id := type->S64 id := type->S64
if id >= type_infos_len if id >= type_infos_len
return 0 return 0
return type_infos + id return type_infos + id
*/ */

View File

@@ -1,20 +1,20 @@
size_t :: U64 // @todo(Krzosa): Need this type size_t :: U64 // @todo(Krzosa): Need this type
malloc :: #foreign (size: size_t): *void malloc :: #foreign (size: size_t): *void
realloc :: #foreign (ptr: *void, size: size_t): *void realloc :: #foreign (ptr: *void, size: size_t): *void
free :: #foreign (ptr: *void) free :: #foreign (ptr: *void)
memset :: #foreign (ptr: *void, val: int, num: size_t): *void memset :: #foreign (ptr: *void, val: int, num: size_t): *void
memcpy :: #foreign (dst: *void, src: *void, size: size_t): *void memcpy :: #foreign (dst: *void, src: *void, size: size_t): *void
memmove :: #foreign (dst: *void, src: *void, size: size_t): *void memmove :: #foreign (dst: *void, src: *void, size: size_t): *void
FILE :: #strict U64 // Doesnt matter the type just handle FILE :: #strict U64 // Doesnt matter the type just handle
fopen :: #foreign (file: *char, mode: *char): *FILE fopen :: #foreign (file: *char, mode: *char): *FILE
fclose :: #foreign (file: *FILE): int fclose :: #foreign (file: *FILE): int
fseek :: #foreign (public_stream: *FILE, offset: long, whence: int): int fseek :: #foreign (public_stream: *FILE, offset: long, whence: int): int
ftell :: #foreign (public_stream: *FILE): long ftell :: #foreign (public_stream: *FILE): long
fread :: #foreign (buffer: *void, element_size: size_t, element_count: size_t, stream: *FILE): size_t fread :: #foreign (buffer: *void, element_size: size_t, element_count: size_t, stream: *FILE): size_t
SEEK_CUR :: 1 SEEK_CUR :: 1
SEEK_END :: 2 SEEK_END :: 2
SEEK_SET :: 0 SEEK_SET :: 0

View File

@@ -1,34 +1,34 @@
sqrtf :: #foreign (value: F32): F32 sqrtf :: #foreign (value: F32): F32
cosf :: #foreign (value: F32): F32 cosf :: #foreign (value: F32): F32
sinf :: #foreign (value: F32): F32 sinf :: #foreign (value: F32): F32
floorf :: #foreign (value: F32): F32 floorf :: #foreign (value: F32): F32
roundf :: #foreign (value: F32): F32 roundf :: #foreign (value: F32): F32
ceilf :: #foreign (value: F32): F32 ceilf :: #foreign (value: F32): F32
Floor :: floorf Floor :: floorf
Round :: roundf Round :: roundf
Ceil :: ceilf Ceil :: ceilf
SquareRoot :: sqrtf SquareRoot :: sqrtf
Cos :: cosf Cos :: cosf
Sin :: sinf Sin :: sinf
Clamp :: (min: F32, value: F32, max: F32): F32 Clamp :: (min: F32, value: F32, max: F32): F32
if value > max;; return max if value > max;; return max
if value < min;; return min if value < min;; return min
return value return value
ClampBottom :: (min: F32, value: F32): F32 ClampBottom :: (min: F32, value: F32): F32
if value < min;; return min if value < min;; return min
return value return value
Absolute :: (val: F32): F32 Absolute :: (val: F32): F32
if val < 0;; return -val if val < 0;; return -val
return val return val
Min :: (a: F32, b: F32): F32 Min :: (a: F32, b: F32): F32
if a > b ;; return b if a > b ;; return b
return a return a
Max :: (a: F32, b: F32): F32 Max :: (a: F32, b: F32): F32
if a > b ;; return a if a > b ;; return a
return b return b

View File

@@ -1,32 +1,32 @@
Vec2I :: struct;; x: int; y: int Vec2I :: struct;; x: int; y: int
Vec2 :: struct;; x: F32; y: F32 Vec2 :: struct;; x: F32; y: F32
"*" :: (a: Vec2, b: Vec2): Vec2 ;; return {a.x*b.x, a.y*b.y} "*" :: (a: Vec2, b: Vec2): Vec2 ;; return {a.x*b.x, a.y*b.y}
"*" :: (a: Vec2, b: F32) : Vec2 ;; return {a.x*b, a.y*b} "*" :: (a: Vec2, b: F32) : Vec2 ;; return {a.x*b, a.y*b}
"*" :: (a: F32, b: Vec2) : Vec2 ;; return {a*b.x, a*b.y} "*" :: (a: F32, b: Vec2) : Vec2 ;; return {a*b.x, a*b.y}
"-" :: (a: Vec2, b: Vec2): Vec2 ;; return {a.x-b.x, a.y-b.y} "-" :: (a: Vec2, b: Vec2): Vec2 ;; return {a.x-b.x, a.y-b.y}
"-" :: (a: Vec2, b: F32) : Vec2 ;; return {a.x-b, a.y-b} "-" :: (a: Vec2, b: F32) : Vec2 ;; return {a.x-b, a.y-b}
"-" :: (a: F32, b: Vec2) : Vec2 ;; return {a-b.x, a-b.y} "-" :: (a: F32, b: Vec2) : Vec2 ;; return {a-b.x, a-b.y}
"+" :: (a: Vec2, b: Vec2): Vec2 ;; return {a.x+b.x, a.y+b.y} "+" :: (a: Vec2, b: Vec2): Vec2 ;; return {a.x+b.x, a.y+b.y}
"+" :: (a: Vec2, b: F32) : Vec2 ;; return {a.x+b, a.y+b} "+" :: (a: Vec2, b: F32) : Vec2 ;; return {a.x+b, a.y+b}
"+" :: (a: F32, b: Vec2) : Vec2 ;; return {a+b.x, a+b.y} "+" :: (a: F32, b: Vec2) : Vec2 ;; return {a+b.x, a+b.y}
"/" :: (a: Vec2, b: Vec2): Vec2 ;; return {a.x/b.x, a.y/b.y} "/" :: (a: Vec2, b: Vec2): Vec2 ;; return {a.x/b.x, a.y/b.y}
"/" :: (a: Vec2, b: F32) : Vec2 ;; return {a.x/b, a.y/b} "/" :: (a: Vec2, b: F32) : Vec2 ;; return {a.x/b, a.y/b}
"/" :: (a: F32, b: Vec2) : Vec2 ;; return {a/b.x, a/b.y} "/" :: (a: F32, b: Vec2) : Vec2 ;; return {a/b.x, a/b.y}
"*" :: (a: Vec2I, b: Vec2I): Vec2I ;; return {a.x*b.x, a.y*b.y} "*" :: (a: Vec2I, b: Vec2I): Vec2I ;; return {a.x*b.x, a.y*b.y}
"*" :: (a: Vec2I, b: int) : Vec2I ;; return {a.x*b, a.y*b} "*" :: (a: Vec2I, b: int) : Vec2I ;; return {a.x*b, a.y*b}
"*" :: (a: int, b: Vec2I) : Vec2I ;; return {a*b.x, a*b.y} "*" :: (a: int, b: Vec2I) : Vec2I ;; return {a*b.x, a*b.y}
"-" :: (a: Vec2I, b: Vec2I): Vec2I ;; return {a.x-b.x, a.y-b.y} "-" :: (a: Vec2I, b: Vec2I): Vec2I ;; return {a.x-b.x, a.y-b.y}
"-" :: (a: Vec2I, b: int) : Vec2I ;; return {a.x-b, a.y-b} "-" :: (a: Vec2I, b: int) : Vec2I ;; return {a.x-b, a.y-b}
"-" :: (a: int, b: Vec2I) : Vec2I ;; return {a-b.x, a-b.y} "-" :: (a: int, b: Vec2I) : Vec2I ;; return {a-b.x, a-b.y}
"+" :: (a: Vec2I, b: Vec2I): Vec2I ;; return {a.x+b.x, a.y+b.y} "+" :: (a: Vec2I, b: Vec2I): Vec2I ;; return {a.x+b.x, a.y+b.y}
"+" :: (a: Vec2I, b: int) : Vec2I ;; return {a.x+b, a.y+b} "+" :: (a: Vec2I, b: int) : Vec2I ;; return {a.x+b, a.y+b}
"+" :: (a: int, b: Vec2I) : Vec2I ;; return {a+b.x, a+b.y} "+" :: (a: int, b: Vec2I) : Vec2I ;; return {a+b.x, a+b.y}
"/" :: (a: Vec2I, b: Vec2I): Vec2I ;; return {a.x/b.x, a.y/b.y} "/" :: (a: Vec2I, b: Vec2I): Vec2I ;; return {a.x/b.x, a.y/b.y}
"/" :: (a: Vec2I, b: int) : Vec2I ;; return {a.x/b, a.y/b} "/" :: (a: Vec2I, b: int) : Vec2I ;; return {a.x/b, a.y/b}
"/" :: (a: int, b: Vec2I) : Vec2I ;; return {a/b.x, a/b.y} "/" :: (a: int, b: Vec2I) : Vec2I ;; return {a/b.x, a/b.y}
FloorVec2ToVec2I :: (a: Vec2): Vec2I ;; return {floorf(a.x)->int, floorf(a.y)->int} FloorVec2ToVec2I :: (a: Vec2): Vec2I ;; return {floorf(a.x)->int, floorf(a.y)->int}
CastVec2ToVec2I :: (a: Vec2): Vec2I ;; return {a.x->int, a.y->int} CastVec2ToVec2I :: (a: Vec2): Vec2I ;; return {a.x->int, a.y->int}

View File

@@ -1,46 +1,46 @@
#import "MathF32.core" #import "MathF32.core"
Vec3 :: struct ;; x: F32; y: F32; z: F32 Vec3 :: struct ;; x: F32; y: F32; z: F32
Length :: (a: Vec3): F32 ;; return sqrtf(a.x*a.x + a.y*a.y + a.z*a.z) Length :: (a: Vec3): F32 ;; return sqrtf(a.x*a.x + a.y*a.y + a.z*a.z)
Negate :: (a: Vec3): Vec3 ;; return {-a.x, -a.y, -a.z} Negate :: (a: Vec3): Vec3 ;; return {-a.x, -a.y, -a.z}
Dot :: (a: Vec3, b: Vec3): F32 ;; return a.x*b.x + a.y*b.y + a.z*b.z Dot :: (a: Vec3, b: Vec3): F32 ;; return a.x*b.x + a.y*b.y + a.z*b.z
"*" :: (a: Vec3, b: Vec3): Vec3 ;; return {a.x*b.x, a.y*b.y, a.z*b.z} "*" :: (a: Vec3, b: Vec3): Vec3 ;; return {a.x*b.x, a.y*b.y, a.z*b.z}
"*" :: (a: Vec3, b: F32) : Vec3 ;; return {a.x*b, a.y*b, a.z*b} "*" :: (a: Vec3, b: F32) : Vec3 ;; return {a.x*b, a.y*b, a.z*b}
"*" :: (a: F32, b: Vec3) : Vec3 ;; return {a*b.x, a*b.y, a*b.z} "*" :: (a: F32, b: Vec3) : Vec3 ;; return {a*b.x, a*b.y, a*b.z}
"-" :: (a: Vec3, b: Vec3): Vec3 ;; return {a.x-b.x, a.y-b.y, a.z-b.z} "-" :: (a: Vec3, b: Vec3): Vec3 ;; return {a.x-b.x, a.y-b.y, a.z-b.z}
"-" :: (a: Vec3, b: F32) : Vec3 ;; return {a.x-b, a.y-b, a.z-b} "-" :: (a: Vec3, b: F32) : Vec3 ;; return {a.x-b, a.y-b, a.z-b}
"-" :: (a: F32, b: Vec3) : Vec3 ;; return {a-b.x, a-b.y, a-b.z} "-" :: (a: F32, b: Vec3) : Vec3 ;; return {a-b.x, a-b.y, a-b.z}
"+" :: (a: Vec3, b: Vec3): Vec3 ;; return {a.x+b.x, a.y+b.y, a.z+b.z} "+" :: (a: Vec3, b: Vec3): Vec3 ;; return {a.x+b.x, a.y+b.y, a.z+b.z}
"+" :: (a: Vec3, b: F32) : Vec3 ;; return {a.x+b, a.y+b, a.z+b} "+" :: (a: Vec3, b: F32) : Vec3 ;; return {a.x+b, a.y+b, a.z+b}
"+" :: (a: F32, b: Vec3) : Vec3 ;; return {a+b.x, a+b.y, a+b.z} "+" :: (a: F32, b: Vec3) : Vec3 ;; return {a+b.x, a+b.y, a+b.z}
"/" :: (a: Vec3, b: Vec3): Vec3 ;; return {a.x/b.x, a.y/b.y, a.z/b.z} "/" :: (a: Vec3, b: Vec3): Vec3 ;; return {a.x/b.x, a.y/b.y, a.z/b.z}
"/" :: (a: Vec3, b: F32) : Vec3 ;; return {a.x/b, a.y/b, a.z/b} "/" :: (a: Vec3, b: F32) : Vec3 ;; return {a.x/b, a.y/b, a.z/b}
"/" :: (a: F32, b: Vec3) : Vec3 ;; return {a/b.x, a/b.y, a/b.z} "/" :: (a: F32, b: Vec3) : Vec3 ;; return {a/b.x, a/b.y, a/b.z}
Cross :: (a: Vec3, b: Vec3): Vec3 Cross :: (a: Vec3, b: Vec3): Vec3
result := Vec3{ result := Vec3{
a.y * b.z - a.z * b.y, a.y * b.z - a.z * b.y,
a.z * b.x - a.x * b.z, a.z * b.x - a.x * b.z,
a.x * b.y - a.y * b.x, a.x * b.y - a.y * b.x,
} }
return result return result
Normalize :: (a: Vec3): Vec3 Normalize :: (a: Vec3): Vec3
length := Length(a) length := Length(a)
result := a / length result := a / length
return result return result
Reflect :: (a: Vec3, normal: Vec3): Vec3 Reflect :: (a: Vec3, normal: Vec3): Vec3
an := Dot(a, normal)*2 an := Dot(a, normal)*2
result := a - a * an result := a - a * an
return result return result
ConvertToARGB :: (a: Vec3): U32 ConvertToARGB :: (a: Vec3): U32
a.x = Clamp(0, a.x, 1) a.x = Clamp(0, a.x, 1)
a.y = Clamp(0, a.y, 1) a.y = Clamp(0, a.y, 1)
a.z = Clamp(0, a.z, 1) a.z = Clamp(0, a.z, 1)
r := (a.x * 255)->U32 << 16 r := (a.x * 255)->U32 << 16
g := (a.y * 255)->U32 << 8 g := (a.y * 255)->U32 << 8
b := (a.z * 255)->U32 << 0 b := (a.z * 255)->U32 << 0
result := r | g | b result := r | g | b
return result return result

View File

@@ -1,64 +1,64 @@
/* /*
Library for making games/graphical applications Library for making games/graphical applications
* The api is very simple, very few function calls * The api is very simple, very few function calls
* You retrieve information about the state of application from "Mu" struct * You retrieve information about the state of application from "Mu" struct
* Data is available in many different formats to avoid format conversions in user code * Data is available in many different formats to avoid format conversions in user code
API and name inspired by one of Per Vognsen streams API and name inspired by one of Per Vognsen streams
https://www.youtube.com/watch?v=NG_mUhc8LRw&list=PLU94OURih-CjrtFuazwZ5GYzTrupOMDL7&index=19 https://www.youtube.com/watch?v=NG_mUhc8LRw&list=PLU94OURih-CjrtFuazwZ5GYzTrupOMDL7&index=19
All of his channel is recommended watch for programmers. All of his channel is recommended watch for programmers.
*/ */
Mu: MU Mu: MU
MU :: struct MU :: struct
screen: *U32 screen: *U32
window: MUWindow window: MUWindow
key: [Key.Count]KeyState key: [Key.Count]KeyState
mouse: Mouse mouse: Mouse
frame_count: U64 frame_count: U64
time: MUTime time: MUTime
quit: bool quit: bool
frame_arena: Arena frame_arena: Arena
os: Platform os: Platform
MUWindow :: struct MUWindow :: struct
x: int x: int
y: int y: int
sizef: Vec2 sizef: Vec2
size: Vec2I size: Vec2I
resizable: bool resizable: bool
MUTime :: struct MUTime :: struct
total : F64 total : F64
delta : F64 // @modifiable delta : F64 // @modifiable
start : F64 start : F64
frame_start: F64 frame_start: F64
KeyState :: struct KeyState :: struct
down: bool down: bool
Key :: enum Key :: enum
None None
Up;Down;Left;Right;Escape;Control;Backspace;Alt;Shift;Tab Up;Down;Left;Right;Escape;Control;Backspace;Alt;Shift;Tab
F1;F2;F3;F4;F5;F6;F7;F8;F9;F10 F1;F2;F3;F4;F5;F6;F7;F8;F9;F10
F11;F12;A;B;C;D;E;F;G;H F11;F12;A;B;C;D;E;F;G;H
I;J;K;L;M;N;O;P;Q;R I;J;K;L;M;N;O;P;Q;R
S;T;U;V;W;X;Y;Z;K0;K1 S;T;U;V;W;X;Y;Z;K0;K1
K2;K3;K4;K5;K6;K7;K8;K9 K2;K3;K4;K5;K6;K7;K8;K9
Count Count
Mouse :: struct Mouse :: struct
left: KeyState left: KeyState
right: KeyState right: KeyState
middle: KeyState middle: KeyState
wheel: int wheel: int
#import "Base.core" #import "Base.core"
#import "MathF32.core" #import "MathF32.core"
#import "MathVec2.core" #import "MathVec2.core"
#import "Arena.core" #import "Arena.core"
#load "$os_multimedia.core" #load "$os_multimedia.core"

View File

@@ -1,65 +1,65 @@
#import "KERNEL32.core" #import "KERNEL32.core"
#import "Base.core" #import "Base.core"
PAGE_SIZE :: 4096 PAGE_SIZE :: 4096
Memory :: struct Memory :: struct
commit : SizeU commit : SizeU
reserve: SizeU reserve: SizeU
data : *U8 data : *U8
ProcessHeap: HANDLE ProcessHeap: HANDLE
Allocate :: (size: U64): *void Allocate :: (size: U64): *void
if ProcessHeap == 0 if ProcessHeap == 0
ProcessHeap = GetProcessHeap() ProcessHeap = GetProcessHeap()
return HeapAlloc(ProcessHeap, 0, size) return HeapAlloc(ProcessHeap, 0, size)
Reserve :: (size: SizeU): Memory Reserve :: (size: SizeU): Memory
result := Memory{reserve=AlignUp(size, PAGE_SIZE)} result := Memory{reserve=AlignUp(size, PAGE_SIZE)}
result.data = VirtualAlloc( result.data = VirtualAlloc(
flProtect = PAGE_READWRITE, flProtect = PAGE_READWRITE,
dwSize = result.reserve, dwSize = result.reserve,
flAllocationType = MEM_RESERVE, flAllocationType = MEM_RESERVE,
lpAddress = 0)->*U8 lpAddress = 0)->*U8
return result return result
Commit :: (m: *Memory, size: SizeU): bool Commit :: (m: *Memory, size: SizeU): bool
commit_size := AlignUp(size, PAGE_SIZE) commit_size := AlignUp(size, PAGE_SIZE)
total_commit := m.commit + commit_size total_commit := m.commit + commit_size
clamped_commit := ClampTopSizeU(total_commit, m.reserve) clamped_commit := ClampTopSizeU(total_commit, m.reserve)
adjusted_commit := clamped_commit - m.commit adjusted_commit := clamped_commit - m.commit
if adjusted_commit != 0 if adjusted_commit != 0
result := VirtualAlloc( result := VirtualAlloc(
lpAddress = (m.data + m.commit)->*void, lpAddress = (m.data + m.commit)->*void,
dwSize = adjusted_commit, dwSize = adjusted_commit,
flAllocationType = MEM_COMMIT, flAllocationType = MEM_COMMIT,
flProtect = PAGE_READWRITE, flProtect = PAGE_READWRITE,
) )
Assert(result != 0) Assert(result != 0)
m.commit += adjusted_commit m.commit += adjusted_commit
return true return true
return false return false
Release :: (m: *Memory) Release :: (m: *Memory)
result := VirtualFree(m.data->*void, 0, MEM_RELEASE) result := VirtualFree(m.data->*void, 0, MEM_RELEASE)
if result != 0 if result != 0
m.data = 0 m.data = 0
m.commit = 0 m.commit = 0
m.reserve = 0 m.reserve = 0
WriteConsole :: (string: String16) WriteConsole :: (string: String16)
handle := GetStdHandle(STD_OUTPUT_HANDLE) handle := GetStdHandle(STD_OUTPUT_HANDLE)
WriteConsoleW(handle, string.str->*void, string.len->DWORD, 0, 0) WriteConsoleW(handle, string.str->*void, string.len->DWORD, 0, 0)
PerformanceFrequency: F64 PerformanceFrequency: F64
PerformanceFrequency_S64: S64 PerformanceFrequency_S64: S64
Time :: (): F64 Time :: (): F64
query: LARGE_INTEGER query: LARGE_INTEGER
if PerformanceFrequency_S64 == 0 if PerformanceFrequency_S64 == 0
err := QueryPerformanceFrequency(&PerformanceFrequency_S64) err := QueryPerformanceFrequency(&PerformanceFrequency_S64)
Assert(err != 0) Assert(err != 0)
PerformanceFrequency = PerformanceFrequency_S64->F64 PerformanceFrequency = PerformanceFrequency_S64->F64
err := QueryPerformanceCounter(&query) err := QueryPerformanceCounter(&query)
Assert(err != 0) Assert(err != 0)
result := query->F64 / PerformanceFrequency result := query->F64 / PerformanceFrequency
return result return result

View File

@@ -1,200 +1,200 @@
#import "KERNEL32.core" #import "KERNEL32.core"
#link "user32" #link "user32"
WNDPROC :: (hwnd: HWND, uMsg: UINT, wParam: WPARAM, lParam: LPARAM): LRESULT WNDPROC :: (hwnd: HWND, uMsg: UINT, wParam: WPARAM, lParam: LPARAM): LRESULT
WNDCLASSW :: struct;; style: UINT; lpfnWndProc: WNDPROC; cbClsExtra: int; cbWndExtra: int; hInstance: HINSTANCE; hIcon: HICON; hCursor: HCURSOR; hbrBackground: HBRUSH; lpszMenuName: LPCWSTR; lpszClassName: LPCWSTR WNDCLASSW :: struct;; style: UINT; lpfnWndProc: WNDPROC; cbClsExtra: int; cbWndExtra: int; hInstance: HINSTANCE; hIcon: HICON; hCursor: HCURSOR; hbrBackground: HBRUSH; lpszMenuName: LPCWSTR; lpszClassName: LPCWSTR
MSG :: struct;; hwnd: HWND; message: UINT; wParam: WPARAM; lParam: LPARAM; time: DWORD; pt: POINT; lPrivate: DWORD MSG :: struct;; hwnd: HWND; message: UINT; wParam: WPARAM; lParam: LPARAM; time: DWORD; pt: POINT; lPrivate: DWORD
POINT :: struct;; x: LONG; y: LONG POINT :: struct;; x: LONG; y: LONG
LPMSG :: *MSG LPMSG :: *MSG
RECT :: struct;; left: LONG; top: LONG; right: LONG; bottom: LONG RECT :: struct;; left: LONG; top: LONG; right: LONG; bottom: LONG
LPRECT :: *RECT LPRECT :: *RECT
PostQuitMessage :: #foreign (nExitCode: int) PostQuitMessage :: #foreign (nExitCode: int)
DefWindowProcW :: #foreign (hwnd: HWND, uMsg: UINT, wParam: WPARAM, lParam: LPARAM): LRESULT DefWindowProcW :: #foreign (hwnd: HWND, uMsg: UINT, wParam: WPARAM, lParam: LPARAM): LRESULT
GetDC :: #foreign (hWnd: HWND): HDC GetDC :: #foreign (hWnd: HWND): HDC
CreateWindowA :: #foreign (dwExStyle: DWORD, lpClassName: *char, lpWindowName: *char, dwStyle: DWORD, X: int, Y: int, nWidth: int, nHeight: int, hWndParent: HWND, hMenu: HMENU, hInstance: HINSTANCE, lpParam: *void): HWND CreateWindowA :: #foreign (dwExStyle: DWORD, lpClassName: *char, lpWindowName: *char, dwStyle: DWORD, X: int, Y: int, nWidth: int, nHeight: int, hWndParent: HWND, hMenu: HMENU, hInstance: HINSTANCE, lpParam: *void): HWND
CreateWindowExW :: #foreign (dwExStyle: DWORD, lpClassName: LPCWSTR, lpWindowName: LPCWSTR, dwStyle: DWORD, X: int, Y: int, nWidth: int, nHeight: int, hWndParent: HWND, hMenu: HMENU, hInstance: HINSTANCE, lpParam: LPVOID): HWND CreateWindowExW :: #foreign (dwExStyle: DWORD, lpClassName: LPCWSTR, lpWindowName: LPCWSTR, dwStyle: DWORD, X: int, Y: int, nWidth: int, nHeight: int, hWndParent: HWND, hMenu: HMENU, hInstance: HINSTANCE, lpParam: LPVOID): HWND
RegisterClassW :: #foreign (lpWndClass: *WNDCLASSW): ATOM RegisterClassW :: #foreign (lpWndClass: *WNDCLASSW): ATOM
ShowWindow :: #foreign (hWnd: HWND, nCmdShow: int): BOOL ShowWindow :: #foreign (hWnd: HWND, nCmdShow: int): BOOL
PeekMessageW :: #foreign (lpMsg: LPMSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT, wRemoveMs: UINT):BOOL PeekMessageW :: #foreign (lpMsg: LPMSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT, wRemoveMs: UINT):BOOL
TranslateMessage :: #foreign (lpMsg: *MSG): BOOL TranslateMessage :: #foreign (lpMsg: *MSG): BOOL
DispatchMessageW :: #foreign (lpMsg: *MSG): LRESULT DispatchMessageW :: #foreign (lpMsg: *MSG): LRESULT
SetProcessDPIAware:: #foreign (): BOOL SetProcessDPIAware:: #foreign (): BOOL
GetDpiForWindow :: #foreign (hwnd: HWND): UINT GetDpiForWindow :: #foreign (hwnd: HWND): UINT
AdjustWindowRectExForDpi :: #foreign (lpRect: *RECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD, dpi: UINT): BOOL AdjustWindowRectExForDpi :: #foreign (lpRect: *RECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD, dpi: UINT): BOOL
AdjustWindowRectEx :: #foreign (lpRect: *RECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD): BOOL AdjustWindowRectEx :: #foreign (lpRect: *RECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD): BOOL
SetWindowPos :: #foreign (hWnd: HWND, hWndInsertAfter: HWND, X: int, Y: int, cx: int, cy: int, uFlags: UINT): BOOL SetWindowPos :: #foreign (hWnd: HWND, hWndInsertAfter: HWND, X: int, Y: int, cx: int, cy: int, uFlags: UINT): BOOL
GetClientRect :: #foreign (hWnd: HWND, lpRect: LPRECT): BOOL GetClientRect :: #foreign (hWnd: HWND, lpRect: LPRECT): BOOL
CW_USEDEFAULT :: 0x80000000-1 // -2147483648 CW_USEDEFAULT :: 0x80000000-1 // -2147483648
WS_CAPTION :: 0x00C00000 WS_CAPTION :: 0x00C00000
WS_CHILD :: 0x40000000 WS_CHILD :: 0x40000000
WS_CHILDWINDOW :: 0x40000000 WS_CHILDWINDOW :: 0x40000000
WS_CLIPCHILDREN :: 0x02000000 WS_CLIPCHILDREN :: 0x02000000
WS_CLIPSIBLINGS :: 0x04000000 WS_CLIPSIBLINGS :: 0x04000000
WS_DISABLED :: 0x08000000 WS_DISABLED :: 0x08000000
WS_DLGFRAME :: 0x00400000 WS_DLGFRAME :: 0x00400000
WS_GROUP :: 0x00020000 WS_GROUP :: 0x00020000
WS_HSCROLL :: 0x00100000 WS_HSCROLL :: 0x00100000
WS_ICONIC :: 0x20000000 WS_ICONIC :: 0x20000000
WS_MAXIMIZE :: 0x01000000 WS_MAXIMIZE :: 0x01000000
WS_MAXIMIZEBOX :: 0x00010000 WS_MAXIMIZEBOX :: 0x00010000
WS_MINIMIZE :: 0x20000000 WS_MINIMIZE :: 0x20000000
WS_MINIMIZEBOX :: 0x00020000 WS_MINIMIZEBOX :: 0x00020000
WS_OVERLAPPED :: 0x00000000 WS_OVERLAPPED :: 0x00000000
WS_POPUP :: 0x80000000 WS_POPUP :: 0x80000000
WS_SIZEBOX :: 0x00040000 WS_SIZEBOX :: 0x00040000
WS_SYSMENU :: 0x00080000 WS_SYSMENU :: 0x00080000
WS_TABSTOP :: 0x00010000 WS_TABSTOP :: 0x00010000
WS_THICKFRAME :: 0x00040000 WS_THICKFRAME :: 0x00040000
WS_TILED :: 0x00000000 WS_TILED :: 0x00000000
WS_VISIBLE :: 0x10000000 WS_VISIBLE :: 0x10000000
WS_VSCROLL :: 0x00200000 WS_VSCROLL :: 0x00200000
WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
PM_NOREMOVE :: 0 PM_NOREMOVE :: 0
PM_REMOVE :: 0x0001 PM_REMOVE :: 0x0001
PM_NOYIELD :: 0x0002 PM_NOYIELD :: 0x0002
SW_HIDE :: 0 SW_HIDE :: 0
SW_NORMAL :: 1 SW_NORMAL :: 1
SW_SHOWMINIMIZED :: 2 SW_SHOWMINIMIZED :: 2
SW_SHOWMAXIMIZED :: 3 SW_SHOWMAXIMIZED :: 3
SW_SHOWNOACTIVATE :: 4 SW_SHOWNOACTIVATE :: 4
SW_SHOW :: 5 SW_SHOW :: 5
SW_MINIMIZE :: 6 SW_MINIMIZE :: 6
SW_SHOWMINNOACTIVE :: 7 SW_SHOWMINNOACTIVE :: 7
SW_SHOWNA :: 8 SW_SHOWNA :: 8
SW_RESTORE :: 9 SW_RESTORE :: 9
SW_SHOWDEFAULT :: 10 SW_SHOWDEFAULT :: 10
SW_FORCEMINIMIZE :: 11 SW_FORCEMINIMIZE :: 11
HWND_TOP :: 0 HWND_TOP :: 0
HWND_BOTTOM :: 1 HWND_BOTTOM :: 1
// HWND_NOTOPMOST :: -2 // Probably relies on overflow ? // HWND_NOTOPMOST :: -2 // Probably relies on overflow ?
// HWND_TOPMOST :: -1 // Probably relies on overflow ? // HWND_TOPMOST :: -1 // Probably relies on overflow ?
SWP_ASYNCWINDOWPOS :: 0x4000 SWP_ASYNCWINDOWPOS :: 0x4000
SWP_DEFERERASE :: 0x2000 SWP_DEFERERASE :: 0x2000
SWP_DRAWFRAME :: 0x0020 SWP_DRAWFRAME :: 0x0020
SWP_FRAMECHANGED :: 0x0020 SWP_FRAMECHANGED :: 0x0020
SWP_HIDEWINDOW :: 0x0080 SWP_HIDEWINDOW :: 0x0080
SWP_NOACTIVATE :: 0x0010 SWP_NOACTIVATE :: 0x0010
SWP_NOCOPYBITS :: 0x0100 SWP_NOCOPYBITS :: 0x0100
SWP_NOMOVE :: 0x0002 SWP_NOMOVE :: 0x0002
SWP_NOOWNERZORDER :: 0x0200 SWP_NOOWNERZORDER :: 0x0200
SWP_NOREDRAW :: 0x0008 SWP_NOREDRAW :: 0x0008
SWP_NOREPOSITION :: 0x0200 SWP_NOREPOSITION :: 0x0200
SWP_NOSENDCHANGING :: 0x0400 SWP_NOSENDCHANGING :: 0x0400
SWP_NOSIZE :: 0x0001 SWP_NOSIZE :: 0x0001
SWP_NOZORDER :: 0x0004 SWP_NOZORDER :: 0x0004
SWP_SHOWWINDOW :: 0x0040 SWP_SHOWWINDOW :: 0x0040
WM_NULL :: 0x0000; WM_CREATE :: 0x0001; WM_DESTROY :: 0x0002; WM_MOVE :: 0x0003; WM_SIZE :: 0x0005 WM_NULL :: 0x0000; WM_CREATE :: 0x0001; WM_DESTROY :: 0x0002; WM_MOVE :: 0x0003; WM_SIZE :: 0x0005
WM_ACTIVATE :: 0x0006; WA_INACTIVE :: 0; WA_ACTIVE :: 1; WA_CLICKACTIVE :: 2 WM_ACTIVATE :: 0x0006; WA_INACTIVE :: 0; WA_ACTIVE :: 1; WA_CLICKACTIVE :: 2
WM_SETFOCUS :: 0x0007; WM_KILLFOCUS :: 0x0008; WM_ENABLE :: 0x000A; WM_SETREDRAW :: 0x000B; WM_SETTEXT :: 0x000C; WM_GETTEXT :: 0x000D; WM_GETTEXTLENGTH :: 0x000E; WM_PAINT :: 0x000F; WM_CLOSE :: 0x0010 WM_SETFOCUS :: 0x0007; WM_KILLFOCUS :: 0x0008; WM_ENABLE :: 0x000A; WM_SETREDRAW :: 0x000B; WM_SETTEXT :: 0x000C; WM_GETTEXT :: 0x000D; WM_GETTEXTLENGTH :: 0x000E; WM_PAINT :: 0x000F; WM_CLOSE :: 0x0010
WM_KEYFIRST :: 0x0100 WM_KEYFIRST :: 0x0100
WM_KEYDOWN :: 0x0100 WM_KEYDOWN :: 0x0100
WM_KEYUP :: 0x0101 WM_KEYUP :: 0x0101
WM_CHAR :: 0x0102 WM_CHAR :: 0x0102
WM_DEADCHAR :: 0x0103 WM_DEADCHAR :: 0x0103
WM_SYSKEYDOWN :: 0x0104 WM_SYSKEYDOWN :: 0x0104
WM_SYSKEYUP :: 0x0105 WM_SYSKEYUP :: 0x0105
WM_SYSCHAR :: 0x0106 WM_SYSCHAR :: 0x0106
WM_SYSDEADCHAR :: 0x0107 WM_SYSDEADCHAR :: 0x0107
WM_MOUSEFIRST :: 0x0200 WM_MOUSEFIRST :: 0x0200
WM_MOUSEMOVE :: 0x0200 WM_MOUSEMOVE :: 0x0200
WM_LBUTTONDOWN :: 0x0201 WM_LBUTTONDOWN :: 0x0201
WM_LBUTTONUP :: 0x0202 WM_LBUTTONUP :: 0x0202
WM_LBUTTONDBLCLK :: 0x0203 WM_LBUTTONDBLCLK :: 0x0203
WM_RBUTTONDOWN :: 0x0204 WM_RBUTTONDOWN :: 0x0204
WM_RBUTTONUP :: 0x0205 WM_RBUTTONUP :: 0x0205
WM_RBUTTONDBLCLK :: 0x0206 WM_RBUTTONDBLCLK :: 0x0206
WM_MBUTTONDOWN :: 0x0207 WM_MBUTTONDOWN :: 0x0207
WM_MBUTTONUP :: 0x0208 WM_MBUTTONUP :: 0x0208
WM_MBUTTONDBLCLK :: 0x0209 WM_MBUTTONDBLCLK :: 0x0209
WM_MOUSEWHEEL :: 0x020A WM_MOUSEWHEEL :: 0x020A
VK_BACK :: 0x08 VK_BACK :: 0x08
VK_TAB :: 0x09 VK_TAB :: 0x09
VK_CLEAR :: 0x0C VK_CLEAR :: 0x0C
VK_RETURN :: 0x0D VK_RETURN :: 0x0D
VK_SHIFT :: 0x10 VK_SHIFT :: 0x10
VK_CONTROL :: 0x11 VK_CONTROL :: 0x11
VK_MENU :: 0x12 VK_MENU :: 0x12
VK_PAUSE :: 0x13 VK_PAUSE :: 0x13
VK_CAPITAL :: 0x14 VK_CAPITAL :: 0x14
VK_KANA :: 0x15 VK_KANA :: 0x15
VK_HANGEUL :: 0x15 /* old name - should be here for compatibility */ VK_HANGEUL :: 0x15 /* old name - should be here for compatibility */
VK_HANGUL :: 0x15 VK_HANGUL :: 0x15
VK_IME_ON :: 0x16 VK_IME_ON :: 0x16
VK_JUNJA :: 0x17 VK_JUNJA :: 0x17
VK_FINAL :: 0x18 VK_FINAL :: 0x18
VK_HANJA :: 0x19 VK_HANJA :: 0x19
VK_KANJI :: 0x19 VK_KANJI :: 0x19
VK_IME_OFF :: 0x1A VK_IME_OFF :: 0x1A
VK_ESCAPE :: 0x1B VK_ESCAPE :: 0x1B
VK_CONVERT :: 0x1C VK_CONVERT :: 0x1C
VK_NONCONVERT :: 0x1D VK_NONCONVERT :: 0x1D
VK_ACCEPT :: 0x1E VK_ACCEPT :: 0x1E
VK_MODECHANGE :: 0x1F VK_MODECHANGE :: 0x1F
VK_SPACE :: 0x20 VK_SPACE :: 0x20
VK_PRIOR :: 0x21 VK_PRIOR :: 0x21
VK_NEXT :: 0x22 VK_NEXT :: 0x22
VK_END :: 0x23 VK_END :: 0x23
VK_HOME :: 0x24 VK_HOME :: 0x24
VK_LEFT :: 0x25 VK_LEFT :: 0x25
VK_UP :: 0x26 VK_UP :: 0x26
VK_RIGHT :: 0x27 VK_RIGHT :: 0x27
VK_DOWN :: 0x28 VK_DOWN :: 0x28
VK_SELECT :: 0x29 VK_SELECT :: 0x29
VK_PRINT :: 0x2A VK_PRINT :: 0x2A
VK_EXECUTE :: 0x2B VK_EXECUTE :: 0x2B
VK_SNAPSHOT :: 0x2C VK_SNAPSHOT :: 0x2C
VK_INSERT :: 0x2D VK_INSERT :: 0x2D
VK_DELETE :: 0x2E VK_DELETE :: 0x2E
VK_HELP :: 0x2F VK_HELP :: 0x2F
/* /*
* VK_0 - VK_9 are the same as ASCII '0' - '9' (0x30 - 0x39) * VK_0 - VK_9 are the same as ASCII '0' - '9' (0x30 - 0x39)
* 0x3A - 0x40 : unassigned * 0x3A - 0x40 : unassigned
* VK_A - VK_Z are the same as ASCII 'A' - 'Z' (0x41 - 0x5A) * VK_A - VK_Z are the same as ASCII 'A' - 'Z' (0x41 - 0x5A)
*/ */
VK_LWIN :: 0x5B VK_LWIN :: 0x5B
VK_RWIN :: 0x5C VK_RWIN :: 0x5C
VK_APPS :: 0x5D VK_APPS :: 0x5D
VK_SLEEP :: 0x5F VK_SLEEP :: 0x5F
VK_NUMPAD0 :: 0x60 VK_NUMPAD0 :: 0x60
VK_NUMPAD1 :: 0x61 VK_NUMPAD1 :: 0x61
VK_NUMPAD2 :: 0x62 VK_NUMPAD2 :: 0x62
VK_NUMPAD3 :: 0x63 VK_NUMPAD3 :: 0x63
VK_NUMPAD4 :: 0x64 VK_NUMPAD4 :: 0x64
VK_NUMPAD5 :: 0x65 VK_NUMPAD5 :: 0x65
VK_NUMPAD6 :: 0x66 VK_NUMPAD6 :: 0x66
VK_NUMPAD7 :: 0x67 VK_NUMPAD7 :: 0x67
VK_NUMPAD8 :: 0x68 VK_NUMPAD8 :: 0x68
VK_NUMPAD9 :: 0x69 VK_NUMPAD9 :: 0x69
VK_MULTIPLY :: 0x6A VK_MULTIPLY :: 0x6A
VK_ADD :: 0x6B VK_ADD :: 0x6B
VK_SEPARATOR :: 0x6C VK_SEPARATOR :: 0x6C
VK_SUBTRACT :: 0x6D VK_SUBTRACT :: 0x6D
VK_DECIMAL :: 0x6E VK_DECIMAL :: 0x6E
VK_DIVIDE :: 0x6F VK_DIVIDE :: 0x6F
VK_F1 :: 0x70 VK_F1 :: 0x70
VK_F2 :: 0x71 VK_F2 :: 0x71
VK_F3 :: 0x72 VK_F3 :: 0x72
VK_F4 :: 0x73 VK_F4 :: 0x73
VK_F5 :: 0x74 VK_F5 :: 0x74
VK_F6 :: 0x75 VK_F6 :: 0x75
VK_F7 :: 0x76 VK_F7 :: 0x76
VK_F8 :: 0x77 VK_F8 :: 0x77
VK_F9 :: 0x78 VK_F9 :: 0x78
VK_F10 :: 0x79 VK_F10 :: 0x79
VK_F11 :: 0x7A VK_F11 :: 0x7A
VK_F12 :: 0x7B VK_F12 :: 0x7B

View File

@@ -1,6 +1,6 @@
#import "KERNEL32.core" #import "KERNEL32.core"
#link "winmm" #link "winmm"
MMRESULT :: UINT MMRESULT :: UINT
TIMERR_NOERROR :: 0 TIMERR_NOERROR :: 0
timeBeginPeriod :: #foreign (uPeriod: UINT): MMRESULT timeBeginPeriod :: #foreign (uPeriod: UINT): MMRESULT

View File

@@ -1,101 +1,101 @@
#import "LibC.core" #import "LibC.core"
Array :: struct($T: Type) Array :: struct($T: Type)
data: *T data: *T
len: int len: int
cap: int cap: int
Pop :: (a: *Array($T)): T Pop :: (a: *Array($T)): T
if a.len > 0 if a.len > 0
a.len -= 1 a.len -= 1
return a.data[a.len] return a.data[a.len]
return {} return {}
Contains :: (a: *Array($T), item: *T): bool Contains :: (a: *Array($T), item: *T): bool
result := item >= a.data && item < a.data + a.len result := item >= a.data && item < a.data + a.len
return result return result
Free :: (a: *Array($T)) Free :: (a: *Array($T))
free(a.data) free(a.data)
a.cap = 0; a.len = 0; a.data = 0 a.cap = 0; a.len = 0; a.data = 0
Reset :: (a: *Array($T)) Reset :: (a: *Array($T))
a.len = 0 a.len = 0
GetLast :: (a: *Array($T)): *T GetLast :: (a: *Array($T)): *T
Assert(a.len > 0) Assert(a.len > 0)
result := a.data + a.len-1 result := a.data + a.len-1
return result return result
Insert :: (a: *Array($T), item: T, index: int) Insert :: (a: *Array($T), item: T, index: int)
if index == a.len if index == a.len
Add(a, item) Add(a, item)
return return
Assert(index < a.len) Assert(index < a.len)
Assert(index >= 0) Assert(index >= 0)
TryGrowing(a) TryGrowing(a)
right_len := (a.len - index)->size_t right_len := (a.len - index)->size_t
memmove(a.data + index + 1, a.data + index, sizeof(T) * right_len) memmove(a.data + index + 1, a.data + index, sizeof(T) * right_len)
a.data[index] = item a.data[index] = item
a.len += 1 a.len += 1
GetIndex :: (a: *Array($T), item: *T): int GetIndex :: (a: *Array($T), item: *T): int
Assert(a.len > 0) Assert(a.len > 0)
Assert(item >= a.data && item < a.data + a.len) Assert(item >= a.data && item < a.data + a.len)
index := (item - a.data)->int index := (item - a.data)->int
Assert(index >= 0 && index < a.len) Assert(index >= 0 && index < a.len)
return index return index
UnorderedRemove :: (a: *Array($T), item: *T) UnorderedRemove :: (a: *Array($T), item: *T)
Assert(a.len > 0) Assert(a.len > 0)
Assert(item >= a.data && item < a.data + a.len) Assert(item >= a.data && item < a.data + a.len)
*item = a.data[--a.len] *item = a.data[--a.len]
OrderedRemove :: (a: *Array($T), item: *T) OrderedRemove :: (a: *Array($T), item: *T)
index := GetIndex(a, item) index := GetIndex(a, item)
if index == a.len - 1 if index == a.len - 1
Pop(a) Pop(a)
return return
length_right_of_item := (a.len - index - 1)->size_t length_right_of_item := (a.len - index - 1)->size_t
memmove(a.data + index, a.data + index + 1, length_right_of_item * sizeof(T)) memmove(a.data + index, a.data + index + 1, length_right_of_item * sizeof(T))
a.len -= 1 a.len -= 1
TryGrowing :: (a: *Array($T)) TryGrowing :: (a: *Array($T))
if a.cap == 0 if a.cap == 0
a.cap = 16 a.cap = 16
a.data = malloc(sizeof(T) * a.cap->size_t) a.data = malloc(sizeof(T) * a.cap->size_t)
if a.len + 1 > a.cap if a.len + 1 > a.cap
a.cap *= 2 a.cap *= 2
a.data = realloc(a.data, sizeof(T) * a.cap->size_t) a.data = realloc(a.data, sizeof(T) * a.cap->size_t)
Add :: (a: *Array($T), item: T) Add :: (a: *Array($T), item: T)
TryGrowing(a) TryGrowing(a)
a.data[a.len++] = item a.data[a.len++] = item
BoundedAdd :: (a: *Array($T), item: T) BoundedAdd :: (a: *Array($T), item: T)
Assert(a.len + 1 <= a.cap) Assert(a.len + 1 <= a.cap)
Add(a, item) Add(a, item)
InsertSortedDecreasing :: (a: *Array($T), item: T) InsertSortedDecreasing :: (a: *Array($T), item: T)
insert_index := -1 insert_index := -1
for i := 0, i < a.len, i += 1 for i := 0, i < a.len, i += 1
it := a.data + i it := a.data + i
if it.value_to_sort_by <= item.value_to_sort_by if it.value_to_sort_by <= item.value_to_sort_by
insert_index = i insert_index = i
Insert(a, item, i) Insert(a, item, i)
break break
if insert_index == -1 if insert_index == -1
Add(a, item) Add(a, item)
Reserve :: (a: *Array($T), size: int) Reserve :: (a: *Array($T), size: int)
Assert(size > a.cap) Assert(size > a.cap)
a.cap = size a.cap = size
p := realloc(a.data, sizeof(T) * a.cap->size_t) p := realloc(a.data, sizeof(T) * a.cap->size_t)
Assert(p != 0) Assert(p != 0)
a.data = p a.data = p

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,355 +1,355 @@
#import "KERNEL32.core" #import "KERNEL32.core"
#import "GDI32.core" #import "GDI32.core"
#import "USER32.core" #import "USER32.core"
#import "WINMM.core" #import "WINMM.core"
#import "OS$OS.core" #import "OS$OS.core"
Platform :: struct Platform :: struct
bitmap: WIN32_Bitmap bitmap: WIN32_Bitmap
window_dc: HDC window_dc: HDC
window: HWND window: HWND
good_scheduling: bool good_scheduling: bool
WIN32_Bitmap :: struct WIN32_Bitmap :: struct
size: Vec2I size: Vec2I
data: *U32 data: *U32
hdc: HDC hdc: HDC
dib: HBITMAP dib: HBITMAP
compatible_dc: HDC compatible_dc: HDC
IsValidBitmap :: (b: *WIN32_Bitmap): bool IsValidBitmap :: (b: *WIN32_Bitmap): bool
result := b.data != 0 result := b.data != 0
return result return result
CreateBitmap :: (for_dc: HDC, size: Vec2I, bottom_up: bool = true): WIN32_Bitmap CreateBitmap :: (for_dc: HDC, size: Vec2I, bottom_up: bool = true): WIN32_Bitmap
result: WIN32_Bitmap = {size = size} result: WIN32_Bitmap = {size = size}
if bottom_up == false if bottom_up == false
result.size.y = -result.size.y result.size.y = -result.size.y
header_size: U32 = sizeof(BITMAPINFOHEADER) header_size: U32 = sizeof(BITMAPINFOHEADER)
Assert(header_size == 40) Assert(header_size == 40)
bminfo := BITMAPINFO{ bminfo := BITMAPINFO{
BITMAPINFOHEADER{ BITMAPINFOHEADER{
biSize = header_size, biSize = header_size,
biWidth = size.x->LONG, biWidth = size.x->LONG,
biHeight = size.y->LONG, biHeight = size.y->LONG,
biPlanes = 1, biPlanes = 1,
biBitCount = 32, biBitCount = 32,
biCompression = BI_RGB, biCompression = BI_RGB,
biXPelsPerMeter = 1, biXPelsPerMeter = 1,
biYPelsPerMeter = 1, biYPelsPerMeter = 1,
} }
} }
result.dib = CreateDIBSection(for_dc, &bminfo, DIB_RGB_COLORS, (&result.data)->**void, 0, 0) result.dib = CreateDIBSection(for_dc, &bminfo, DIB_RGB_COLORS, (&result.data)->**void, 0, 0)
result.hdc = CreateCompatibleDC(for_dc) result.hdc = CreateCompatibleDC(for_dc)
result.compatible_dc = for_dc result.compatible_dc = for_dc
return result return result
DestroyBitmap :: (b: *WIN32_Bitmap) DestroyBitmap :: (b: *WIN32_Bitmap)
if IsValidBitmap(b) if IsValidBitmap(b)
DeleteDC(b.hdc) DeleteDC(b.hdc)
DeleteObject(b.dib) DeleteObject(b.dib)
ZeroMemory(b, sizeof(WIN32_Bitmap)) ZeroMemory(b, sizeof(WIN32_Bitmap))
DrawBitmapInCompatibleDC :: (b: *WIN32_Bitmap) DrawBitmapInCompatibleDC :: (b: *WIN32_Bitmap)
if IsValidBitmap(b) if IsValidBitmap(b)
SelectObject(b.hdc, b.dib) SelectObject(b.hdc, b.dib)
BitBlt(b.compatible_dc, 0, 0, b.size.x->int, b.size.y->int, b.hdc, 0, 0, SRCCOPY) BitBlt(b.compatible_dc, 0, 0, b.size.x->int, b.size.y->int, b.hdc, 0, 0, SRCCOPY)
GetWindowStyle :: (resizable: bool): DWORD GetWindowStyle :: (resizable: bool): DWORD
style: DWORD = WS_SYSMENU | WS_OVERLAPPED | WS_CAPTION style: DWORD = WS_SYSMENU | WS_OVERLAPPED | WS_CAPTION
if resizable ;; style |= WS_MAXIMIZEBOX | WS_THICKFRAME | WS_MINIMIZEBOX if resizable ;; style |= WS_MAXIMIZEBOX | WS_THICKFRAME | WS_MINIMIZEBOX
return style return style
GetWindowSize :: (window: HWND): Vec2I GetWindowSize :: (window: HWND): Vec2I
result: Vec2I result: Vec2I
window_rect: RECT window_rect: RECT
GetClientRect(window, &window_rect) GetClientRect(window, &window_rect)
result.x = (window_rect.right - window_rect.left)->int result.x = (window_rect.right - window_rect.left)->int
result.y = (window_rect.bottom - window_rect.top)->int result.y = (window_rect.bottom - window_rect.top)->int
return result return result
GetWindowPos :: (window: HWND): Vec2I GetWindowPos :: (window: HWND): Vec2I
pos: Point pos: Point
ClientToScreen(window, &pos) ClientToScreen(window, &pos)
return {pos.x, pos.y} return {pos.x, pos.y}
AdjustWindowRect :: (window: HWND, style: DWORD, rect: *RECT): void AdjustWindowRect :: (window: HWND, style: DWORD, rect: *RECT): void
FALSE :: 0 FALSE :: 0
// if window == 0 // if window == 0
// dpi := GetDpiForWindow(window) // dpi := GetDpiForWindow(window)
// AdjustWindowRectExForDpi(rect, style, FALSE, 0, dpi) // AdjustWindowRectExForDpi(rect, style, FALSE, 0, dpi)
// else // else
AdjustWindowRectEx(rect, style, FALSE, 0) AdjustWindowRectEx(rect, style, FALSE, 0)
SetWindowSize :: (window: HWND, style: DWORD, size: Vec2I): void SetWindowSize :: (window: HWND, style: DWORD, size: Vec2I): void
rect := RECT{ 0, 0, size.x->LONG, size.y->LONG } rect := RECT{ 0, 0, size.x->LONG, size.y->LONG }
AdjustWindowRect(window, style, &rect) AdjustWindowRect(window, style, &rect)
SetWindowPos(window, HWND_TOP, 0, 0, (rect.right - rect.left)->int, (rect.bottom - rect.top)->int, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER) SetWindowPos(window, HWND_TOP, 0, 0, (rect.right - rect.left)->int, (rect.bottom - rect.top)->int, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER)
SetWindowPosition :: (window: HWND, style: DWORD, pos: Vec2I): void SetWindowPosition :: (window: HWND, style: DWORD, pos: Vec2I): void
rect := RECT{ pos.x->LONG, pos.y->LONG, pos.x->LONG, pos.y->LONG } rect := RECT{ pos.x->LONG, pos.y->LONG, pos.x->LONG, pos.y->LONG }
AdjustWindowRect(window, style, &rect) AdjustWindowRect(window, style, &rect)
SetWindowPos(window, 0, rect.left, rect.top, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE) SetWindowPos(window, 0, rect.left, rect.top, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE)
StartMultimedia :: ( StartMultimedia :: (
x: int = 1280, y: int = 720, x: int = 1280, y: int = 720,
title: String = "Hello people!", title: String = "Hello people!",
window_resizable: bool = false, window_resizable: bool = false,
target_ms: F64 = 0.0166666 target_ms: F64 = 0.0166666
) )
Mu.time.delta = target_ms Mu.time.delta = target_ms
if timeBeginPeriod(1) == TIMERR_NOERROR if timeBeginPeriod(1) == TIMERR_NOERROR
Mu.os.good_scheduling = true Mu.os.good_scheduling = true
dpi_aware := SetProcessDPIAware() dpi_aware := SetProcessDPIAware()
Assert(dpi_aware != 0) Assert(dpi_aware != 0)
Mu.time.start = Time() Mu.time.start = Time()
hInstance := GetModuleHandleA(0) hInstance := GetModuleHandleA(0)
window_name := StringToString16(&Mu.frame_arena, title) window_name := StringToString16(&Mu.frame_arena, title)
w := WNDCLASSW{ w := WNDCLASSW{
lpfnWndProc = WindowProc, lpfnWndProc = WindowProc,
hInstance = hInstance, hInstance = hInstance,
lpszClassName = window_name.str, lpszClassName = window_name.str,
// style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW, // style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW,
} }
Assert(RegisterClassW(&w) != 0) Assert(RegisterClassW(&w) != 0)
style: DWORD = GetWindowStyle(window_resizable) style: DWORD = GetWindowStyle(window_resizable)
Mu.os.window = CreateWindowExW( Mu.os.window = CreateWindowExW(
dwExStyle = 0, hWndParent = 0, hMenu = 0, lpParam = 0, dwExStyle = 0, hWndParent = 0, hMenu = 0, lpParam = 0,
X = CW_USEDEFAULT, Y = CW_USEDEFAULT, nWidth = x->int, nHeight = y->int, X = CW_USEDEFAULT, Y = CW_USEDEFAULT, nWidth = x->int, nHeight = y->int,
lpClassName = window_name.str, lpClassName = window_name.str,
lpWindowName = window_name.str, lpWindowName = window_name.str,
dwStyle = style, dwStyle = style,
hInstance = hInstance hInstance = hInstance
) )
Assert(Mu.os.window != 0) Assert(Mu.os.window != 0)
SetWindowSize(Mu.os.window, style, {x,y}) SetWindowSize(Mu.os.window, style, {x,y})
ShowWindow(Mu.os.window, SW_SHOW) ShowWindow(Mu.os.window, SW_SHOW)
size := GetWindowSize(Mu.os.window) size := GetWindowSize(Mu.os.window)
Assert(size.x == x && size.y == y) Assert(size.x == x && size.y == y)
Mu.os.window_dc = GetDC(Mu.os.window) Mu.os.window_dc = GetDC(Mu.os.window)
Mu.os.bitmap = CreateBitmap(Mu.os.window_dc, size) Mu.os.bitmap = CreateBitmap(Mu.os.window_dc, size)
Mu.window.resizable = window_resizable Mu.window.resizable = window_resizable
Mu.screen = Mu.os.bitmap.data Mu.screen = Mu.os.bitmap.data
Mu.window.x = size.x Mu.window.x = size.x
Mu.window.y = size.y Mu.window.y = size.y
Mu.window.size = size Mu.window.size = size
Mu.window.sizef.x = Mu.window.x->F32 Mu.window.sizef.x = Mu.window.x->F32
Mu.window.sizef.y = Mu.window.y->F32 Mu.window.sizef.y = Mu.window.y->F32
UpdateMultimedia :: (): bool UpdateMultimedia :: (): bool
DrawBitmapInCompatibleDC(&Mu.os.bitmap) DrawBitmapInCompatibleDC(&Mu.os.bitmap)
msg: MSG msg: MSG
for PeekMessageW(&msg, Mu.os.window, 0, 0, PM_REMOVE) == 1 for PeekMessageW(&msg, Mu.os.window, 0, 0, PM_REMOVE) == 1
TranslateMessage(&msg) TranslateMessage(&msg)
DispatchMessageW(&msg) DispatchMessageW(&msg)
size := GetWindowSize(Mu.os.window) size := GetWindowSize(Mu.os.window)
if size.x != Mu.window.x || size.y != Mu.window.y if size.x != Mu.window.x || size.y != Mu.window.y
DestroyBitmap(&Mu.os.bitmap) DestroyBitmap(&Mu.os.bitmap)
Mu.os.bitmap = CreateBitmap(Mu.os.window_dc, size) Mu.os.bitmap = CreateBitmap(Mu.os.window_dc, size)
Mu.screen = Mu.os.bitmap.data Mu.screen = Mu.os.bitmap.data
Mu.window.x = size.x Mu.window.x = size.x
Mu.window.y = size.y Mu.window.y = size.y
Mu.window.sizef.x = Mu.window.x->F32 Mu.window.sizef.x = Mu.window.x->F32
Mu.window.sizef.y = Mu.window.y->F32 Mu.window.sizef.y = Mu.window.y->F32
Mu.window.size = size Mu.window.size = size
Mu.frame_count += 1 Mu.frame_count += 1
frame_time := Time() - Mu.time.frame_start frame_time := Time() - Mu.time.frame_start
Mu.time.total += frame_time Mu.time.total += frame_time
if frame_time < Mu.time.delta if frame_time < Mu.time.delta
if Mu.os.good_scheduling if Mu.os.good_scheduling
time_to_sleep := (Mu.time.delta - frame_time) * 1000 time_to_sleep := (Mu.time.delta - frame_time) * 1000
if time_to_sleep > 0 if time_to_sleep > 0
time_to_sleep_dword := time_to_sleep->DWORD time_to_sleep_dword := time_to_sleep->DWORD
// @check if time_to_sleep_dword truncates down // @check if time_to_sleep_dword truncates down
Sleep(time_to_sleep_dword) Sleep(time_to_sleep_dword)
new_frame_time := Time() new_frame_time := Time()
for new_frame_time < Mu.time.delta for new_frame_time < Mu.time.delta
new_frame_time = Time() - Mu.time.frame_start new_frame_time = Time() - Mu.time.frame_start
Mu.time.frame_start = Time() Mu.time.frame_start = Time()
return !Mu.quit return !Mu.quit
WindowProc :: (hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM): LRESULT WindowProc :: (hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM): LRESULT
result: LRESULT result: LRESULT
if msg == WM_DESTROY if msg == WM_DESTROY
// @todo: Add destroy window // @todo: Add destroy window
PostQuitMessage(0) PostQuitMessage(0)
return 0 return 0
elif msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN elif msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN
key := MapVKToKey(wparam) key := MapVKToKey(wparam)
Mu.key[key].down = true Mu.key[key].down = true
elif msg == WM_KEYUP || msg == WM_SYSKEYUP elif msg == WM_KEYUP || msg == WM_SYSKEYUP
key := MapVKToKey(wparam) key := MapVKToKey(wparam)
Mu.key[key].down = false Mu.key[key].down = false
elif msg == WM_LBUTTONDOWN ;; Mu.mouse.left.down = true elif msg == WM_LBUTTONDOWN ;; Mu.mouse.left.down = true
elif msg == WM_LBUTTONUP ;; Mu.mouse.left.down = false elif msg == WM_LBUTTONUP ;; Mu.mouse.left.down = false
elif msg == WM_RBUTTONDOWN ;; Mu.mouse.right.down = true elif msg == WM_RBUTTONDOWN ;; Mu.mouse.right.down = true
elif msg == WM_RBUTTONUP ;; Mu.mouse.right.down = false elif msg == WM_RBUTTONUP ;; Mu.mouse.right.down = false
elif msg == WM_MBUTTONDOWN ;; Mu.mouse.middle.down = true elif msg == WM_MBUTTONDOWN ;; Mu.mouse.middle.down = true
elif msg == WM_MBUTTONUP ;; Mu.mouse.middle.down = false elif msg == WM_MBUTTONUP ;; Mu.mouse.middle.down = false
elif msg == WM_MOUSEWHEEL elif msg == WM_MOUSEWHEEL
if wparam->int > 0 if wparam->int > 0
Mu.mouse.wheel = 1 Mu.mouse.wheel = 1
else else
Mu.mouse.wheel = -1 Mu.mouse.wheel = -1
// Case(WM_CHAR){ // Case(WM_CHAR){
// Utf32Result utf32 = Utf16ToUtf32((u16 *)&wparam, 1); // Utf32Result utf32 = Utf16ToUtf32((u16 *)&wparam, 1);
// if(!utf32.error){ // if(!utf32.error){
// int index = OS->input_count; // int index = OS->input_count;
// OS->input_count = ClampTop(OS->input_count + 1, (int)(ArrayCount(OS->input) - 1)); // OS->input_count = ClampTop(OS->input_count + 1, (int)(ArrayCount(OS->input) - 1));
// OS->input[index] = utf32.out_str; // OS->input[index] = utf32.out_str;
// } // }
// }Break; // }Break;
else;; result = DefWindowProcW(hwnd, msg, wparam, lparam) else;; result = DefWindowProcW(hwnd, msg, wparam, lparam)
return result return result
/*# /*#
mapping = [ mapping = [
["Up", "VK_UP"], ["Up", "VK_UP"],
["Down", "VK_DOWN"], ["Down", "VK_DOWN"],
["Left", "VK_LEFT"], ["Left", "VK_LEFT"],
["Right", "VK_RIGHT"], ["Right", "VK_RIGHT"],
["Escape", "VK_ESCAPE"], ["Escape", "VK_ESCAPE"],
["Control", "VK_CONTROL"], ["Control", "VK_CONTROL"],
["Backspace", "VK_BACK"], ["Backspace", "VK_BACK"],
["Alt", "VK_MENU"], ["Alt", "VK_MENU"],
["Shift", "VK_SHIFT"], ["Shift", "VK_SHIFT"],
["Tab", "VK_TAB"], ["Tab", "VK_TAB"],
["F1", "VK_F1"], ["F1", "VK_F1"],
["F2", "VK_F2"], ["F2", "VK_F2"],
["F3", "VK_F3"], ["F3", "VK_F3"],
["F4", "VK_F4"], ["F4", "VK_F4"],
["F5", "VK_F5"], ["F5", "VK_F5"],
["F6", "VK_F6"], ["F6", "VK_F6"],
["F7", "VK_F7"], ["F7", "VK_F7"],
["F8", "VK_F8"], ["F8", "VK_F8"],
["F9", "VK_F9"], ["F9", "VK_F9"],
["F10", "VK_F10"], ["F10", "VK_F10"],
["F11", "VK_F11"], ["F11", "VK_F11"],
["F12", "VK_F12"], ["F12", "VK_F12"],
["A", "'A'"], ["A", "'A'"],
["B", "'B'"], ["B", "'B'"],
["C", "'C'"], ["C", "'C'"],
["D", "'D'"], ["D", "'D'"],
["E", "'E'"], ["E", "'E'"],
["F", "'F'"], ["F", "'F'"],
["G", "'G'"], ["G", "'G'"],
["H", "'H'"], ["H", "'H'"],
["I", "'I'"], ["I", "'I'"],
["J", "'J'"], ["J", "'J'"],
["K", "'K'"], ["K", "'K'"],
["L", "'L'"], ["L", "'L'"],
["M", "'M'"], ["M", "'M'"],
["N", "'N'"], ["N", "'N'"],
["O", "'O'"], ["O", "'O'"],
["P", "'P'"], ["P", "'P'"],
["Q", "'Q'"], ["Q", "'Q'"],
["R", "'R'"], ["R", "'R'"],
["S", "'S'"], ["S", "'S'"],
["T", "'T'"], ["T", "'T'"],
["U", "'U'"], ["U", "'U'"],
["V", "'V'"], ["V", "'V'"],
["W", "'W'"], ["W", "'W'"],
["X", "'X'"], ["X", "'X'"],
["Y", "'Y'"], ["Y", "'Y'"],
["Z", "'Z'"], ["Z", "'Z'"],
["K0", "'0'"], ["K0", "'0'"],
["K1", "'1'"], ["K1", "'1'"],
["K2", "'2'"], ["K2", "'2'"],
["K3", "'3'"], ["K3", "'3'"],
["K4", "'4'"], ["K4", "'4'"],
["K5", "'5'"], ["K5", "'5'"],
["K6", "'6'"], ["K6", "'6'"],
["K7", "'7'"], ["K7", "'7'"],
["K8", "'8'"], ["K8", "'8'"],
["K9", "'9'"], ["K9", "'9'"],
] ]
print("MapVKToKey :: (vk: WPARAM): Key") print("MapVKToKey :: (vk: WPARAM): Key")
el = "" el = ""
for val,map in mapping: for val,map in mapping:
print(f" {el}if vk == {map} ;; return Key.{val}") print(f" {el}if vk == {map} ;; return Key.{val}")
el = "el" el = "el"
print(" return Key.None") print(" return Key.None")
*/ */
MapVKToKey :: (vk: WPARAM): Key MapVKToKey :: (vk: WPARAM): Key
if vk == VK_UP ;; return Key.Up if vk == VK_UP ;; return Key.Up
elif vk == VK_DOWN ;; return Key.Down elif vk == VK_DOWN ;; return Key.Down
elif vk == VK_LEFT ;; return Key.Left elif vk == VK_LEFT ;; return Key.Left
elif vk == VK_RIGHT ;; return Key.Right elif vk == VK_RIGHT ;; return Key.Right
elif vk == VK_ESCAPE ;; return Key.Escape elif vk == VK_ESCAPE ;; return Key.Escape
elif vk == VK_CONTROL ;; return Key.Control elif vk == VK_CONTROL ;; return Key.Control
elif vk == VK_BACK ;; return Key.Backspace elif vk == VK_BACK ;; return Key.Backspace
elif vk == VK_MENU ;; return Key.Alt elif vk == VK_MENU ;; return Key.Alt
elif vk == VK_SHIFT ;; return Key.Shift elif vk == VK_SHIFT ;; return Key.Shift
elif vk == VK_TAB ;; return Key.Tab elif vk == VK_TAB ;; return Key.Tab
elif vk == VK_F1 ;; return Key.F1 elif vk == VK_F1 ;; return Key.F1
elif vk == VK_F2 ;; return Key.F2 elif vk == VK_F2 ;; return Key.F2
elif vk == VK_F3 ;; return Key.F3 elif vk == VK_F3 ;; return Key.F3
elif vk == VK_F4 ;; return Key.F4 elif vk == VK_F4 ;; return Key.F4
elif vk == VK_F5 ;; return Key.F5 elif vk == VK_F5 ;; return Key.F5
elif vk == VK_F6 ;; return Key.F6 elif vk == VK_F6 ;; return Key.F6
elif vk == VK_F7 ;; return Key.F7 elif vk == VK_F7 ;; return Key.F7
elif vk == VK_F8 ;; return Key.F8 elif vk == VK_F8 ;; return Key.F8
elif vk == VK_F9 ;; return Key.F9 elif vk == VK_F9 ;; return Key.F9
elif vk == VK_F10 ;; return Key.F10 elif vk == VK_F10 ;; return Key.F10
elif vk == VK_F11 ;; return Key.F11 elif vk == VK_F11 ;; return Key.F11
elif vk == VK_F12 ;; return Key.F12 elif vk == VK_F12 ;; return Key.F12
elif vk == 'A' ;; return Key.A elif vk == 'A' ;; return Key.A
elif vk == 'B' ;; return Key.B elif vk == 'B' ;; return Key.B
elif vk == 'C' ;; return Key.C elif vk == 'C' ;; return Key.C
elif vk == 'D' ;; return Key.D elif vk == 'D' ;; return Key.D
elif vk == 'E' ;; return Key.E elif vk == 'E' ;; return Key.E
elif vk == 'F' ;; return Key.F elif vk == 'F' ;; return Key.F
elif vk == 'G' ;; return Key.G elif vk == 'G' ;; return Key.G
elif vk == 'H' ;; return Key.H elif vk == 'H' ;; return Key.H
elif vk == 'I' ;; return Key.I elif vk == 'I' ;; return Key.I
elif vk == 'J' ;; return Key.J elif vk == 'J' ;; return Key.J
elif vk == 'K' ;; return Key.K elif vk == 'K' ;; return Key.K
elif vk == 'L' ;; return Key.L elif vk == 'L' ;; return Key.L
elif vk == 'M' ;; return Key.M elif vk == 'M' ;; return Key.M
elif vk == 'N' ;; return Key.N elif vk == 'N' ;; return Key.N
elif vk == 'O' ;; return Key.O elif vk == 'O' ;; return Key.O
elif vk == 'P' ;; return Key.P elif vk == 'P' ;; return Key.P
elif vk == 'Q' ;; return Key.Q elif vk == 'Q' ;; return Key.Q
elif vk == 'R' ;; return Key.R elif vk == 'R' ;; return Key.R
elif vk == 'S' ;; return Key.S elif vk == 'S' ;; return Key.S
elif vk == 'T' ;; return Key.T elif vk == 'T' ;; return Key.T
elif vk == 'U' ;; return Key.U elif vk == 'U' ;; return Key.U
elif vk == 'V' ;; return Key.V elif vk == 'V' ;; return Key.V
elif vk == 'W' ;; return Key.W elif vk == 'W' ;; return Key.W
elif vk == 'X' ;; return Key.X elif vk == 'X' ;; return Key.X
elif vk == 'Y' ;; return Key.Y elif vk == 'Y' ;; return Key.Y
elif vk == 'Z' ;; return Key.Z elif vk == 'Z' ;; return Key.Z
elif vk == '0' ;; return Key.K0 elif vk == '0' ;; return Key.K0
elif vk == '1' ;; return Key.K1 elif vk == '1' ;; return Key.K1
elif vk == '2' ;; return Key.K2 elif vk == '2' ;; return Key.K2
elif vk == '3' ;; return Key.K3 elif vk == '3' ;; return Key.K3
elif vk == '4' ;; return Key.K4 elif vk == '4' ;; return Key.K4
elif vk == '5' ;; return Key.K5 elif vk == '5' ;; return Key.K5
elif vk == '6' ;; return Key.K6 elif vk == '6' ;; return Key.K6
elif vk == '7' ;; return Key.K7 elif vk == '7' ;; return Key.K7
elif vk == '8' ;; return Key.K8 elif vk == '8' ;; return Key.K8
elif vk == '9' ;; return Key.K9 elif vk == '9' ;; return Key.K9
return Key.None return Key.None
/*END*/ /*END*/

306
src/base/array.hpp Normal file
View File

@@ -0,0 +1,306 @@
// #define ARRAY_ALLOCATOR_TYPE Allocator
#ifndef ARRAY_PRIVATE_FUNCTION
#if defined(__GNUC__) || defined(__clang__)
#define ARRAY_PRIVATE_FUNCTION __attribute__((unused)) static
#else
#define ARRAY_PRIVATE_FUNCTION static
#endif
#endif
#ifndef ARRAY_ALLOCATE
#include <stdlib.h>
#define ARRAY_ALLOCATE(allocator, size) malloc(size)
#endif
#ifndef ARRAY_DEALLOCATE
#include <stdlib.h>
#define ARRAY_DEALLOCATE(allocator, p) free(p)
#endif
#ifndef ARRAY_ASSERT
#include <assert.h>
#define ARRAY_ASSERT(x) assert(x)
#endif
#ifndef ARRAY_MemoryMove
#include <string.h>
#define ARRAY_MemoryMove(dst, src, size) memmove(dst, src, size)
#endif
#ifndef ARRAY_SET_DEFAULT_ALLOCATOR
#define ARRAY_SET_DEFAULT_ALLOCATOR
// Example:
// #define ARRAY_SET_DEFAULT_ALLOCATOR if (!allocator) allocator = global_heap;
#endif
#ifdef DEFER_HEADER
#define ForArrayRemovable(a) for (int __i = 0; __i < (a).len; __i += 1)
#define ForArrayRemovablePrepare(a) \
auto &it = (a)[__i]; \
bool remove_it = false; \
Defer { \
if (remove_it) { \
(a).ordered_remove(it); \
__i -= 1; \
} \
}
#define ForArrayRemovableDeclare() (remove_it = true)
#endif
#if !defined(ARRAY_ALLOCATOR_CODE)
#if defined(ARRAY_ALLOCATOR_TYPE)
#define ARRAY_ALLOCATOR_CODE(x) x
#define ARRAY_ALLOCATOR_PARAM ARRAY_ALLOCATOR_TYPE *allocator,
#define ARRAY_ALLOCATOR_PASS allocator,
#define ARRAY__PASS(ctx, name) (ctx)->name,
#else
#define ARRAY_ALLOCATOR_CODE(x)
#define ARRAY_ALLOCATOR_PARAM
#define ARRAY_ALLOCATOR_PASS
#define ARRAY__PASS(ctx, name)
#endif
#endif
#if !defined(For)
#define For2(a,it) for(auto &it : (a))
#define For(x) For2(x,it)
#endif
template <class T>
struct Array {
ARRAY_ALLOCATOR_CODE(ARRAY_ALLOCATOR_TYPE *allocator;)
T *data;
int cap, len;
T &operator[](int index) {
ARRAY_ASSERT(index >= 0 && index < len);
return data[index];
}
T &operator[](long long index) {
ARRAY_ASSERT(index >= 0 && index < len);
return data[index];
}
bool is_first(T &item) { return &item == first(); }
bool is_last(T &item) { return &item == last(); }
bool contains(T *item) {
bool result = item >= data && item < data + len;
return result;
}
int get_index(T &item) {
ARRAY_ASSERT((data <= &item) && ((data + len) > &item));
size_t offset = &item - data;
return (int)offset;
}
void add(T item) {
try_growing();
data[len++] = item;
}
// Struct needs to have 'value_to_sort_by' field
void sorted_insert_decreasing(T item) {
int insert_index = -1;
For(*this) {
if (it.value_to_sort_by <= item.value_to_sort_by) {
insert_index = get_index(it);
insert(item, insert_index);
break;
}
}
if (insert_index == -1) {
add(item);
}
}
void bounded_add(T item) {
ARRAY_ASSERT(len + 1 <= cap);
try_growing(); // in case of error
data[len++] = item;
}
T *alloc(const T &item) {
try_growing();
T *ref = data + len++;
*ref = item;
return ref;
}
T *alloc() {
try_growing();
T *ref = data + len++;
*ref = {};
return ref;
}
void add_array(T *items, int item_count) {
for (int i = 0; i < item_count; i += 1) {
add(items[i]);
}
}
void reserve(int size) {
ARRAY_ASSERT(size == 0 || (size != 0 && size > cap));
ARRAY_SET_DEFAULT_ALLOCATOR;
void *p = ARRAY_ALLOCATE(allocator, size * sizeof(T));
ARRAY_ASSERT(p);
if (data) {
ARRAY_MemoryMove(p, data, len * sizeof(T));
ARRAY_DEALLOCATE(allocator, data);
}
data = (T *)p;
cap = size;
}
void init(ARRAY_ALLOCATOR_PARAM int size) {
len = 0;
cap = 0;
data = 0;
ARRAY_ALLOCATOR_CODE(this->allocator = allocator;)
reserve(size);
}
void reset() {
len = 0;
}
T pop() {
ARRAY_ASSERT(len > 0);
return data[--len];
}
void unordered_remove(T &item) { // DONT USE IN LOOPS !!!!
ARRAY_ASSERT(len > 0);
ARRAY_ASSERT(&item >= begin() && &item < end());
item = data[--len];
}
int get_index(const T &item) {
ptrdiff_t index = (ptrdiff_t)(&item - data);
ARRAY_ASSERT(index >= 0 && index < len);
// ARRAY_ASSERT(index > INT_MIN && index < INT_MAX);
return (int)index;
}
void ordered_remove(T &item) { // DONT USE IN LOOPS !!!
ARRAY_ASSERT(len > 0);
ARRAY_ASSERT(&item >= begin() && &item < end());
int index = get_index(item);
ARRAY_ASSERT(index >= 0 && index < len);
int right_len = len - index - 1;
ARRAY_MemoryMove(data + index, data + index + 1, right_len * sizeof(T));
len -= 1;
}
void insert(T item, int index) {
if (index == len) {
add(item);
return;
}
ARRAY_ASSERT(index < len);
ARRAY_ASSERT(index >= 0);
try_growing();
int right_len = len - index;
ARRAY_MemoryMove(data + index + 1, data + index, sizeof(T) * right_len);
data[index] = item;
len += 1;
}
void dealloc() {
if (data) ARRAY_DEALLOCATE(allocator, data);
data = 0;
len = cap = 0;
}
Array<T> exact_copy(ARRAY_ALLOCATOR_CODE(ARRAY_ALLOCATOR_TYPE *allocator)) {
Array result = {};
ARRAY_ALLOCATOR_CODE(result.allocator = allocator;)
result.reserve(cap);
ARRAY_MemoryMove(result.data, data, sizeof(T) * len);
result.len = len;
return result;
}
Array<T> tight_copy(ARRAY_ALLOCATOR_CODE(ARRAY_ALLOCATOR_TYPE *allocator)) {
Array result = {};
ARRAY_ALLOCATOR_CODE(result.allocator = allocator;)
result.reserve(len);
ARRAY_MemoryMove(result.data, data, sizeof(T) * len);
result.len = len;
return result;
}
T *first() {
ARRAY_ASSERT(len > 0);
return data;
}
T *last() {
ARRAY_ASSERT(len > 0);
return data + len - 1;
}
T *front() {
ARRAY_ASSERT(len > 0);
return data;
}
T *back() {
ARRAY_ASSERT(len > 0);
return data + len - 1;
}
T *begin() { return data; }
T *end() { return data + len; }
struct Reverse_Iter {
T *data;
Array<T> *arr;
Reverse_Iter operator++(int) {
Reverse_Iter ret = *this;
data -= 1;
return ret;
}
Reverse_Iter &operator++() {
data -= 1;
return *this;
}
T &operator*() { return data[0]; }
T *operator->() { return data; }
friend bool operator==(const Reverse_Iter &a, const Reverse_Iter &b) { return a.data == b.data; };
friend bool operator!=(const Reverse_Iter &a, const Reverse_Iter &b) { return a.data != b.data; };
Reverse_Iter begin() { return Reverse_Iter{arr->end() - 1, arr}; }
Reverse_Iter end() { return Reverse_Iter{arr->begin() - 1, arr}; }
};
Reverse_Iter reverse() { return {end() - 1, this}; }
private:
void try_growing() {
if (len + 1 > cap) {
int new_size = cap * 2;
if (new_size < 16) new_size = 16;
reserve(new_size);
}
}
void try_growing_to_fit_item_count(int item_count) {
if (len + item_count > cap) {
int new_size = max(16, (cap + item_count) * 2);
reserve(new_size);
}
}
};

View File

@@ -1,347 +1,350 @@
#define CORE_BASE #define CORE_BASE
#if defined(__clang__) #if defined(__clang__)
#define COMPILER_CLANG 1 #define COMPILER_CLANG 1
#if defined(_WIN32) #if defined(_WIN32)
#define OS_WINDOWS 1 #define OS_WINDOWS 1
#elif defined(__linux__) #elif defined(__linux__)
#define OS_LINUX 1 #define OS_LINUX 1
#else #else
#error Couldnt figure out the platform automatically #error Couldnt figure out the platform automatically
#endif #endif
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
#define COMPILER_MSVC 1 #define COMPILER_MSVC 1
#define OS_WINDOWS 1 #define OS_WINDOWS 1
#elif defined(__GNUC__) #elif defined(__GNUC__)
#define COMPILER_GCC 1 #define COMPILER_GCC 1
#if defined(__linux__) #if defined(__linux__)
#define OS_LINUX 1 #define OS_LINUX 1
#endif #endif
#else #else
#error Couldnt figure out the compiler #error Couldnt figure out the compiler
#endif #endif
#if defined(OS_MAC) #if defined(OS_MAC)
#define OS_UNIX 1 #define OS_UNIX 1
#endif #endif
#if defined(OS_LINUX) #if defined(OS_LINUX)
#define OS_UNIX 1 #define OS_UNIX 1
#endif #endif
#if !defined(COMPILER_MSVC) #if !defined(COMPILER_MSVC)
#define COMPILER_MSVC 0 #define COMPILER_MSVC 0
#endif #endif
#if !defined(COMPILER_GCC) #if !defined(COMPILER_GCC)
#define COMPILER_GCC 0 #define COMPILER_GCC 0
#endif #endif
#if !defined(COMPILER_CLANG) #if !defined(COMPILER_CLANG)
#define COMPILER_CLANG 0 #define COMPILER_CLANG 0
#endif #endif
#if !defined(OS_WINDOWS) #if !defined(OS_WINDOWS)
#define OS_WINDOWS 0 #define OS_WINDOWS 0
#endif #endif
#if !defined(OS_LINUX) #if !defined(OS_LINUX)
#define OS_LINUX 0 #define OS_LINUX 0
#endif #endif
#if !defined(OS_MAC) #if !defined(OS_MAC)
#define OS_MAC 0 #define OS_MAC 0
#endif #endif
#if !defined(OS_UNIX) #if !defined(OS_UNIX)
#define OS_UNIX 0 #define OS_UNIX 0
#endif #endif
#if OS_WINDOWS #if OS_WINDOWS
#define OS_EXE ".exe" #define OS_EXE ".exe"
#define OS_NAME "Win32"_s #define OS_NAME "Win32"_s
#define OS_NAME_LOWER "win32"_s #define OS_NAME_LOWER "win32"_s
#elif OS_LINUX #elif OS_LINUX
#define OS_EXE ".out" #define OS_EXE ".out"
#define OS_NAME "Linux"_s #define OS_NAME "Linux"_s
#define OS_NAME_LOWER "linux"_s #define OS_NAME_LOWER "linux"_s
#elif OS_MAC #elif OS_MAC
#define OS_EXE ".out" #define OS_EXE ".out"
#define OS_NAME "Mac"_s #define OS_NAME "Mac"_s
#define OS_NAME_LOWER "mac"_s #define OS_NAME_LOWER "mac"_s
#else #else
#error Couldnt figure out the OS with C macros! #error Couldnt figure out the OS with C macros!
#endif #endif
#if OS_WINDOWS #if OS_WINDOWS
#define NOMINMAX #define NOMINMAX
#ifndef _CRT_SECURE_NO_WARNINGS #ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS
#endif #endif
#include <windows.h> #include <windows.h>
#define Breakpoint __debugbreak() #define Breakpoint __debugbreak()
#define force_inline __forceinline #define force_inline __forceinline
#else #else
#define Breakpoint (*(volatile int *)0 = 0) #define Breakpoint (*(volatile int *)0 = 0)
#define force_inline inline #define force_inline inline
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#include <float.h> #include <float.h>
#include <stdint.h> #include <stdint.h>
typedef int8_t S8; typedef int8_t S8;
typedef int16_t S16; typedef int16_t S16;
typedef int32_t S32; typedef int32_t S32;
typedef int64_t S64; typedef int64_t S64;
typedef uint8_t U8; typedef uint8_t U8;
typedef uint16_t U16; typedef uint16_t U16;
typedef uint32_t U32; typedef uint32_t U32;
typedef uint64_t U64; typedef uint64_t U64;
typedef S8 B8; typedef S8 B8;
typedef S16 B16; typedef S16 B16;
typedef S32 B32; typedef S32 B32;
typedef S64 B64; typedef S64 B64;
typedef float F32; typedef float F32;
typedef double F64; typedef double F64;
#define U64MAX UINT64_MAX #define U64MAX UINT64_MAX
#define U32MAX UINT32_MAX #define U32MAX UINT32_MAX
#define U16MAX UINT16_MAX #define U16MAX UINT16_MAX
#define U8MAX UINT8_MAX #define U8MAX UINT8_MAX
#define U64MIN 0 #define U64MIN 0
#define U32MIN 0 #define U32MIN 0
#define U16MIN 0 #define U16MIN 0
#define U8MIN 0 #define U8MIN 0
#define S64MAX INT64_MAX #define S64MAX INT64_MAX
#define S64MIN INT64_MIN #define S64MIN INT64_MIN
#define S32MAX INT32_MAX #define S32MAX INT32_MAX
#define S32MIN INT32_MIN #define S32MIN INT32_MIN
#define S16MAX INT16_MAX #define S16MAX INT16_MAX
#define S16MIN INT16_MIN #define S16MIN INT16_MIN
#define S8MAX INT8_MAX #define S8MAX INT8_MAX
#define S8MIN INT8_MIN #define S8MIN INT8_MIN
#define F32MAX FLT_MAX #define F32MAX FLT_MAX
#define F32MIN FLT_MIN #define F32MIN FLT_MIN
#define F64MAX DBL_MAX #define F64MAX DBL_MAX
#define F64MIN DBL_MIN #define F64MIN DBL_MIN
#include <stdio.h> #include <stdio.h>
#define api #define api
#define CORE_Static static #define CORE_Static static
#define global static #define global static
#define assert(x) \ #define assert(x) \
do { \ do { \
if (!(x)) Breakpoint; \ if (!(x)) { \
} while (0) printf("Assertion! %s", #x); \
#define assert_message(x, ...) \ Breakpoint; \
do { \ } \
if (!(x)) { \ } while (0)
printf(__VA_ARGS__); \ #define assert_message(x, ...) \
printf("\n"); \ do { \
Breakpoint; \ if (!(x)) { \
} \ printf(__VA_ARGS__); \
} while (0) printf("\n"); \
#define invalid_codepath assert_message(0, "Invalid codepath") Breakpoint; \
#define invalid_return \ } \
do { \ } while (0)
assert_message(0, "Invalid codepath"); \ #define invalid_codepath assert_message(0, "Invalid codepath")
return {}; \ #define invalid_return \
} while (0) do { \
#define invalid_default_case \ assert_message(0, "Invalid codepath"); \
default: \ return {}; \
invalid_codepath } while (0)
#define not_implemented assert_message(0, "Not implemented") #define invalid_default_case \
#define unused(x) ((void)x) default: \
#define buff_cap(x) (sizeof(x) / sizeof((x)[0])) invalid_codepath
#define is_flag_set(val, flag) ((val) & (flag)) #define not_implemented assert_message(0, "Not implemented")
#define set_flag(val, flag) ((val) |= (flag)) #define unused(x) ((void)x)
#define unset_flag(val, flag) ((val) &= (~(flag))) #define buff_cap(x) (sizeof(x) / sizeof((x)[0]))
#define bit_flag(x) (1ull << (x)) #define is_flag_set(val, flag) ((val) & (flag))
#define kib(x) ((x)*1024llu) #define set_flag(val, flag) ((val) |= (flag))
#define mib(x) (kib(x) * 1024llu) #define unset_flag(val, flag) ((val) &= (~(flag)))
#define gib(x) (mib(x) * 1024llu) #define bit_flag(x) (1ull << (x))
#define JOIN1(X, Y) X##Y #define kib(x) ((x)*1024llu)
#define JOIN(X, Y) JOIN1(X, Y) #define mib(x) (kib(x) * 1024llu)
#define string_expand(x) (int)x.len, x.str #define gib(x) (mib(x) * 1024llu)
#define JOIN1(X, Y) X##Y
struct String { #define JOIN(X, Y) JOIN1(X, Y)
U8 *str; #define string_expand(x) (int)x.len, x.str
S64 len;
}; struct String {
global String string_null = {(U8 *)"null", 4}; U8 *str;
S64 len;
union Intern_String { // Basically just String };
String s; global String string_null = {(U8 *)"null", 4};
struct {
U8 *str; union Intern_String { // Basically just String
S64 len; String s;
}; struct {
}; U8 *str;
S64 len;
struct Allocator { };
typedef void *Allocate(Allocator *, size_t); };
typedef void Deallocate(Allocator *, void *p);
struct Allocator {
Allocate *allocate; typedef void *Allocate(Allocator *, size_t);
Deallocate *deallocate; typedef void Deallocate(Allocator *, void *p);
};
Allocate *allocate;
CORE_Static void memory_zero(void *p, size_t size); Deallocate *deallocate;
CORE_Static void deallocate_stub(Allocator *, void *) {} };
#define allocate_array(a, T, size, ...) (T *)allocate_size(a, sizeof(T) * (size), ##__VA_ARGS__) CORE_Static void memory_zero(void *p, size_t size);
#define allocate_struct(a, T, ...) allocate_array(a, T, 1, ##__VA_ARGS__) CORE_Static void deallocate_stub(Allocator *, void *) {}
CORE_Static void *allocate_size(Allocator *allocator, size_t size, bool zero_memory = true) {
void *result = allocator->allocate(allocator, size); #define allocate_array(a, T, size, ...) (T *)allocate_size(a, sizeof(T) * (size), ##__VA_ARGS__)
if (zero_memory) { #define allocate_struct(a, T, ...) allocate_array(a, T, 1, ##__VA_ARGS__)
memory_zero(result, size); CORE_Static void *allocate_size(Allocator *allocator, size_t size, bool zero_memory = true) {
} void *result = allocator->allocate(allocator, size);
return result; if (zero_memory) {
} memory_zero(result, size);
}
CORE_Static void deallocate(Allocator *allocator, void *p) { return result;
assert(p); }
allocator->deallocate(allocator, p);
} CORE_Static void deallocate(Allocator *allocator, void *p) {
assert(p);
//----------------------------------------------------------------------------- allocator->deallocate(allocator, p);
// Utilities }
//-----------------------------------------------------------------------------
CORE_Static size_t //-----------------------------------------------------------------------------
get_align_offset(size_t size, size_t align) { // Utilities
size_t mask = align - 1; //-----------------------------------------------------------------------------
size_t val = size & mask; CORE_Static size_t
if (val) { get_align_offset(size_t size, size_t align) {
val = align - val; size_t mask = align - 1;
} size_t val = size & mask;
return val; if (val) {
} val = align - val;
}
CORE_Static size_t return val;
align_up(size_t size, size_t align) { }
size_t result = size + get_align_offset(size, align);
return result; CORE_Static size_t
} align_up(size_t size, size_t align) {
size_t result = size + get_align_offset(size, align);
CORE_Static size_t return result;
align_down(size_t size, size_t align) { }
size += 1; // Make sure 8 when align is 8 doesn't get rounded down to 0
size_t result = size - (align - get_align_offset(size, align)); CORE_Static size_t
return result; align_down(size_t size, size_t align) {
} size += 1; // Make sure 8 when align is 8 doesn't get rounded down to 0
size_t result = size - (align - get_align_offset(size, align));
CORE_Static void return result;
memory_copy(void *dst, const void *src, size_t size) { }
U8 *d = (U8 *)dst;
U8 *s = (U8 *)src; CORE_Static void
for (size_t i = 0; i < size; i++) { memory_copy(void *dst, const void *src, size_t size) {
d[i] = s[i]; U8 *d = (U8 *)dst;
} U8 *s = (U8 *)src;
} for (size_t i = 0; i < size; i++) {
d[i] = s[i];
CORE_Static void }
memory_zero(void *p, size_t size) { }
U8 *pp = (U8 *)p;
for (size_t i = 0; i < size; i++) CORE_Static void
pp[i] = 0; memory_zero(void *p, size_t size) {
} U8 *pp = (U8 *)p;
for (size_t i = 0; i < size; i++)
template <class T> pp[i] = 0;
void swap(T &a, T &b) { }
T temp = a;
a = b; template <class T>
b = temp; void swap(T &a, T &b) {
} T temp = a;
a = b;
template <class T> b = temp;
T max(T a, T b) { }
if (a > b) return a;
return b; template <class T>
} T max(T a, T b) {
if (a > b) return a;
template <class T> return b;
T min(T a, T b) { }
if (a > b) return b;
return a; template <class T>
} T min(T a, T b) {
if (a > b) return b;
template <class T> return a;
T clamp_top(T val, T max) { }
if (val > max) val = max;
return val; template <class T>
} T clamp_top(T val, T max) {
if (val > max) val = max;
template <class T> return val;
T clamp_bot(T bot, T val) { }
if (val < bot) val = bot;
return val; template <class T>
} T clamp_bot(T bot, T val) {
if (val < bot) val = bot;
template <class T> return val;
T clamp(T min, T val, T max) { }
if (val > max) val = max;
if (val < min) val = min; template <class T>
return val; T clamp(T min, T val, T max) {
} if (val > max) val = max;
if (val < min) val = min;
CORE_Static U64 return val;
hash_string(String string) { }
U64 hash = (U64)14695981039346656037ULL;
for (S64 i = 0; i < string.len; i++) { CORE_Static U64
hash = hash ^ (U64)(string.str[i]); hash_string(String string) {
hash = hash * (U64)1099511628211ULL; U64 hash = (U64)14695981039346656037ULL;
} for (S64 i = 0; i < string.len; i++) {
return hash; hash = hash ^ (U64)(string.str[i]);
} hash = hash * (U64)1099511628211ULL;
}
force_inline U64 return hash;
hash_u64(U64 x) { }
U64 result = hash_string({(U8 *)&x, sizeof(x)});
return result; force_inline U64
} hash_u64(U64 x) {
U64 result = hash_string({(U8 *)&x, sizeof(x)});
force_inline U64 return result;
hash_ptr(const void *ptr) { }
return hash_u64((uintptr_t)ptr);
} force_inline U64
hash_ptr(const void *ptr) {
CORE_Static U64 return hash_u64((uintptr_t)ptr);
hash_mix(U64 x, U64 y) { }
// @note: murmur hash 3 mixer but I add the 'y'
// which means it's probably bad, hopefully better CORE_Static U64
// then some random scribble I could do hash_mix(U64 x, U64 y) {
x ^= (y >> 33); // @note: murmur hash 3 mixer but I add the 'y'
x *= 0xff51afd7ed558ccd; // which means it's probably bad, hopefully better
x ^= (x >> 33); // then some random scribble I could do
x *= 0xc4ceb9fe1a85ec53; x ^= (y >> 33);
x ^= (y >> 33); x *= 0xff51afd7ed558ccd;
return x; x ^= (x >> 33);
} x *= 0xc4ceb9fe1a85ec53;
x ^= (y >> 33);
force_inline U64 return x;
is_pow2(U64 x) { }
assert(x != 0);
B32 result = (x & (x - 1llu)) == 0; force_inline U64
return result; is_pow2(U64 x) {
} assert(x != 0);
B32 result = (x & (x - 1llu)) == 0;
force_inline U64 return result;
wrap_around_pow2(U64 x, U64 power_of_2) { }
assert(is_pow2(power_of_2));
U64 r = (((x) & ((power_of_2)-1llu))); force_inline U64
return r; wrap_around_pow2(U64 x, U64 power_of_2) {
} assert(is_pow2(power_of_2));
U64 r = (((x) & ((power_of_2)-1llu)));
force_inline String return r;
operator""_s(const char *str, size_t size) { }
return String{(U8 *)str, (S64)size};
} force_inline String
operator""_s(const char *str, size_t size) {
force_inline B32 return String{(U8 *)str, (S64)size};
operator==(Intern_String a, Intern_String b) { }
return a.str == b.str;
} force_inline B32
operator==(Intern_String a, Intern_String b) {
force_inline B32 return a.str == b.str;
operator!=(Intern_String a, Intern_String b) { }
B32 result = a.str == b.str;
return !result; force_inline B32
} operator!=(Intern_String a, Intern_String b) {
B32 result = a.str == b.str;
#define For_Linked_List_Named(a, it) for (auto *it = (a); it; it = it->next) return !result;
#define For_Linked_List(a) For_Linked_List_Named(a, it) }
#define For_Linked_List_Named(a, it) for (auto *it = (a); it; it = it->next)
#define For_Linked_List(a) For_Linked_List_Named(a, it)

View File

@@ -1,140 +1,147 @@
constexpr size_t ARENA_BLOCK_SIZE = mib(4); constexpr size_t ARENA_BLOCK_SIZE = mib(4);
constexpr size_t ARENA_ALIGNMENT = 8; constexpr size_t ARENA_ALIGNMENT = 8;
struct CRT_Heap : Allocator {}; struct CRT_Heap : Allocator {};
CORE_Static void *crt_allocate(Allocator *allocator, size_t size) { return malloc(size); } CORE_Static void *crt_allocate(Allocator *allocator, size_t size) { return malloc(size); }
CORE_Static void crt_deallocate(Allocator *allocator, void *p) { return free(p); } CORE_Static void crt_deallocate(Allocator *allocator, void *p) { return free(p); }
CORE_Static CRT_Heap make_crt_heap() { CORE_Static CRT_Heap make_crt_heap() {
CRT_Heap result = {}; CRT_Heap result = {};
result.allocate = crt_allocate; result.allocate = crt_allocate;
result.deallocate = crt_deallocate; result.deallocate = crt_deallocate;
return result; return result;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Memory OS // Memory OS
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
struct OS_Memory { struct OS_Memory {
size_t commit, reserve; size_t commit, reserve;
U8 *data; U8 *data;
}; };
CORE_Static OS_Memory os_reserve(size_t size); CORE_Static OS_Memory os_reserve(size_t size);
CORE_Static B32 os_commit(OS_Memory *m, size_t size); CORE_Static B32 os_commit(OS_Memory *m, size_t size);
CORE_Static void os_release(OS_Memory *m); CORE_Static void os_release(OS_Memory *m);
CORE_Static B32 os_decommit_pos(OS_Memory *m, size_t pos); CORE_Static B32 os_decommit_pos(OS_Memory *m, size_t pos);
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Memory arenas // Memory arenas
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
global const size_t default_reserve_size = gib(4); global const size_t default_reserve_size = gib(4);
global const size_t default_alignment = 8; global const size_t default_alignment = 8;
global const size_t additional_commit_size = mib(1); global const size_t additional_commit_size = mib(1);
struct Arena : Allocator { global U32 global_arena_ids;
OS_Memory memory; struct Arena : Allocator {
size_t alignment; OS_Memory memory;
size_t len; size_t alignment;
String debug_string; size_t len;
}; String debug_string;
U32 id;
CORE_Static void };
arena_pop_pos(Arena *arena, size_t pos) {
pos = clamp_top(pos, arena->len); CORE_Static void
arena->len = pos; arena_pop_pos(Arena *arena, size_t pos) {
} pos = clamp_top(pos, arena->len);
arena->len = pos;
CORE_Static void * }
arena_pop(Arena *arena, size_t size) {
size = clamp_top(size, arena->len); CORE_Static void *
arena->len -= size; arena_pop(Arena *arena, size_t size) {
return arena->memory.data + arena->len; size = clamp_top(size, arena->len);
} arena->len -= size;
return arena->memory.data + arena->len;
CORE_Static void }
arena_release(Arena *arena) {
os_release(&arena->memory); CORE_Static void
} arena_release(Arena *arena) {
os_release(&arena->memory);
CORE_Static void }
arena_clear(Arena *arena) {
arena_pop_pos(arena, 0); CORE_Static void
} arena_clear(Arena *arena) {
arena_pop_pos(arena, 0);
CORE_Static void * }
arena_push_size(Arena *a, size_t size) {
size_t generous_size = size + a->alignment; static float GLOBAL_VIS_VALUE;
if (a->len + generous_size > a->memory.commit) { CORE_Static void *
assert(a->memory.reserve > 0); arena_push_size(Arena *a, size_t size) {
B32 result = os_commit(&a->memory, generous_size + additional_commit_size); size_t generous_size = size + a->alignment;
assert(result); if (a->len + generous_size > a->memory.commit) {
} assert(a->memory.reserve > 0);
B32 result = os_commit(&a->memory, generous_size + additional_commit_size);
a->len = align_up(a->len, a->alignment); assert(result);
assert(a->memory.reserve > a->len + size); }
void *result = (U8 *)a->memory.data + a->len;
a->len += size; a->len = align_up(a->len, a->alignment);
assert(a->memory.reserve > a->len + size);
return result; void *result = (U8 *)a->memory.data + a->len;
} a->len += size;
#define push_struct_copy(a, T, p) (T *)push_copy(a, p, sizeof(T)) return result;
CORE_Static void * }
push_copy(Arena *a, void *p, size_t size) {
void *result = arena_push_size(a, size); #define push_struct_copy(a, T, p) (T *)push_copy(a, p, sizeof(T))
memory_copy(result, p, size); CORE_Static void *
return result; push_copy(Arena *a, void *p, size_t size) {
} void *result = arena_push_size(a, size);
memory_copy(result, p, size);
CORE_Static Arena return result;
push_arena(Allocator *allocator, size_t size, String debug_name) { }
Arena result = {};
result.memory.data = (U8 *)allocate_size(allocator, size); CORE_Static Arena
result.memory.reserve = size; push_arena(Allocator *allocator, size_t size, String debug_name) {
result.alignment = default_alignment; Arena result = {};
result.debug_string = debug_name; result.memory.data = (U8 *)allocate_size(allocator, size);
result.allocate = (Allocator::Allocate *)arena_push_size; result.memory.reserve = size;
result.deallocate = (Allocator::Deallocate *)deallocate_stub; result.alignment = default_alignment;
return result; result.id = ++global_arena_ids;
} result.debug_string = debug_name;
result.allocate = (Allocator::Allocate *)arena_push_size;
CORE_Static void result.deallocate = (Allocator::Deallocate *)deallocate_stub;
arena_init(Arena *a, String debug_name) { return result;
a->memory = os_reserve(default_reserve_size); }
a->alignment = default_alignment;
a->debug_string = debug_name; CORE_Static void
a->allocate = (Allocator::Allocate *)arena_push_size; arena_init(Arena *a, String debug_name) {
a->deallocate = (Allocator::Deallocate *)deallocate_stub; a->memory = os_reserve(default_reserve_size);
} a->alignment = default_alignment;
a->id = ++global_arena_ids;
CORE_Static Arena a->debug_string = debug_name;
arena_sub(Arena *base, size_t size, String debug_name) { a->allocate = (Allocator::Allocate *)arena_push_size;
Arena result = {}; a->deallocate = (Allocator::Deallocate *)deallocate_stub;
result.memory.data = (U8 *)arena_push_size(base, size); }
result.memory.commit = size;
result.memory.reserve = size; CORE_Static Arena
result.alignment = default_alignment; arena_sub(Arena *base, size_t size, String debug_name) {
result.allocate = (Allocator::Allocate *)arena_push_size; Arena result = {};
result.deallocate = (Allocator::Deallocate *)deallocate_stub; result.memory.data = (U8 *)arena_push_size(base, size);
return result; result.memory.commit = size;
} result.memory.reserve = size;
result.alignment = default_alignment;
CORE_Static Arena result.allocate = (Allocator::Allocate *)arena_push_size;
arena_from_buffer(void *buffer, size_t size) { result.deallocate = (Allocator::Deallocate *)deallocate_stub;
Arena result = {}; result.id = ++global_arena_ids;
result.memory.data = (U8 *)buffer; return result;
result.memory.commit = size; }
result.memory.reserve = size;
result.alignment = default_alignment; CORE_Static Arena
result.allocate = (Allocator::Allocate *)arena_push_size; arena_from_buffer(void *buffer, size_t size) {
result.deallocate = (Allocator::Deallocate *)deallocate_stub; Arena result = {};
return result; result.memory.data = (U8 *)buffer;
} result.memory.commit = size;
result.memory.reserve = size;
struct Scoped_Arena { result.alignment = default_alignment;
Arena *arena; result.allocate = (Allocator::Allocate *)arena_push_size;
size_t pos; result.deallocate = (Allocator::Deallocate *)deallocate_stub;
Scoped_Arena(Arena *arena) { result.id = ++global_arena_ids;
this->arena = arena; return result;
this->pos = arena->len; }
}
~Scoped_Arena() { this->arena->len = this->pos; } struct Scoped_Arena {
}; Arena *arena;
size_t pos;
Scoped_Arena(Arena *arena) {
this->arena = arena;
this->pos = arena->len;
}
~Scoped_Arena() { this->arena->len = this->pos; }
};

View File

@@ -1,454 +1,452 @@
#include "core/defer.hpp" #include "../base/defer.hpp"
#define ARRAY_ALLOCATOR_TYPE Allocator #define ARRAY_ALLOCATOR_TYPE Allocator
#define ARRAY_ASSERT assert #define ARRAY_ASSERT assert
#define ARRAY_ALLOCATE(allocator, size) allocate_size(allocator, size) #define ARRAY_ALLOCATE(allocator, size) allocate_size(allocator, size)
#define ARRAY_DEALLOCATE(allocator, p) deallocate(allocator, p) #define ARRAY_DEALLOCATE(allocator, p) deallocate(allocator, p)
#include "core/array.hpp" #include "../base/array.hpp"
#include "core/linked_list.h" #include "../base/linked_list.h"
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Map // Map
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
struct Map_Key_Value { struct Map_Key_Value {
int occupied; int occupied;
U64 key; U64 key;
void *value; void *value;
}; };
struct Map { struct Map {
Allocator *allocator; Allocator *allocator;
Map_Key_Value *data; Map_Key_Value *data;
S64 len; S64 len;
S64 cap; S64 cap;
}; };
CORE_Static void map_insert(Map *map, U64 key, void *val); CORE_Static void map_insert(Map *map, U64 key, void *val);
CORE_Static void CORE_Static void
map_grow(Map *map, S64 new_size) { map_grow(Map *map, S64 new_size) {
new_size = max((S64)16, new_size); new_size = max((S64)16, new_size);
assert(new_size > map->cap); assert(new_size > map->cap);
assert(is_pow2(new_size)); assert(is_pow2(new_size));
assert(map->allocator); assert(map->allocator);
Map new_map = {}; Map new_map = {};
new_map.data = allocate_array(map->allocator, Map_Key_Value, new_size); new_map.data = allocate_array(map->allocator, Map_Key_Value, new_size);
new_map.cap = new_size; new_map.cap = new_size;
new_map.allocator = map->allocator; new_map.allocator = map->allocator;
for (S64 i = 0; i < map->cap; i++) { for (S64 i = 0; i < map->cap; i++) {
if (map->data[i].occupied) { if (map->data[i].occupied) {
map_insert(&new_map, map->data[i].key, map->data[i].value); map_insert(&new_map, map->data[i].key, map->data[i].value);
} }
} }
if (map->data) deallocate(map->allocator, map->data); if (map->data) deallocate(map->allocator, map->data);
*map = new_map; *map = new_map;
} }
CORE_Static Map CORE_Static Map
map_make(Allocator *a, S64 size) { map_make(Allocator *a, S64 size) {
Map result = {a}; Map result = {a};
map_grow(&result, size); map_grow(&result, size);
return result; return result;
} }
CORE_Static void CORE_Static void
map_insert(Map *map, U64 key, void *val) { map_insert(Map *map, U64 key, void *val) {
assert(val); assert(val);
assert(key); assert(key);
// if(key == 0) key+=1; // if(key == 0) key+=1;
if ((2 * map->len) + 1 > map->cap) { if ((2 * map->len) + 1 > map->cap) {
map_grow(map, 2 * map->cap); map_grow(map, 2 * map->cap);
} }
U64 hash = hash_u64(key); U64 hash = hash_u64(key);
U64 index = wrap_around_pow2(hash, map->cap); U64 index = wrap_around_pow2(hash, map->cap);
U64 i = index; U64 i = index;
for (;;) { for (;;) {
if (map->data[i].occupied == false) { if (map->data[i].occupied == false) {
map->len++; map->len++;
map->data[i].occupied = true; map->data[i].occupied = true;
map->data[i].key = key; map->data[i].key = key;
map->data[i].value = val; map->data[i].value = val;
return; return;
} } else if (map->data[i].key == key) {
else if (map->data[i].key == key) { map->data[i].value = val;
map->data[i].value = val; return;
return; }
}
i = wrap_around_pow2(i + 1, map->cap);
i = wrap_around_pow2(i + 1, map->cap); if (i == map->cap) {
if (i == map->cap) { return;
return; }
} }
} }
}
CORE_Static Map_Key_Value *
CORE_Static Map_Key_Value * map_base_get(Map *map, U64 key) {
map_base_get(Map *map, U64 key) { if (map->len == 0) return 0;
if (map->len == 0) return 0; assert(key);
assert(key);
U64 hash = hash_u64(key);
U64 hash = hash_u64(key); U64 index = wrap_around_pow2(hash, map->cap);
U64 index = wrap_around_pow2(hash, map->cap); U64 i = index;
U64 i = index; for (;;) {
for (;;) { if (map->data[i].key == key) {
if (map->data[i].key == key) { return map->data + i;
return map->data + i; } else if (map->data[i].key == 0) {
} return 0;
else if (map->data[i].key == 0) { }
return 0;
} i = wrap_around_pow2(i + 1, map->cap);
if (i == map->cap) {
i = wrap_around_pow2(i + 1, map->cap); return 0;
if (i == map->cap) { }
return 0; }
} }
}
} CORE_Static void *
map_get(Map *map, U64 key) {
CORE_Static void * Map_Key_Value *result = map_base_get(map, key);
map_get(Map *map, U64 key) { if (result && result->occupied) return result->value;
Map_Key_Value *result = map_base_get(map, key); return 0;
if (result && result->occupied) return result->value; }
return 0;
} CORE_Static void *
map_remove(Map *map, U64 key) {
CORE_Static void * Map_Key_Value *kv = map_base_get(map, key);
map_remove(Map *map, U64 key) { if (kv) {
Map_Key_Value *kv = map_base_get(map, key); kv->occupied = false;
if (kv) { return kv->value;
kv->occupied = false; }
return kv->value; return 0;
} }
return 0;
} CORE_Static void *
map_get(Map *map, void *pointer) {
CORE_Static void * return map_get(map, (U64)pointer);
map_get(Map *map, void *pointer) { }
return map_get(map, (U64)pointer);
} CORE_Static void *
map_get(Map *map, Intern_String string) {
CORE_Static void * return map_get(map, hash_string(string.s));
map_get(Map *map, Intern_String string) { }
return map_get(map, hash_string(string.s));
} CORE_Static void
map_insert(Map *map, void *key, void *value) {
CORE_Static void map_insert(map, (U64)key, value);
map_insert(Map *map, void *key, void *value) { }
map_insert(map, (U64)key, value);
} CORE_Static void
map_insert(Map *map, Intern_String key, void *value) {
CORE_Static void map_insert(map, hash_string(key.s), value);
map_insert(Map *map, Intern_String key, void *value) { }
map_insert(map, hash_string(key.s), value);
} //-----------------------------------------------------------------------------
// String intern
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// String intern struct Intern_Table {
//----------------------------------------------------------------------------- Allocator *string_allocator;
struct Intern_Table { Map map;
Allocator *string_allocator; U8 *first_keyword;
Map map; U8 *last_keyword;
U8 *first_keyword; };
U8 *last_keyword;
}; CORE_Static Intern_Table
intern_table_make(Allocator *string_allocator, Allocator *map_allocator, S64 initial_size = 32) {
CORE_Static Intern_Table Intern_Table result = {};
intern_table_make(Allocator *string_allocator, Allocator *map_allocator, S64 initial_size = 32) { result.map = map_make(map_allocator, initial_size);
Intern_Table result = {}; result.string_allocator = string_allocator;
result.map = map_make(map_allocator, initial_size); return result;
result.string_allocator = string_allocator; }
return result;
} CORE_Static Intern_String
intern_string(Intern_Table *t, String string) {
CORE_Static Intern_String assert(t->string_allocator);
intern_string(Intern_Table *t, String string) { U64 hash = hash_string(string);
assert(t->string_allocator); U8 *slot = (U8 *)map_get(&t->map, hash);
U64 hash = hash_string(string); if (slot) {
U8 *slot = (U8 *)map_get(&t->map, hash); // @todo: Is this a cast bug: *(slot-sizeof(S64))? slot is u8 so truncates?
if (slot) { Intern_String result = {
// @todo: Is this a cast bug: *(slot-sizeof(S64))? slot is u8 so truncates? {slot, *(slot - sizeof(S64))}
Intern_String result = { };
{slot, *(slot - sizeof(S64))} return result;
}; }
return result;
} S64 *len_address = (S64 *)allocate_size(t->string_allocator, string.len + 1 + sizeof(S64), false);
*len_address = string.len;
S64 *len_address = (S64 *)allocate_size(t->string_allocator, string.len + 1 + sizeof(S64), false);
*len_address = string.len; U8 *string_address = (U8 *)(len_address + 1);
memory_copy(string_address, string.str, string.len);
U8 *string_address = (U8 *)(len_address + 1); string_address[string.len] = 0;
memory_copy(string_address, string.str, string.len);
string_address[string.len] = 0; map_insert(&t->map, hash, string_address);
Intern_String result = {
map_insert(&t->map, hash, string_address); {string_address, *len_address}
Intern_String result = { };
{string_address, *len_address}
}; return result;
}
return result;
} //-----------------------------------------------------------------------------
// Array List
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Array List const int LIST_DEFAULT_BLOCK_SIZE = 16;
//----------------------------------------------------------------------------- const int LIST_DEFAULT_ALLOCATION_MUL = 2;
const int LIST_DEFAULT_BLOCK_SIZE = 16;
const int LIST_DEFAULT_ALLOCATION_MUL = 2; template <class T>
struct List_Node {
template <class T> List_Node<T> *next;
struct List_Node { List_Node<T> *prev;
List_Node<T> *next; int cap;
List_Node<T> *prev; int len;
int cap; T data[];
int len; };
T data[];
}; template <class T>
struct List {
template <class T> int block_size = 0;
struct List { int allocation_multiplier = 0;
int block_size = 0; List_Node<T> *first = 0;
int allocation_multiplier = 0; List_Node<T> *last = 0;
List_Node<T> *first = 0; List_Node<T> *first_free = 0;
List_Node<T> *last = 0;
List_Node<T> *first_free = 0; struct Iter {
T *item;
struct Iter { List_Node<T> *node;
T *item; int node_index;
List_Node<T> *node;
int node_index; T &operator*() { return *item; }
T &operator*() { return *item; } Iter &operator++() {
if (node) {
Iter &operator++() { if (node_index + 1 >= node->len) {
if (node) { node = node->next;
if (node_index + 1 >= node->len) { node_index = -1;
node = node->next; item = 0;
node_index = -1; }
item = 0;
} if (node) {
node_index += 1;
if (node) { item = node->data + node_index;
node_index += 1; }
item = node->data + node_index; }
} return *this;
} }
return *this; };
}
}; Iter begin() {
Iter result = {};
Iter begin() { result.node = first;
Iter result = {}; result.node_index = -1;
result.node = first; return ++result;
result.node_index = -1; }
return ++result; Iter end() { return {}; }
} friend bool operator!=(Iter &a, Iter &b) { return a.item != b.item; }
Iter end() { return {}; } };
friend bool operator!=(Iter &a, Iter &b) { return a.item != b.item; }
}; template <class T>
List_Node<T> *list_allocate_node(Allocator *arena, int size) {
template <class T> auto node = (List_Node<T> *)allocate_size(arena, sizeof(List_Node<T>) + size * sizeof(T), false);
List_Node<T> *list_allocate_node(Allocator *arena, int size) { node->cap = size;
auto node = (List_Node<T> *)allocate_size(arena, sizeof(List_Node<T>) + size * sizeof(T), false); node->len = 0;
node->cap = size; node->next = 0;
node->len = 0; node->prev = 0;
node->next = 0; return node;
node->prev = 0; }
return node;
} template <class T>
void list_allocate_free_node(Allocator *arena, List<T> *list, int size) {
template <class T> List_Node<T> *node = list_allocate_node<T>(arena, size);
void list_allocate_free_node(Allocator *arena, List<T> *list, int size) { DLL_STACK_ADD(list->first_free, node);
List_Node<T> *node = list_allocate_node<T>(arena, size); }
DLL_STACK_ADD(list->first_free, node);
} template <class T>
void list_make_sure_there_is_room_for_item_count(Allocator *arena, List<T> *list, int item_count) {
template <class T> if (list->last == 0 || list->last->len + item_count > list->last->cap) {
void list_make_sure_there_is_room_for_item_count(Allocator *arena, List<T> *list, int item_count) { // Not enough space we need to get a new block
if (list->last == 0 || list->last->len + item_count > list->last->cap) { List_Node<T> *node = 0;
// Not enough space we need to get a new block
List_Node<T> *node = 0; // Iterate the free list to check if we have a block of required size there
For_Linked_List(list->first_free) {
// Iterate the free list to check if we have a block of required size there if (it->cap >= item_count) {
For_Linked_List(list->first_free) { DLL_STACK_REMOVE(list->first_free, it);
if (it->cap >= item_count) { node = it;
DLL_STACK_REMOVE(list->first_free, it); node->len = 0;
node = it; break;
node->len = 0; }
break; }
}
} // We don't have a block on the free list need to allocate
if (!node) {
// We don't have a block on the free list need to allocate // Set default values if not initialized
if (!node) { if (!list->allocation_multiplier) list->allocation_multiplier = LIST_DEFAULT_ALLOCATION_MUL;
// Set default values if not initialized if (!list->block_size) list->block_size = LIST_DEFAULT_BLOCK_SIZE;
if (!list->allocation_multiplier) list->allocation_multiplier = LIST_DEFAULT_ALLOCATION_MUL;
if (!list->block_size) list->block_size = LIST_DEFAULT_BLOCK_SIZE; if (item_count > list->block_size)
list->block_size = item_count * 2;
if (item_count > list->block_size) node = list_allocate_node<T>(arena, list->block_size);
list->block_size = item_count * 2; list->block_size *= list->allocation_multiplier;
node = list_allocate_node<T>(arena, list->block_size); }
list->block_size *= list->allocation_multiplier;
} assert(node);
DLL_QUEUE_ADD(list->first, list->last, node);
assert(node); }
DLL_QUEUE_ADD(list->first, list->last, node); }
}
} template <class T>
T *list_get(List<T> *list, int index, List_Node<T> **node = 0, int *in_block_index = 0) {
template <class T> if (list) {
T *list_get(List<T> *list, int index, List_Node<T> **node = 0, int *in_block_index = 0) { int i = 0;
if (list) { For_Linked_List(list->first) {
int i = 0; int lookup_i = index - i;
For_Linked_List(list->first) { if (lookup_i < it->len) {
int lookup_i = index - i; if (node) *node = it;
if (lookup_i < it->len) { if (in_block_index) *in_block_index = lookup_i;
if (node) *node = it; return it->data + lookup_i;
if (in_block_index) *in_block_index = lookup_i; }
return it->data + lookup_i; i += it->len;
} }
i += it->len; }
} return 0;
} }
return 0;
} template <class T>
T *getp(List<T> *list, int index) {
template <class T> return list_get(list, index);
T *getp(List<T> *list, int index) { }
return list_get(list, index);
} template <class T>
T get(List<T> *list, int index) {
template <class T> return *list_get(list, index);
T get(List<T> *list, int index) { }
return *list_get(list, index);
} template <class T>
void add(Allocator *arena, List<T> *list, T item) {
template <class T> list_make_sure_there_is_room_for_item_count(arena, list, 1);
void add(Allocator *arena, List<T> *list, T item) { list->last->data[list->last->len++] = item;
list_make_sure_there_is_room_for_item_count(arena, list, 1); }
list->last->data[list->last->len++] = item;
} template <class T>
T *add_size(Allocator *arena, List<T> *list, int count = 1, int zero_memory = 0) {
template <class T> list_make_sure_there_is_room_for_item_count(arena, list, count);
T *add_size(Allocator *arena, List<T> *list, int count = 1, int zero_memory = 0) { T *result = list->last->data + list->last->len;
list_make_sure_there_is_room_for_item_count(arena, list, count); list->last->len += count;
T *result = list->last->data + list->last->len;
list->last->len += count; if (zero_memory) {
memory_zero(result, sizeof(T) * count);
if (zero_memory) { }
memory_zero(result, sizeof(T) * count);
} return result;
}
return result;
} template <class T>
void list_free_node(List<T> *list, List_Node<T> *node) {
template <class T> #if 1
void list_free_node(List<T> *list, List_Node<T> *node) { // Make sure it's actually in list list
#if 1 bool found = false;
// Make sure it's actually in list list For_Linked_List(list->first) {
bool found = false; if (it == node) {
For_Linked_List(list->first) { found = true;
if (it == node) { break;
found = true; }
break; }
} assert(found);
} #endif
assert(found);
#endif DLL_QUEUE_REMOVE(list->first, list->last, node);
DLL_STACK_ADD(list->first_free, node);
DLL_QUEUE_REMOVE(list->first, list->last, node); }
DLL_STACK_ADD(list->first_free, node);
} template <class T>
int length(List<T> *list) {
template <class T> int result = 0;
int length(List<T> *list) { For_Linked_List(list->first) {
int result = 0; result += it->len;
For_Linked_List(list->first) { }
result += it->len; return result;
} }
return result;
} template <class T>
void free_all_nodes(List<T> *list) {
template <class T> if (list->first == 0) return;
void free_all_nodes(List<T> *list) { assert(!list->last->next);
if (list->first == 0) return; assert(!list->first->prev);
assert(!list->last->next); list->last->next = list->first_free;
assert(!list->first->prev); if (list->first_free) list->first_free->prev = list->last;
list->last->next = list->first_free; list->first_free = list->first;
if (list->first_free) list->first_free->prev = list->last; list->last = list->first = 0;
list->first_free = list->first; }
list->last = list->first = 0;
} template <class T>
T ordered_remove(List<T> *list, int index) {
template <class T> List_Node<T> *node;
T ordered_remove(List<T> *list, int index) { int in_block_index;
List_Node<T> *node; T *data = list_get(list, index, &node, &in_block_index);
int in_block_index;
T *data = list_get(list, index, &node, &in_block_index); assert_message(data, "Trying to unordered_remove element that's outside of the List");
if (!data)
assert_message(data, "Trying to unordered_remove element that's outside of the List"); return {};
if (!data)
return {}; T result = *data;
T result = *data; // Check if we need to deallocate the block
if (node->len == 1) {
// Check if we need to deallocate the block list_free_node(list, node);
if (node->len == 1) { return result;
list_free_node(list, node); }
return result;
} // We need to move part of the block to fill the new empty spot
int right_count = (--node->len) - in_block_index;
// We need to move part of the block to fill the new empty spot memory_copy(data, data + 1, sizeof(T) * right_count);
int right_count = (--node->len) - in_block_index; return result;
memory_copy(data, data + 1, sizeof(T) * right_count); }
return result;
} template <class T>
T unordered_remove(List<T> *list, int index) {
template <class T> List_Node<T> *node;
T unordered_remove(List<T> *list, int index) { T *data = list_get(list, index, &node);
List_Node<T> *node;
T *data = list_get(list, index, &node); assert_message(data, "Trying to unordered_remove element that's outside of the List");
if (!data)
assert_message(data, "Trying to unordered_remove element that's outside of the List"); return {};
if (!data)
return {}; assert(node->len);
assert(node->cap);
assert(node->len);
assert(node->cap); // Swap
T result = *data;
// Swap *data = node->data[node->len - 1];
T result = *data;
*data = node->data[node->len - 1]; node->len -= 1;
if (node->len == 0) {
node->len -= 1; list_free_node(list, node);
if (node->len == 0) { }
list_free_node(list, node);
} return result;
}
return result;
} template <class T>
T pop(List<T> *list) {
template <class T> assert(list->last != 0);
T pop(List<T> *list) { assert(list->last->len > 0);
assert(list->last != 0); T result = list->last->data[--list->last->len];
assert(list->last->len > 0); if (list->last->len == 0) {
T result = list->last->data[--list->last->len]; list_free_node(list, list->last);
if (list->last->len == 0) { }
list_free_node(list, list->last); return result;
} }
return result;
} template <class T>
T *merge(Allocator *arena, List<T> *list) {
template <class T> int len = length(list);
T *merge(Allocator *arena, List<T> *list) { T *result = allocate_size(arena, T, len, false);
int len = length(list);
T *result = allocate_size(arena, T, len, false); int i = 0;
For_Linked_List(list->first) {
int i = 0; memory_copy(result + i, it->data, it->len * sizeof(T));
For_Linked_List(list->first) { i += it->len;
memory_copy(result + i, it->data, it->len * sizeof(T)); }
i += it->len;
} return result;
}
return result;
}

View File

@@ -1,478 +1,478 @@
CORE_Static U8 CORE_Static U8
to_lower_case(U8 a) { to_lower_case(U8 a) {
if (a >= 'A' && a <= 'Z') if (a >= 'A' && a <= 'Z')
a += 32; a += 32;
return a; return a;
} }
CORE_Static U8 CORE_Static U8
to_upper_case(U8 a) { to_upper_case(U8 a) {
if (a >= 'a' && a <= 'z') if (a >= 'a' && a <= 'z')
a -= 32; a -= 32;
return a; return a;
} }
CORE_Static U8 CORE_Static U8
char_to_lower(U8 c) { char_to_lower(U8 c) {
if (c >= 'A' && c <= 'Z') if (c >= 'A' && c <= 'Z')
c += 32; c += 32;
return c; return c;
} }
CORE_Static U8 CORE_Static U8
char_to_upper(U8 c) { char_to_upper(U8 c) {
if (c >= 'a' && c <= 'z') if (c >= 'a' && c <= 'z')
c -= 32; c -= 32;
return c; return c;
} }
CORE_Static B32 CORE_Static B32
is_whitespace(U8 w) { is_whitespace(U8 w) {
bool result = w == '\n' || w == ' ' || w == '\t' || w == '\v' || w == '\r'; bool result = w == '\n' || w == ' ' || w == '\t' || w == '\v' || w == '\r';
return result; return result;
} }
CORE_Static B32 CORE_Static B32
is_alphabetic(U8 a) { is_alphabetic(U8 a) {
if ((a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z')) { if ((a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z')) {
return true; return true;
} }
return false; return false;
} }
CORE_Static B32 CORE_Static B32
is_number(U8 a) { is_number(U8 a) {
B32 result = a >= '0' && a <= '9'; B32 result = a >= '0' && a <= '9';
return result; return result;
} }
CORE_Static B32 CORE_Static B32
is_alphanumeric(U8 a) { is_alphanumeric(U8 a) {
B32 result = is_number(a) || is_alphabetic(a); B32 result = is_number(a) || is_alphabetic(a);
return result; return result;
} }
CORE_Static S64 CORE_Static S64
string_len(char *string) { string_len(char *string) {
S64 len = 0; S64 len = 0;
while (*string++ != 0) len++; while (*string++ != 0) len++;
return len; return len;
} }
CORE_Static String CORE_Static String
string_from_cstring(char *string) { string_from_cstring(char *string) {
String result; String result;
result.str = (U8 *)string; result.str = (U8 *)string;
result.len = string_len(string); result.len = string_len(string);
return result; return result;
} }
CORE_Static B32 CORE_Static B32
string_compare(String a, String b, B32 ignore_case = false) { string_compare(String a, String b, B32 ignore_case = false) {
if (a.len != b.len) if (a.len != b.len)
return false; return false;
for (S64 i = 0; i < a.len; i++) { for (S64 i = 0; i < a.len; i++) {
U8 A = a.str[i]; U8 A = a.str[i];
U8 B = b.str[i]; U8 B = b.str[i];
if (ignore_case) { if (ignore_case) {
A = to_lower_case(A); A = to_lower_case(A);
B = to_lower_case(B); B = to_lower_case(B);
} }
if (A != B) if (A != B)
return false; return false;
} }
return true; return true;
} }
CORE_Static B32 CORE_Static B32
cstring_compare(char *a, char *b, B32 ignore_case = false) { cstring_compare(char *a, char *b, B32 ignore_case = false) {
return string_compare(string_from_cstring(a), string_from_cstring(b), ignore_case); return string_compare(string_from_cstring(a), string_from_cstring(b), ignore_case);
} }
CORE_Static B32 CORE_Static B32
operator==(String a, String b) { operator==(String a, String b) {
return string_compare(a, b); return string_compare(a, b);
} }
CORE_Static String CORE_Static String
string_copy(Allocator *a, String string) { string_copy(Allocator *a, String string) {
U8 *copy = allocate_array(a, U8, string.len + 1); U8 *copy = allocate_array(a, U8, string.len + 1);
memory_copy(copy, string.str, string.len); memory_copy(copy, string.str, string.len);
copy[string.len] = 0; copy[string.len] = 0;
return String{copy, string.len}; return String{copy, string.len};
} }
CORE_Static String CORE_Static String
string_fmtv(Allocator *a, const char *str, va_list args1) { string_fmtv(Allocator *a, const char *str, va_list args1) {
va_list args2; va_list args2;
va_copy(args2, args1); va_copy(args2, args1);
S64 len = stbsp_vsnprintf(0, 0, str, args2); S64 len = stbsp_vsnprintf(0, 0, str, args2);
va_end(args2); va_end(args2);
char *result = allocate_array(a, char, len + 1); char *result = allocate_array(a, char, len + 1);
stbsp_vsnprintf(result, (int)(len + 1), str, args1); stbsp_vsnprintf(result, (int)(len + 1), str, args1);
String res = {(U8 *)result, len}; String res = {(U8 *)result, len};
return res; return res;
} }
#define STRING_FMT(alloc, str, result) \ #define STRING_FMT(alloc, str, result) \
va_list args1; \ va_list args1; \
va_start(args1, str); \ va_start(args1, str); \
String result = string_fmtv(alloc, str, args1); \ String result = string_fmtv(alloc, str, args1); \
va_end(args1) va_end(args1)
CORE_Static String CORE_Static String
string_fmt(Allocator *a, const char *str, ...) { string_fmt(Allocator *a, const char *str, ...) {
STRING_FMT(a, str, result); STRING_FMT(a, str, result);
return result; return result;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// String builder // String builder
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
struct String_Builder_Block { struct String_Builder_Block {
String_Builder_Block *next; String_Builder_Block *next;
S64 cap; S64 cap;
S64 len; S64 len;
U8 data[0]; U8 data[0];
}; };
struct String_Builder { struct String_Builder {
Allocator *allocator; Allocator *allocator;
String_Builder_Block *first_free; String_Builder_Block *first_free;
String_Builder_Block *first; String_Builder_Block *first;
String_Builder_Block *last; String_Builder_Block *last;
U64 di; U64 di;
void reset() { void reset() {
for (; first;) { for (; first;) {
auto *block = first; auto *block = first;
first = first->next; first = first->next;
block->next = first_free; block->next = first_free;
first_free = block; first_free = block;
} }
last = 0; last = 0;
assert(!last && !first); assert(!last && !first);
} }
void push_block(size_t size) { void push_block(size_t size) {
String_Builder_Block *block = 0; String_Builder_Block *block = 0;
if (first_free) { if (first_free) {
block = first_free; block = first_free;
first_free = first_free->next; first_free = first_free->next;
} }
else { else {
block = (String_Builder_Block *)allocate_size(allocator, sizeof(String_Builder_Block) + size, false); block = (String_Builder_Block *)allocate_size(allocator, sizeof(String_Builder_Block) + size, false);
} }
memory_zero(block, sizeof(String_Builder_Block) + 1); // Also clear first byte of character data memory_zero(block, sizeof(String_Builder_Block) + 1); // Also clear first byte of character data
block->cap = size; block->cap = size;
SLL_QUEUE_ADD(first, last, block); SLL_QUEUE_ADD(first, last, block);
} }
void init(S64 size = 4096) { void init(S64 size = 4096) {
assert(allocator); assert(allocator);
push_block(size); push_block(size);
} }
void append_data(void *data, S64 size) { void append_data(void *data, S64 size) {
if (first == 0) { if (first == 0) {
init(); init();
} }
S64 remaining_cap = last->cap - last->len; S64 remaining_cap = last->cap - last->len;
if (size > remaining_cap) { if (size > remaining_cap) {
S64 new_block_size = max(last->cap * 2, size * 2); S64 new_block_size = max(last->cap * 2, size * 2);
push_block(new_block_size); push_block(new_block_size);
} }
U8 *write_address = last->data + last->len; U8 *write_address = last->data + last->len;
last->len += size; last->len += size;
memory_copy(write_address, data, size); memory_copy(write_address, data, size);
} }
void addf(const char *str, ...) { void addf(const char *str, ...) {
if (first == 0) { if (first == 0) {
init(); init();
} }
va_list args, args2; va_list args, args2;
va_start(args, str); va_start(args, str);
retry : { retry : {
String_Builder_Block *block = last; String_Builder_Block *block = last;
S64 block_size = block->cap - block->len; S64 block_size = block->cap - block->len;
char *write_address = (char *)block->data + block->len; char *write_address = (char *)block->data + block->len;
va_copy(args2, args); va_copy(args2, args);
int written = stbsp_vsnprintf(write_address, (int)block_size, str, args2); int written = stbsp_vsnprintf(write_address, (int)block_size, str, args2);
va_end(args2); va_end(args2);
if (written > (block_size - 1)) { if (written > (block_size - 1)) {
S64 new_block_size = max(4096, (written + 1) * 2); S64 new_block_size = max(4096, (written + 1) * 2);
push_block(new_block_size); push_block(new_block_size);
goto retry; goto retry;
} }
block->len += written; block->len += written;
} }
va_end(args); va_end(args);
di++; di++;
} }
}; };
CORE_Static String_Builder CORE_Static String_Builder
string_builder_make(Allocator *a, S64 first_block_size = 4096) { string_builder_make(Allocator *a, S64 first_block_size = 4096) {
String_Builder sb = {a}; String_Builder sb = {a};
sb.init(first_block_size); sb.init(first_block_size);
return sb; return sb;
} }
// @! Make string_flatten a method // @! Make string_flatten a method
static String string_flatten(Allocator *a, String_Builder *b) { static String string_flatten(Allocator *a, String_Builder *b) {
// @Note(Krzosa): Compute size to allocate // @Note(Krzosa): Compute size to allocate
S64 size = 1; S64 size = 1;
For_Linked_List(b->first) { For_Linked_List(b->first) {
size += it->len; size += it->len;
} }
String result = {}; String result = {};
result.str = (U8 *)allocate_size(a, size, false); result.str = (U8 *)allocate_size(a, size, false);
// @Note(Krzosa): Copy the content of each block into the string // @Note(Krzosa): Copy the content of each block into the string
For_Linked_List(b->first) { For_Linked_List(b->first) {
memory_copy(result.str + result.len, it->data, it->len); memory_copy(result.str + result.len, it->data, it->len);
result.len += it->len; result.len += it->len;
} }
result.str[result.len] = 0; result.str[result.len] = 0;
return result; return result;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// String ops // String ops
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
CORE_Static void CORE_Static void
string_path_normalize(String s) { string_path_normalize(String s) {
for (S64 i = 0; i < s.len; i++) { for (S64 i = 0; i < s.len; i++) {
if (s.str[i] == '\\') if (s.str[i] == '\\')
s.str[i] = '/'; s.str[i] = '/';
} }
} }
CORE_Static String CORE_Static String
string_make(char *str, S64 len) { string_make(char *str, S64 len) {
String result; String result;
result.str = (U8 *)str; result.str = (U8 *)str;
result.len = len; result.len = len;
return result; return result;
} }
CORE_Static String CORE_Static String
string_make(U8 *str, S64 len) { string_make(U8 *str, S64 len) {
return string_make((char *)str, len); return string_make((char *)str, len);
} }
CORE_Static String CORE_Static String
string_chop(String string, S64 len) { string_chop(String string, S64 len) {
len = clamp_top(len, string.len); len = clamp_top(len, string.len);
String result = string_make(string.str, string.len - len); String result = string_make(string.str, string.len - len);
return result; return result;
} }
CORE_Static String CORE_Static String
string_skip(String string, S64 len) { string_skip(String string, S64 len) {
len = clamp_top(len, string.len); len = clamp_top(len, string.len);
S64 remain = string.len - len; S64 remain = string.len - len;
String result = string_make(string.str + len, remain); String result = string_make(string.str + len, remain);
return result; return result;
} }
CORE_Static String CORE_Static String
string_get_postfix(String string, S64 len) { string_get_postfix(String string, S64 len) {
len = clamp_top(len, string.len); len = clamp_top(len, string.len);
S64 remain_len = string.len - len; S64 remain_len = string.len - len;
String result = string_make(string.str + remain_len, len); String result = string_make(string.str + remain_len, len);
return result; return result;
} }
CORE_Static String CORE_Static String
string_get_prefix(String string, S64 len) { string_get_prefix(String string, S64 len) {
len = clamp_top(len, string.len); len = clamp_top(len, string.len);
String result = string_make(string.str, len); String result = string_make(string.str, len);
return result; return result;
} }
CORE_Static String CORE_Static String
string_slice(String string, S64 first_index, S64 one_past_last_index) { string_slice(String string, S64 first_index, S64 one_past_last_index) {
assert_message(first_index < one_past_last_index, "string_slice, first_index is bigger then one_past_last_index"); assert_message(first_index < one_past_last_index, "string_slice, first_index is bigger then one_past_last_index");
assert_message(string.len > 0, "Slicing string of length 0! Might be an error!"); assert_message(string.len > 0, "Slicing string of length 0! Might be an error!");
String result = string; String result = string;
if (string.len > 0) { if (string.len > 0) {
if (one_past_last_index > first_index) { if (one_past_last_index > first_index) {
first_index = clamp_top(first_index, string.len - 1); first_index = clamp_top(first_index, string.len - 1);
one_past_last_index = clamp_top(one_past_last_index, string.len); one_past_last_index = clamp_top(one_past_last_index, string.len);
result.str += first_index; result.str += first_index;
result.len = one_past_last_index - first_index; result.len = one_past_last_index - first_index;
} }
else { else {
result.len = 0; result.len = 0;
} }
} }
return result; return result;
} }
CORE_Static String CORE_Static String
string_trim(String string) { string_trim(String string) {
if (string.len == 0) return string; if (string.len == 0) return string;
S64 whitespace_begin = 0; S64 whitespace_begin = 0;
for (; whitespace_begin < string.len; whitespace_begin++) { for (; whitespace_begin < string.len; whitespace_begin++) {
if (!is_whitespace(string.str[whitespace_begin])) { if (!is_whitespace(string.str[whitespace_begin])) {
break; break;
} }
} }
S64 whitespace_end = string.len; S64 whitespace_end = string.len;
for (; whitespace_end != whitespace_begin; whitespace_end--) { for (; whitespace_end != whitespace_begin; whitespace_end--) {
if (!is_whitespace(string.str[whitespace_end - 1])) { if (!is_whitespace(string.str[whitespace_end - 1])) {
break; break;
} }
} }
if (whitespace_begin == whitespace_end) { if (whitespace_begin == whitespace_end) {
string.len = 0; string.len = 0;
} }
else { else {
string = string_slice(string, whitespace_begin, whitespace_end); string = string_slice(string, whitespace_begin, whitespace_end);
} }
return string; return string;
} }
CORE_Static String CORE_Static String
string_trim_end(String string) { string_trim_end(String string) {
S64 whitespace_end = string.len; S64 whitespace_end = string.len;
for (; whitespace_end != 0; whitespace_end--) { for (; whitespace_end != 0; whitespace_end--) {
if (!is_whitespace(string.str[whitespace_end - 1])) { if (!is_whitespace(string.str[whitespace_end - 1])) {
break; break;
} }
} }
String result = string_get_prefix(string, whitespace_end); String result = string_get_prefix(string, whitespace_end);
return result; return result;
} }
CORE_Static String CORE_Static String
string_to_lower_case(Allocator *arena, String s) { string_to_lower_case(Allocator *arena, String s) {
String copy = string_copy(arena, s); String copy = string_copy(arena, s);
for (S64 i = 0; i < copy.len; i++) { for (S64 i = 0; i < copy.len; i++) {
copy.str[i] = to_lower_case(copy.str[i]); copy.str[i] = to_lower_case(copy.str[i]);
} }
return copy; return copy;
} }
CORE_Static String CORE_Static String
string_to_upper_case(Allocator *arena, String s) { string_to_upper_case(Allocator *arena, String s) {
String copy = string_copy(arena, s); String copy = string_copy(arena, s);
for (S64 i = 0; i < copy.len; i++) { for (S64 i = 0; i < copy.len; i++) {
copy.str[i] = to_upper_case(copy.str[i]); copy.str[i] = to_upper_case(copy.str[i]);
} }
return copy; return copy;
} }
typedef U32 MatchFlag; typedef U32 MatchFlag;
enum { enum {
MatchFlag_None = 0, MatchFlag_None = 0,
MatchFlag_FindLast = 1, MatchFlag_FindLast = 1,
MatchFlag_IgnoreCase = 2, MatchFlag_IgnoreCase = 2,
}; };
CORE_Static B32 CORE_Static B32
string_find(String string, String find, MatchFlag flags, S64 *index_out) { string_find(String string, String find, MatchFlag flags, S64 *index_out) {
B32 result = false; B32 result = false;
if (flags & MatchFlag_FindLast) { if (flags & MatchFlag_FindLast) {
for (S64 i = string.len; i != 0; i--) { for (S64 i = string.len; i != 0; i--) {
S64 index = i - 1; S64 index = i - 1;
String substring = string_slice(string, index, index + find.len); String substring = string_slice(string, index, index + find.len);
if (string_compare(substring, find, flags & MatchFlag_IgnoreCase)) { if (string_compare(substring, find, flags & MatchFlag_IgnoreCase)) {
if (index_out) if (index_out)
*index_out = index; *index_out = index;
result = true; result = true;
break; break;
} }
} }
} }
else { else {
for (S64 i = 0; i < string.len; i++) { for (S64 i = 0; i < string.len; i++) {
String substring = string_slice(string, i, i + find.len); String substring = string_slice(string, i, i + find.len);
if (string_compare(substring, find, flags & MatchFlag_IgnoreCase)) { if (string_compare(substring, find, flags & MatchFlag_IgnoreCase)) {
if (index_out) if (index_out)
*index_out = i; *index_out = i;
result = true; result = true;
break; break;
} }
} }
} }
return result; return result;
} }
CORE_Static String CORE_Static String
string_chop_last_slash(String s) { string_chop_last_slash(String s) {
String result = s; String result = s;
string_find(s, "/"_s, MatchFlag_FindLast, &result.len); string_find(s, "/"_s, MatchFlag_FindLast, &result.len);
return result; return result;
} }
CORE_Static String CORE_Static String
string_chop_last_period(String s) { string_chop_last_period(String s) {
String result = s; String result = s;
string_find(s, "."_s, MatchFlag_FindLast, &result.len); string_find(s, "."_s, MatchFlag_FindLast, &result.len);
return result; return result;
} }
CORE_Static String CORE_Static String
string_skip_to_last_slash(String s) { string_skip_to_last_slash(String s) {
S64 pos; S64 pos;
String result = s; String result = s;
if (string_find(s, "/"_s, MatchFlag_FindLast, &pos)) { if (string_find(s, "/"_s, MatchFlag_FindLast, &pos)) {
result = string_skip(result, pos + 1); result = string_skip(result, pos + 1);
} }
return result; return result;
} }
CORE_Static String CORE_Static String
string_skip_to_last_period(String s) { string_skip_to_last_period(String s) {
S64 pos; S64 pos;
String result = s; String result = s;
if (string_find(s, "."_s, MatchFlag_FindLast, &pos)) { if (string_find(s, "."_s, MatchFlag_FindLast, &pos)) {
result = string_skip(result, pos + 1); result = string_skip(result, pos + 1);
} }
return result; return result;
} }
struct String_Replace { struct String_Replace {
String find; String find;
String replace; String replace;
}; };
CORE_Static String CORE_Static String
string_replace(Arena *scratch, Allocator *allocator, String string, Array<String_Replace> pairs) { string_replace(Arena *scratch, Allocator *allocator, String string, Array<String_Replace> pairs) {
Scoped_Arena _scope(scratch); Scoped_Arena _scope(scratch);
String_Builder builder = {scratch}; String_Builder builder = {scratch};
for (S64 i = 0; i < string.len; i++) { for (S64 i = 0; i < string.len; i++) {
For(pairs) { For(pairs) {
String current = string_skip(string, i); String current = string_skip(string, i);
current = string_get_prefix(current, it.find.len); current = string_get_prefix(current, it.find.len);
if (current == it.find) { if (current == it.find) {
builder.append_data(it.replace.str, it.replace.len); builder.append_data(it.replace.str, it.replace.len);
i += it.find.len; i += it.find.len;
continue; continue;
} }
} }
builder.append_data(string.str + i, 1); builder.append_data(string.str + i, 1);
} }
return string_flatten(allocator, &builder); return string_flatten(allocator, &builder);
} }

View File

@@ -1,274 +1,274 @@
global U32 question_mark32 = '?'; global U32 question_mark32 = '?';
global U16 question_mark16 = 0x003f; global U16 question_mark16 = 0x003f;
global U8 question_mark8 = '?'; global U8 question_mark8 = '?';
struct String32 { struct String32 {
U32 *str; U32 *str;
S64 len; S64 len;
}; };
struct UTF32_Result { struct UTF32_Result {
U32 out_str; U32 out_str;
S64 advance; S64 advance;
B32 error; B32 error;
}; };
CORE_Static UTF32_Result CORE_Static UTF32_Result
utf8_to_utf32(U8 *c, S64 max_advance) { utf8_to_utf32(U8 *c, S64 max_advance) {
UTF32_Result result = {}; UTF32_Result result = {};
if ((c[0] & 0b10000000) == 0) { // Check if leftmost zero of first byte is unset if ((c[0] & 0b10000000) == 0) { // Check if leftmost zero of first byte is unset
if (max_advance >= 1) { if (max_advance >= 1) {
result.out_str = c[0]; result.out_str = c[0];
result.advance = 1; result.advance = 1;
} }
else result.error = 1; else result.error = 1;
} }
else if ((c[0] & 0b11100000) == 0b11000000) { else if ((c[0] & 0b11100000) == 0b11000000) {
if ((c[1] & 0b11000000) == 0b10000000) { // Continuation byte required if ((c[1] & 0b11000000) == 0b10000000) { // Continuation byte required
if (max_advance >= 2) { if (max_advance >= 2) {
result.out_str = (U32)(c[0] & 0b00011111) << 6u | (c[1] & 0b00111111); result.out_str = (U32)(c[0] & 0b00011111) << 6u | (c[1] & 0b00111111);
result.advance = 2; result.advance = 2;
} }
else result.error = 2; else result.error = 2;
} }
else result.error = 2; else result.error = 2;
} }
else if ((c[0] & 0b11110000) == 0b11100000) { else if ((c[0] & 0b11110000) == 0b11100000) {
if ((c[1] & 0b11000000) == 0b10000000 && (c[2] & 0b11000000) == 0b10000000) { // Two continuation bytes required if ((c[1] & 0b11000000) == 0b10000000 && (c[2] & 0b11000000) == 0b10000000) { // Two continuation bytes required
if (max_advance >= 3) { if (max_advance >= 3) {
result.out_str = (U32)(c[0] & 0b00001111) << 12u | (U32)(c[1] & 0b00111111) << 6u | (c[2] & 0b00111111); result.out_str = (U32)(c[0] & 0b00001111) << 12u | (U32)(c[1] & 0b00111111) << 6u | (c[2] & 0b00111111);
result.advance = 3; result.advance = 3;
} }
else result.error = 3; else result.error = 3;
} }
else result.error = 3; else result.error = 3;
} }
else if ((c[0] & 0b11111000) == 0b11110000) { else if ((c[0] & 0b11111000) == 0b11110000) {
if ((c[1] & 0b11000000) == 0b10000000 && (c[2] & 0b11000000) == 0b10000000 && (c[3] & 0b11000000) == 0b10000000) { // Three continuation bytes required if ((c[1] & 0b11000000) == 0b10000000 && (c[2] & 0b11000000) == 0b10000000 && (c[3] & 0b11000000) == 0b10000000) { // Three continuation bytes required
if (max_advance >= 4) { if (max_advance >= 4) {
result.out_str = (U32)(c[0] & 0b00001111) << 18u | (U32)(c[1] & 0b00111111) << 12u | (U32)(c[2] & 0b00111111) << 6u | (U32)(c[3] & 0b00111111); result.out_str = (U32)(c[0] & 0b00001111) << 18u | (U32)(c[1] & 0b00111111) << 12u | (U32)(c[2] & 0b00111111) << 6u | (U32)(c[3] & 0b00111111);
result.advance = 4; result.advance = 4;
} }
else result.error = 4; else result.error = 4;
} }
else result.error = 4; else result.error = 4;
} }
else result.error = 4; else result.error = 4;
return result; return result;
} }
struct String16 { struct String16 {
U16 *str; U16 *str;
S64 len; S64 len;
}; };
struct UTF16_Result { struct UTF16_Result {
U16 out_str[2]; U16 out_str[2];
S32 len; S32 len;
B32 error; B32 error;
}; };
CORE_Static UTF16_Result CORE_Static UTF16_Result
utf32_to_utf16(U32 codepoint) { utf32_to_utf16(U32 codepoint) {
UTF16_Result result = {}; UTF16_Result result = {};
if (codepoint < 0x10000) { if (codepoint < 0x10000) {
result.out_str[0] = (U16)codepoint; result.out_str[0] = (U16)codepoint;
result.out_str[1] = 0; result.out_str[1] = 0;
result.len = 1; result.len = 1;
} }
else if (codepoint <= 0x10FFFF) { else if (codepoint <= 0x10FFFF) {
U32 code = (codepoint - 0x10000); U32 code = (codepoint - 0x10000);
result.out_str[0] = (U16)(0xD800 | (code >> 10)); result.out_str[0] = (U16)(0xD800 | (code >> 10));
result.out_str[1] = (U16)(0xDC00 | (code & 0x3FF)); result.out_str[1] = (U16)(0xDC00 | (code & 0x3FF));
result.len = 2; result.len = 2;
} }
else { else {
result.error = 1; result.error = 1;
} }
return result; return result;
} }
struct UTF8_Result { struct UTF8_Result {
U8 out_str[4]; U8 out_str[4];
S32 len; S32 len;
B32 error; B32 error;
}; };
CORE_Static UTF8_Result CORE_Static UTF8_Result
utf32_to_utf8(U32 codepoint) { utf32_to_utf8(U32 codepoint) {
UTF8_Result result = {}; UTF8_Result result = {};
if (codepoint <= 0x7F) { if (codepoint <= 0x7F) {
result.len = 1; result.len = 1;
result.out_str[0] = (U8)codepoint; result.out_str[0] = (U8)codepoint;
} }
else if (codepoint <= 0x7FF) { else if (codepoint <= 0x7FF) {
result.len = 2; result.len = 2;
result.out_str[0] = 0b11000000 | (0b00011111 & (codepoint >> 6)); result.out_str[0] = 0b11000000 | (0b00011111 & (codepoint >> 6));
result.out_str[1] = 0b10000000 | (0b00111111 & codepoint); result.out_str[1] = 0b10000000 | (0b00111111 & codepoint);
} }
else if (codepoint <= 0xFFFF) { // 16 bit word else if (codepoint <= 0xFFFF) { // 16 bit word
result.len = 3; result.len = 3;
result.out_str[0] = 0b11100000 | (0b00001111 & (codepoint >> 12)); // 4 bits result.out_str[0] = 0b11100000 | (0b00001111 & (codepoint >> 12)); // 4 bits
result.out_str[1] = 0b10000000 | (0b00111111 & (codepoint >> 6)); // 6 bits result.out_str[1] = 0b10000000 | (0b00111111 & (codepoint >> 6)); // 6 bits
result.out_str[2] = 0b10000000 | (0b00111111 & codepoint); // 6 bits result.out_str[2] = 0b10000000 | (0b00111111 & codepoint); // 6 bits
} }
else if (codepoint <= 0x10FFFF) { // 21 bit word else if (codepoint <= 0x10FFFF) { // 21 bit word
result.len = 4; result.len = 4;
result.out_str[0] = 0b11110000 | (0b00000111 & (codepoint >> 18)); // 3 bits result.out_str[0] = 0b11110000 | (0b00000111 & (codepoint >> 18)); // 3 bits
result.out_str[1] = 0b10000000 | (0b00111111 & (codepoint >> 12)); // 6 bits result.out_str[1] = 0b10000000 | (0b00111111 & (codepoint >> 12)); // 6 bits
result.out_str[2] = 0b10000000 | (0b00111111 & (codepoint >> 6)); // 6 bits result.out_str[2] = 0b10000000 | (0b00111111 & (codepoint >> 6)); // 6 bits
result.out_str[3] = 0b10000000 | (0b00111111 & codepoint); // 6 bits result.out_str[3] = 0b10000000 | (0b00111111 & codepoint); // 6 bits
} }
else { else {
result.error = true; result.error = true;
} }
return result; return result;
} }
CORE_Static UTF32_Result CORE_Static UTF32_Result
utf16_to_utf32(U16 *c, S32 max_advance) { utf16_to_utf32(U16 *c, S32 max_advance) {
UTF32_Result result = {}; UTF32_Result result = {};
if (max_advance >= 1) { if (max_advance >= 1) {
result.advance = 1; result.advance = 1;
result.out_str = c[0]; result.out_str = c[0];
if (c[0] >= 0xD800 && c[0] <= 0xDBFF && c[1] >= 0xDC00 && c[1] <= 0xDFFF) { if (c[0] >= 0xD800 && c[0] <= 0xDBFF && c[1] >= 0xDC00 && c[1] <= 0xDFFF) {
if (max_advance >= 2) { if (max_advance >= 2) {
result.out_str = 0x10000; result.out_str = 0x10000;
result.out_str += (U32)(c[0] & 0x03FF) << 10u | (c[1] & 0x03FF); result.out_str += (U32)(c[0] & 0x03FF) << 10u | (c[1] & 0x03FF);
result.advance = 2; result.advance = 2;
} }
else result.error = 2; else result.error = 2;
} }
} }
else result.error = 1; else result.error = 1;
return result; return result;
} }
#define unicode_error(question_mark) \ #define unicode_error(question_mark) \
{ \ { \
result.str[result.len++] = question_mark; \ result.str[result.len++] = question_mark; \
break; \ break; \
} }
CORE_Static String32 CORE_Static String32
string16_to_string32(Allocator *allocator, String16 string) { string16_to_string32(Allocator *allocator, String16 string) {
String32 result = {allocate_array(allocator, U32, string.len + 1)}; String32 result = {allocate_array(allocator, U32, string.len + 1)};
for (S64 i = 0; i < string.len;) { for (S64 i = 0; i < string.len;) {
UTF32_Result decode = utf16_to_utf32(string.str + i, (S32)(string.len - i)); UTF32_Result decode = utf16_to_utf32(string.str + i, (S32)(string.len - i));
if (!decode.error) { if (!decode.error) {
i += decode.advance; i += decode.advance;
result.str[result.len++] = decode.out_str; result.str[result.len++] = decode.out_str;
} }
else unicode_error(question_mark32); else unicode_error(question_mark32);
} }
result.str[result.len] = 0; result.str[result.len] = 0;
return result; return result;
} }
CORE_Static String32 CORE_Static String32
string8_to_string32(Allocator *allocator, String string) { string8_to_string32(Allocator *allocator, String string) {
String32 result = {allocate_array(allocator, U32, string.len + 1)}; String32 result = {allocate_array(allocator, U32, string.len + 1)};
for (S64 i = 0; i < string.len;) { for (S64 i = 0; i < string.len;) {
UTF32_Result decode = utf8_to_utf32(string.str + i, string.len - i); UTF32_Result decode = utf8_to_utf32(string.str + i, string.len - i);
if (!decode.error) { if (!decode.error) {
i += decode.advance; i += decode.advance;
result.str[result.len++] = decode.out_str; result.str[result.len++] = decode.out_str;
} }
else unicode_error(question_mark32); else unicode_error(question_mark32);
} }
result.str[result.len] = 0; result.str[result.len] = 0;
return result; return result;
} }
CORE_Static String16 CORE_Static String16
string8_to_string16(Allocator *allocator, String in) { string8_to_string16(Allocator *allocator, String in) {
String16 result = {allocate_array(allocator, U16, (in.len * 2) + 1)}; // @Note(Krzosa): Should be more then enough space String16 result = {allocate_array(allocator, U16, (in.len * 2) + 1)}; // @Note(Krzosa): Should be more then enough space
for (S64 i = 0; i < in.len;) { for (S64 i = 0; i < in.len;) {
UTF32_Result decode = utf8_to_utf32(in.str + i, in.len - i); UTF32_Result decode = utf8_to_utf32(in.str + i, in.len - i);
if (!decode.error) { if (!decode.error) {
i += decode.advance; i += decode.advance;
UTF16_Result encode = utf32_to_utf16(decode.out_str); UTF16_Result encode = utf32_to_utf16(decode.out_str);
if (!encode.error) { if (!encode.error) {
for (S32 j = 0; j < encode.len; j++) { for (S32 j = 0; j < encode.len; j++) {
result.str[result.len++] = encode.out_str[j]; result.str[result.len++] = encode.out_str[j];
} }
} }
else unicode_error(question_mark16); else unicode_error(question_mark16);
} }
else unicode_error(question_mark16); else unicode_error(question_mark16);
} }
result.str[result.len] = 0; result.str[result.len] = 0;
return result; return result;
} }
CORE_Static String CORE_Static String
string16_to_string8(Allocator *allocator, String16 in) { string16_to_string8(Allocator *allocator, String16 in) {
String result = {allocate_array(allocator, U8, in.len * 4 + 1)}; String result = {allocate_array(allocator, U8, in.len * 4 + 1)};
for (S64 i = 0; i < in.len;) { for (S64 i = 0; i < in.len;) {
UTF32_Result decode = utf16_to_utf32(in.str + i, (S32)(in.len - i)); UTF32_Result decode = utf16_to_utf32(in.str + i, (S32)(in.len - i));
if (!decode.error) { if (!decode.error) {
i += decode.advance; i += decode.advance;
UTF8_Result encode = utf32_to_utf8(decode.out_str); UTF8_Result encode = utf32_to_utf8(decode.out_str);
if (!encode.error) { if (!encode.error) {
for (S32 j = 0; j < encode.len; j++) for (S32 j = 0; j < encode.len; j++)
result.str[result.len++] = encode.out_str[j]; result.str[result.len++] = encode.out_str[j];
} }
else unicode_error(question_mark8); else unicode_error(question_mark8);
} }
else unicode_error(question_mark8); else unicode_error(question_mark8);
} }
result.str[result.len] = 0; result.str[result.len] = 0;
return result; return result;
} }
CORE_Static B32 CORE_Static B32
string_compare(String16 a, String16 b) { string_compare(String16 a, String16 b) {
if (a.len != b.len) return false; if (a.len != b.len) return false;
for (S64 i = 0; i < a.len; i++) { for (S64 i = 0; i < a.len; i++) {
if (a.str[i] != b.str[i]) return false; if (a.str[i] != b.str[i]) return false;
} }
return true; return true;
} }
CORE_Static B32 CORE_Static B32
string_compare(String32 a, String32 b) { string_compare(String32 a, String32 b) {
if (a.len != b.len) return false; if (a.len != b.len) return false;
for (S64 i = 0; i < a.len; i++) { for (S64 i = 0; i < a.len; i++) {
if (a.str[i] != b.str[i]) return false; if (a.str[i] != b.str[i]) return false;
} }
return true; return true;
} }
CORE_Static S64 CORE_Static S64
widechar_len(wchar_t *string) { widechar_len(wchar_t *string) {
S64 len = 0; S64 len = 0;
while (*string++ != 0) len++; while (*string++ != 0) len++;
return len; return len;
} }
CORE_Static String16 CORE_Static String16
string16_from_widechar(wchar_t *string) { string16_from_widechar(wchar_t *string) {
String16 result; String16 result;
result.str = (U16 *)string; result.str = (U16 *)string;
result.len = widechar_len(string); result.len = widechar_len(string);
return result; return result;
} }
CORE_Static String CORE_Static String
string16_copy(Allocator *a, String string) { string16_copy(Allocator *a, String string) {
U8 *copy = allocate_array(a, U8, string.len + 1); U8 *copy = allocate_array(a, U8, string.len + 1);
memory_copy(copy, string.str, string.len); memory_copy(copy, string.str, string.len);
copy[string.len] = 0; copy[string.len] = 0;
return String{copy, string.len}; return String{copy, string.len};
} }

21
src/base/defer.hpp Normal file
View File

@@ -0,0 +1,21 @@
#define DEFER_HEADER
template <typename T>
struct DEFER_ExitScope {
T lambda;
DEFER_ExitScope(T lambda) : lambda(lambda) {}
~DEFER_ExitScope() { lambda(); }
DEFER_ExitScope(const DEFER_ExitScope &i) : lambda(i.lambda){};
private:
DEFER_ExitScope &operator=(const DEFER_ExitScope &);
};
class DEFER_ExitScopeHelp {
public:
template <typename T>
DEFER_ExitScope<T> operator+(T t) { return t; }
};
#define DEFER_CONCAT_INTERNAL(x, y) x##y
#define DEFER_CONCAT(x, y) DEFER_CONCAT_INTERNAL(x, y)
#define Defer const auto DEFER_CONCAT(defer__, __LINE__) = DEFER_ExitScopeHelp() + [&]()

131
src/base/linked_list.h Normal file
View File

@@ -0,0 +1,131 @@
#ifndef LINKED_LIST_HEADER
#define LINKED_LIST_HEADER
#define GET_ARRAY_SIZE(x) ((sizeof(x) / sizeof((x)[0])))
#define SLL_QUEUE_ADD_MOD(f, l, n, next) \
do { \
(n)->next = 0; \
if ((f) == 0) { \
(f) = (l) = (n); \
} \
else { \
(l) = (l)->next = (n); \
} \
} while (0)
#define SLL_QUEUE_ADD(f, l, n) SLL_QUEUE_ADD_MOD(f, l, n, next)
#define SLL_QUEUE_POP_FIRST_MOD(f, l, next) \
do { \
if ((f) == (l)) { \
(f) = (l) = 0; \
} \
else { \
(f) = (f)->next; \
} \
} while (0)
#define SLL_QUEUE_POP_FIRST(f, l) SLL_QUEUE_POP_FIRST_MOD(f, l, next)
#define SLL_STACK_ADD_MOD(stack_base, new_stack_base, next) \
do { \
(new_stack_base)->next = (stack_base); \
(stack_base) = (new_stack_base); \
} while (0)
#define SLL_STACK_ADD(stack_base, new_stack_base) \
SLL_STACK_ADD_MOD(stack_base, new_stack_base, next)
#define SLL_STACK_POP_AND_STORE(stack_base, out_node) \
do { \
if (stack_base) { \
(out_node) = (stack_base); \
(stack_base) = (stack_base)->next; \
(out_node)->next = 0; \
} \
} while (0)
#define DLL_QUEUE_ADD_MOD(f, l, node, next, prev) \
do { \
if ((f) == 0) { \
(f) = (l) = (node); \
(node)->prev = 0; \
(node)->next = 0; \
} \
else { \
(l)->next = (node); \
(node)->prev = (l); \
(node)->next = 0; \
(l) = (node); \
} \
} while (0)
#define DLL_QUEUE_ADD(f, l, node) DLL_QUEUE_ADD_MOD(f, l, node, next, prev)
#define DLL_QUEUE_REMOVE_MOD(first, last, node, next, prev) \
do { \
if ((first) == (last)) { \
IO_Assertf((node) == (first), "Not you are trying to remove is not in the list"); \
(first) = (last) = 0; \
} \
else if ((last) == (node)) { \
(last) = (last)->prev; \
(last)->next = 0; \
} \
else if ((first) == (node)) { \
(first) = (first)->next; \
(first)->prev = 0; \
} \
else { \
(node)->prev->next = (node)->next; \
(node)->next->prev = (node)->prev; \
} \
if (node) { \
(node)->prev = 0; \
(node)->next = 0; \
} \
} while (0)
#define DLL_QUEUE_REMOVE(first, last, node) DLL_QUEUE_REMOVE_MOD(first, last, node, next, prev)
#define DLL_STACK_ADD_MOD(first, node, next, prev) \
do { \
(node)->next = (first); \
if ((first)) \
(first)->prev = (node); \
(first) = (node); \
(node)->prev = 0; \
} while (0)
#define DLL_STACK_ADD(first, node) DLL_STACK_ADD_MOD(first, node, next, prev)
#define DLL_STACK_REMOVE_MOD(first, node, next, prev) \
do { \
if ((node) == (first)) { \
(first) = (first)->next; \
if ((first)) \
(first)->prev = 0; \
} \
else { \
(node)->prev->next = (node)->next; \
if ((node)->next) \
(node)->next->prev = (node)->prev; \
} \
if (node) { \
(node)->prev = 0; \
(node)->next = 0; \
} \
} while (0)
#define DLL_STACK_REMOVE(first, node) DLL_STACK_REMOVE_MOD(first, node, next, prev)
#define DLL_INSERT_NEXT_MOD(base, new, next, prev) \
do { \
if ((base) == 0) { \
(base) = (new); \
(new)->next = 0; \
(new)->prev = 0; \
} \
else { \
(new)->next = (base)->next; \
(base)->next = (new); \
(new)->prev = (base); \
if ((new)->next) (new)->next->prev = (new); \
} \
} while (0)
#define DLL_INSERT_NEXT(base, new) DLL_INSERT_NEXT_MOD(base, new, next, prev)
#define DLL_INSERT_PREV(base, new) DLL_INSERT_NEXT_MOD(base, new, next, prev)
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,56 +1,56 @@
struct Token; struct Token;
#include <inttypes.h> #include <inttypes.h>
enum CmpRes { enum CmpRes {
CMP_LT, CMP_LT,
CMP_GT, CMP_GT,
CMP_EQ, CMP_EQ,
}; };
#define malloc_arena(x) allocate_size(bigint_allocator, x) #define malloc_arena(x) allocate_size(bigint_allocator, x)
#define ALLOC_DIGITS(_digits) (uint64_t *)((_digits) ? malloc_arena(sizeof(uint64_t) * (_digits)) : NULL) #define ALLOC_DIGITS(_digits) (uint64_t *)((_digits) ? malloc_arena(sizeof(uint64_t) * (_digits)) : NULL)
#define FATAL_ERROR(x) compiler_error(0, x) #define FATAL_ERROR(x) compiler_error(0, x)
CORE_Static void compiler_error(Token *token, const char *str, ...); CORE_Static void compiler_error(Token *token, const char *str, ...);
const char *bigint_to_error_string(Allocator *allocator, const BigInt *bigint, uint64_t base); const char *bigint_to_error_string(Allocator *allocator, const BigInt *bigint, uint64_t base);
void bigint_init_unsigned(BigInt *big_int, uint64_t value); void bigint_init_unsigned(BigInt *big_int, uint64_t value);
void bigint_init_signed(BigInt *big_int, int64_t value); void bigint_init_signed(BigInt *big_int, int64_t value);
void bigint_init_bigint(BigInt *dest, const BigInt *src); void bigint_init_bigint(BigInt *dest, const BigInt *src);
void bigint_init_data(BigInt *dest, const uint64_t *digits, unsigned int digit_count, bool is_negative); void bigint_init_data(BigInt *dest, const uint64_t *digits, unsigned int digit_count, bool is_negative);
void bigint_negate(BigInt *dest, const BigInt *source); void bigint_negate(BigInt *dest, const BigInt *source);
size_t bigint_clz(const BigInt *big_int, size_t bit_count); size_t bigint_clz(const BigInt *big_int, size_t bit_count);
size_t bigint_ctz(const BigInt *big_int, size_t bit_count); size_t bigint_ctz(const BigInt *big_int, size_t bit_count);
bool bigint_fits_in_bits(const BigInt *big_int, size_t bit_count, bool is_signed); bool bigint_fits_in_bits(const BigInt *big_int, size_t bit_count, bool is_signed);
void bigint_write_twos_complement(const BigInt *big_int, uint8_t *buf, size_t bit_count, bool is_big_endian); void bigint_write_twos_complement(const BigInt *big_int, uint8_t *buf, size_t bit_count, bool is_big_endian);
void bigint_read_twos_complement(BigInt *dest, const uint8_t *buf, size_t bit_count, bool is_big_endian, bool is_signed); void bigint_read_twos_complement(BigInt *dest, const uint8_t *buf, size_t bit_count, bool is_big_endian, bool is_signed);
void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2); void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2);
void bigint_add_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed); void bigint_add_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed);
void bigint_sub(BigInt *dest, const BigInt *op1, const BigInt *op2); void bigint_sub(BigInt *dest, const BigInt *op1, const BigInt *op2);
void bigint_sub_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed); void bigint_sub_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed);
void bigint_mul(BigInt *dest, const BigInt *op1, const BigInt *op2); void bigint_mul(BigInt *dest, const BigInt *op1, const BigInt *op2);
void bigint_mul_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed); void bigint_mul_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed);
void bigint_rem(BigInt *dest, const BigInt *op1, const BigInt *op2); void bigint_rem(BigInt *dest, const BigInt *op1, const BigInt *op2);
void bigint_mod(BigInt *dest, const BigInt *op1, const BigInt *op2); void bigint_mod(BigInt *dest, const BigInt *op1, const BigInt *op2);
void bigint_shl(BigInt *dest, const BigInt *op1, const BigInt *op2); void bigint_shl(BigInt *dest, const BigInt *op1, const BigInt *op2);
void bigint_shl_int(BigInt *dest, const BigInt *op1, uint64_t shift); void bigint_shl_int(BigInt *dest, const BigInt *op1, uint64_t shift);
void bigint_shl_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed); void bigint_shl_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed);
void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2); void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2);
void bigint_div_floor(BigInt *dest, const BigInt *op1, const BigInt *op2); void bigint_div_floor(BigInt *dest, const BigInt *op1, const BigInt *op2);
void bigint_or(BigInt *dest, const BigInt *op1, const BigInt *op2); void bigint_or(BigInt *dest, const BigInt *op1, const BigInt *op2);
void bigint_and(BigInt *dest, const BigInt *op1, const BigInt *op2); void bigint_and(BigInt *dest, const BigInt *op1, const BigInt *op2);
void bigint_xor(BigInt *dest, const BigInt *op1, const BigInt *op2); void bigint_xor(BigInt *dest, const BigInt *op1, const BigInt *op2);
void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count); void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count);
void bigint_not(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed); void bigint_not(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed);
bool bigint_eql(BigInt a, BigInt b); bool bigint_eql(BigInt a, BigInt b);
CmpRes bigint_cmp(const BigInt *op1, const BigInt *op2); CmpRes bigint_cmp(const BigInt *op1, const BigInt *op2);
CmpRes bigint_cmp_zero(const BigInt *op); CmpRes bigint_cmp_zero(const BigInt *op);
uint32_t bigint_hash(BigInt x); uint32_t bigint_hash(BigInt x);
void bigint_print(BigInt *bigint, uint64_t base); void bigint_print(BigInt *bigint, uint64_t base);
void bigint_fprint(FILE *file, BigInt *bigint, uint64_t base); void bigint_fprint(FILE *file, BigInt *bigint, uint64_t base);
uint64_t bigint_as_unsigned(const BigInt *bigint); uint64_t bigint_as_unsigned(const BigInt *bigint);
int64_t bigint_as_signed(const BigInt *bigint); int64_t bigint_as_signed(const BigInt *bigint);
double bigint_as_float(const BigInt *bigint); double bigint_as_float(const BigInt *bigint);
void bigint_truncate(BigInt *dst, const BigInt *op, size_t bit_count, bool is_signed); void bigint_truncate(BigInt *dst, const BigInt *op, size_t bit_count, bool is_signed);
void bigint_incr(BigInt *x); void bigint_incr(BigInt *x);
size_t bigint_popcount_signed(const BigInt *bi, size_t bit_count); size_t bigint_popcount_signed(const BigInt *bi, size_t bit_count);
size_t bigint_popcount_unsigned(const BigInt *big_int); size_t bigint_popcount_unsigned(const BigInt *big_int);

File diff suppressed because it is too large Load Diff

View File

@@ -1,489 +1,489 @@
// apifn // apifn
static void core_free_compiler() { static void core_free_compiler() {
deallocate(pctx->heap, pctx->type_map.data); deallocate(pctx->heap, pctx->type_map.data);
deallocate(pctx->heap, pctx->interns.map.data); deallocate(pctx->heap, pctx->interns.map.data);
arena_release(pctx->stage_arena); arena_release(pctx->stage_arena);
arena_release(pctx->scratch); arena_release(pctx->scratch);
arena_release(pctx->perm); arena_release(pctx->perm);
} }
// apifn // apifn
static void core_init_compiler(Core_Ctx *ctx, Allocator *allocator) { static void core_init_compiler(Core_Ctx *ctx, Allocator *allocator) {
ctx->time.init_context = os_time(); ctx->time.init_context = os_time();
pctx = ctx; pctx = ctx;
ctx->emit_type_info = true; ctx->emit_type_info = true;
ctx->emit_line_directives = true; ctx->emit_line_directives = true;
ctx->debugger_break_on_compiler_error = true; ctx->debugger_break_on_compiler_error = true;
ctx->same_scope_token = {SAME_SCOPE}; ctx->same_scope_token = {SAME_SCOPE};
arena_init(&ctx->perm_push_only, "Perm Push Only"_s); arena_init(&ctx->perm_push_only, "Perm Push Only"_s);
arena_init(&ctx->scratch_, "Scratch"_s); arena_init(&ctx->scratch_, "Scratch"_s);
arena_init(&ctx->stage_arena_, "Stage Arena"_s); arena_init(&ctx->stage_arena_, "Stage Arena"_s);
arena_init(&ctx->token_arena, "Token Arena"_s); arena_init(&ctx->token_arena, "Token Arena"_s);
ctx->scratch = &ctx->scratch_; ctx->scratch = &ctx->scratch_;
ctx->stage_arena = &ctx->stage_arena_; ctx->stage_arena = &ctx->stage_arena_;
ctx->perm = &ctx->perm_push_only; ctx->perm = &ctx->perm_push_only;
ctx->heap = allocator; ctx->heap = allocator;
ctx->type_map = map_make(ctx->heap, 2048); ctx->type_map = map_make(ctx->heap, 2048);
ctx->gen = {ctx->perm}; ctx->gen = {ctx->perm};
ctx->helper_builder = {ctx->perm}; ctx->helper_builder = {ctx->perm};
ctx->scope_ids = 1; ctx->scope_ids = 1;
bigint_allocator = ctx->perm; bigint_allocator = ctx->perm;
ctx->interns = intern_table_make(ctx->perm, ctx->heap, 2048); ctx->interns = intern_table_make(ctx->perm, ctx->heap, 2048);
/*#import meta /*#import meta
for i in meta.keywords: for i in meta.keywords:
print(f'pctx->keyword_{i.lower()} = pctx->intern("{i}"_s);') print(f'pctx->keyword_{i.lower()} = pctx->intern("{i}"_s);')
print(f'pctx->interns.first_keyword = pctx->keyword_{meta.keywords[0].lower()}.str;') print(f'pctx->interns.first_keyword = pctx->keyword_{meta.keywords[0].lower()}.str;')
print(f'pctx->interns.last_keyword = pctx->keyword_{meta.keywords[-1].lower()}.str;') print(f'pctx->interns.last_keyword = pctx->keyword_{meta.keywords[-1].lower()}.str;')
for i in meta.interns: for i in meta.interns:
print(f'pctx->intern_{i.lower()} = pctx->intern("{i}"_s);') print(f'pctx->intern_{i.lower()} = pctx->intern("{i}"_s);')
index = 0 index = 0
for i in meta.token_simple_expr: for i in meta.token_simple_expr:
if i[1] != "SPECIAL": if i[1] != "SPECIAL":
print(f'pctx->op_info_table[{index}] = {{pctx->intern("{i[1]}"_s), "{i[0].upper()}"_s, TK_{i[0]}, {int(i[2]&meta.BINARY_EXPR>0)}, {int(i[2]&meta.UNARY_EXPR>0)}}};') print(f'pctx->op_info_table[{index}] = {{pctx->intern("{i[1]}"_s), "{i[0].upper()}"_s, TK_{i[0]}, {int(i[2]&meta.BINARY_EXPR>0)}, {int(i[2]&meta.UNARY_EXPR>0)}}};')
index += 1 index += 1
*/ */
pctx->keyword_struct = pctx->intern("struct"_s); pctx->keyword_struct = pctx->intern("struct"_s);
pctx->keyword_union = pctx->intern("union"_s); pctx->keyword_union = pctx->intern("union"_s);
pctx->keyword_true = pctx->intern("true"_s); pctx->keyword_true = pctx->intern("true"_s);
pctx->keyword_default = pctx->intern("default"_s); pctx->keyword_default = pctx->intern("default"_s);
pctx->keyword_continue = pctx->intern("continue"_s); pctx->keyword_continue = pctx->intern("continue"_s);
pctx->keyword_break = pctx->intern("break"_s); pctx->keyword_break = pctx->intern("break"_s);
pctx->keyword_false = pctx->intern("false"_s); pctx->keyword_false = pctx->intern("false"_s);
pctx->keyword_return = pctx->intern("return"_s); pctx->keyword_return = pctx->intern("return"_s);
pctx->keyword_switch = pctx->intern("switch"_s); pctx->keyword_switch = pctx->intern("switch"_s);
pctx->keyword_assert = pctx->intern("Assert"_s); pctx->keyword_assert = pctx->intern("Assert"_s);
pctx->keyword_if = pctx->intern("if"_s); pctx->keyword_if = pctx->intern("if"_s);
pctx->keyword_elif = pctx->intern("elif"_s); pctx->keyword_elif = pctx->intern("elif"_s);
pctx->keyword_pass = pctx->intern("pass"_s); pctx->keyword_pass = pctx->intern("pass"_s);
pctx->keyword_else = pctx->intern("else"_s); pctx->keyword_else = pctx->intern("else"_s);
pctx->keyword_for = pctx->intern("for"_s); pctx->keyword_for = pctx->intern("for"_s);
pctx->keyword_enum = pctx->intern("enum"_s); pctx->keyword_enum = pctx->intern("enum"_s);
pctx->keyword_goto = pctx->intern("goto"_s); pctx->keyword_goto = pctx->intern("goto"_s);
pctx->keyword_defer = pctx->intern("defer"_s); pctx->keyword_defer = pctx->intern("defer"_s);
pctx->interns.first_keyword = pctx->keyword_struct.str; pctx->interns.first_keyword = pctx->keyword_struct.str;
pctx->interns.last_keyword = pctx->keyword_defer.str; pctx->interns.last_keyword = pctx->keyword_defer.str;
pctx->intern_typeof = pctx->intern("typeof"_s); pctx->intern_typeof = pctx->intern("typeof"_s);
pctx->intern_sizeof = pctx->intern("sizeof"_s); pctx->intern_sizeof = pctx->intern("sizeof"_s);
pctx->intern_len = pctx->intern("Len"_s); pctx->intern_len = pctx->intern("Len"_s);
pctx->intern_alignof = pctx->intern("alignof"_s); pctx->intern_alignof = pctx->intern("alignof"_s);
pctx->intern_foreign = pctx->intern("foreign"_s); pctx->intern_foreign = pctx->intern("foreign"_s);
pctx->intern_strict = pctx->intern("strict"_s); pctx->intern_strict = pctx->intern("strict"_s);
pctx->intern_void = pctx->intern("void"_s); pctx->intern_void = pctx->intern("void"_s);
pctx->intern_flag = pctx->intern("flag"_s); pctx->intern_flag = pctx->intern("flag"_s);
pctx->intern_it = pctx->intern("it"_s); pctx->intern_it = pctx->intern("it"_s);
pctx->intern_load = pctx->intern("load"_s); pctx->intern_load = pctx->intern("load"_s);
pctx->intern_import = pctx->intern("import"_s); pctx->intern_import = pctx->intern("import"_s);
pctx->intern_link = pctx->intern("link"_s); pctx->intern_link = pctx->intern("link"_s);
pctx->intern_compiler_breakpoint = pctx->intern("compiler_breakpoint"_s); pctx->intern_compiler_breakpoint = pctx->intern("compiler_breakpoint"_s);
pctx->op_info_table[0] = {pctx->intern("*"_s), "MUL"_s, TK_Mul, 1, 0}; pctx->op_info_table[0] = {pctx->intern("*"_s), "MUL"_s, TK_Mul, 1, 0};
pctx->op_info_table[1] = {pctx->intern("/"_s), "DIV"_s, TK_Div, 1, 0}; pctx->op_info_table[1] = {pctx->intern("/"_s), "DIV"_s, TK_Div, 1, 0};
pctx->op_info_table[2] = {pctx->intern("%"_s), "MOD"_s, TK_Mod, 1, 0}; pctx->op_info_table[2] = {pctx->intern("%"_s), "MOD"_s, TK_Mod, 1, 0};
pctx->op_info_table[3] = {pctx->intern("<<"_s), "LEFTSHIFT"_s, TK_LeftShift, 1, 0}; pctx->op_info_table[3] = {pctx->intern("<<"_s), "LEFTSHIFT"_s, TK_LeftShift, 1, 0};
pctx->op_info_table[4] = {pctx->intern(">>"_s), "RIGHTSHIFT"_s, TK_RightShift, 1, 0}; pctx->op_info_table[4] = {pctx->intern(">>"_s), "RIGHTSHIFT"_s, TK_RightShift, 1, 0};
pctx->op_info_table[5] = {pctx->intern("+"_s), "ADD"_s, TK_Add, 1, 1}; pctx->op_info_table[5] = {pctx->intern("+"_s), "ADD"_s, TK_Add, 1, 1};
pctx->op_info_table[6] = {pctx->intern("-"_s), "SUB"_s, TK_Sub, 1, 1}; pctx->op_info_table[6] = {pctx->intern("-"_s), "SUB"_s, TK_Sub, 1, 1};
pctx->op_info_table[7] = {pctx->intern("=="_s), "EQUALS"_s, TK_Equals, 1, 0}; pctx->op_info_table[7] = {pctx->intern("=="_s), "EQUALS"_s, TK_Equals, 1, 0};
pctx->op_info_table[8] = {pctx->intern("<="_s), "LESSERTHENOREQUAL"_s, TK_LesserThenOrEqual, 1, 0}; pctx->op_info_table[8] = {pctx->intern("<="_s), "LESSERTHENOREQUAL"_s, TK_LesserThenOrEqual, 1, 0};
pctx->op_info_table[9] = {pctx->intern(">="_s), "GREATERTHENOREQUAL"_s, TK_GreaterThenOrEqual, 1, 0}; pctx->op_info_table[9] = {pctx->intern(">="_s), "GREATERTHENOREQUAL"_s, TK_GreaterThenOrEqual, 1, 0};
pctx->op_info_table[10] = {pctx->intern("<"_s), "LESSERTHEN"_s, TK_LesserThen, 1, 0}; pctx->op_info_table[10] = {pctx->intern("<"_s), "LESSERTHEN"_s, TK_LesserThen, 1, 0};
pctx->op_info_table[11] = {pctx->intern(">"_s), "GREATERTHEN"_s, TK_GreaterThen, 1, 0}; pctx->op_info_table[11] = {pctx->intern(">"_s), "GREATERTHEN"_s, TK_GreaterThen, 1, 0};
pctx->op_info_table[12] = {pctx->intern("!="_s), "NOTEQUALS"_s, TK_NotEquals, 1, 0}; pctx->op_info_table[12] = {pctx->intern("!="_s), "NOTEQUALS"_s, TK_NotEquals, 1, 0};
pctx->op_info_table[13] = {pctx->intern("&"_s), "BITAND"_s, TK_BitAnd, 1, 0}; pctx->op_info_table[13] = {pctx->intern("&"_s), "BITAND"_s, TK_BitAnd, 1, 0};
pctx->op_info_table[14] = {pctx->intern("|"_s), "BITOR"_s, TK_BitOr, 1, 0}; pctx->op_info_table[14] = {pctx->intern("|"_s), "BITOR"_s, TK_BitOr, 1, 0};
pctx->op_info_table[15] = {pctx->intern("^"_s), "BITXOR"_s, TK_BitXor, 1, 0}; pctx->op_info_table[15] = {pctx->intern("^"_s), "BITXOR"_s, TK_BitXor, 1, 0};
pctx->op_info_table[16] = {pctx->intern("&&"_s), "AND"_s, TK_And, 1, 0}; pctx->op_info_table[16] = {pctx->intern("&&"_s), "AND"_s, TK_And, 1, 0};
pctx->op_info_table[17] = {pctx->intern("||"_s), "OR"_s, TK_Or, 1, 0}; pctx->op_info_table[17] = {pctx->intern("||"_s), "OR"_s, TK_Or, 1, 0};
pctx->op_info_table[18] = {pctx->intern("~"_s), "NEG"_s, TK_Neg, 0, 1}; pctx->op_info_table[18] = {pctx->intern("~"_s), "NEG"_s, TK_Neg, 0, 1};
pctx->op_info_table[19] = {pctx->intern("!"_s), "NOT"_s, TK_Not, 0, 1}; pctx->op_info_table[19] = {pctx->intern("!"_s), "NOT"_s, TK_Not, 0, 1};
/*END*/ /*END*/
// Init types // Init types
pctx->type__void = {TYPE_VOID}; pctx->type__void = {TYPE_VOID};
pctx->type__bool = {TYPE_BOOL, sizeof(bool), __alignof(bool)}; pctx->type__bool = {TYPE_BOOL, sizeof(bool), __alignof(bool)};
pctx->type__type = {TYPE_TYPE, sizeof(S64), __alignof(S64)}; pctx->type__type = {TYPE_TYPE, sizeof(S64), __alignof(S64)};
pctx->type__f32 = {TYPE_F32, sizeof(F32), __alignof(F32)}; pctx->type__f32 = {TYPE_F32, sizeof(F32), __alignof(F32)};
pctx->type__f64 = {TYPE_F64, sizeof(F64), __alignof(F64)}; pctx->type__f64 = {TYPE_F64, sizeof(F64), __alignof(F64)};
pctx->type__s8 = {TYPE_S8, sizeof(S8), __alignof(S8)}; pctx->type__s8 = {TYPE_S8, sizeof(S8), __alignof(S8)};
pctx->type__s16 = {TYPE_S16, sizeof(S16), __alignof(S16)}; pctx->type__s16 = {TYPE_S16, sizeof(S16), __alignof(S16)};
pctx->type__s32 = {TYPE_S32, sizeof(S32), __alignof(S32)}; pctx->type__s32 = {TYPE_S32, sizeof(S32), __alignof(S32)};
pctx->type__s64 = {TYPE_S64, sizeof(S64), __alignof(S64)}; pctx->type__s64 = {TYPE_S64, sizeof(S64), __alignof(S64)};
pctx->type__u8 = {TYPE_U8, sizeof(U8), __alignof(U8), true}; pctx->type__u8 = {TYPE_U8, sizeof(U8), __alignof(U8), true};
pctx->type__u16 = {TYPE_U16, sizeof(U16), __alignof(U16), true}; pctx->type__u16 = {TYPE_U16, sizeof(U16), __alignof(U16), true};
pctx->type__u32 = {TYPE_U32, sizeof(U32), __alignof(U32), true}; pctx->type__u32 = {TYPE_U32, sizeof(U32), __alignof(U32), true};
pctx->type__u64 = {TYPE_U64, sizeof(U64), __alignof(U64), true}; pctx->type__u64 = {TYPE_U64, sizeof(U64), __alignof(U64), true};
pctx->type__untyped_bool = {TYPE_UNTYPED_BOOL, sizeof(bool), __alignof(bool)}; pctx->type__untyped_bool = {TYPE_UNTYPED_BOOL, sizeof(bool), __alignof(bool)};
pctx->type__untyped_int = {TYPE_UNTYPED_INT, sizeof(S64), __alignof(S64)}; pctx->type__untyped_int = {TYPE_UNTYPED_INT, sizeof(S64), __alignof(S64)};
pctx->type__untyped_string = {TYPE_UNTYPED_STRING, sizeof(String), __alignof(String)}; pctx->type__untyped_string = {TYPE_UNTYPED_STRING, sizeof(String), __alignof(String)};
pctx->type__untyped_float = {TYPE_UNTYPED_FLOAT, sizeof(double), __alignof(double)}; pctx->type__untyped_float = {TYPE_UNTYPED_FLOAT, sizeof(double), __alignof(double)};
pctx->type__char = {TYPE_CHAR, sizeof(char), __alignof(char)}; pctx->type__char = {TYPE_CHAR, sizeof(char), __alignof(char)};
pctx->type__uchar = {TYPE_UCHAR, sizeof(unsigned char), __alignof(unsigned char), true}; pctx->type__uchar = {TYPE_UCHAR, sizeof(unsigned char), __alignof(unsigned char), true};
pctx->type__int = {TYPE_INT, sizeof(int), __alignof(int)}; pctx->type__int = {TYPE_INT, sizeof(int), __alignof(int)};
pctx->type__uint = {TYPE_UINT, sizeof(unsigned), __alignof(unsigned), true}; pctx->type__uint = {TYPE_UINT, sizeof(unsigned), __alignof(unsigned), true};
pctx->type__long = {TYPE_LONG, sizeof(long), __alignof(long)}; pctx->type__long = {TYPE_LONG, sizeof(long), __alignof(long)};
pctx->type__ulong = {TYPE_ULONG, sizeof(unsigned long), __alignof(unsigned long), true}; pctx->type__ulong = {TYPE_ULONG, sizeof(unsigned long), __alignof(unsigned long), true};
pctx->type__llong = {TYPE_LLONG, sizeof(long long), __alignof(long long)}; pctx->type__llong = {TYPE_LLONG, sizeof(long long), __alignof(long long)};
pctx->type__ullong = {TYPE_ULLONG, sizeof(unsigned long long), __alignof(unsigned long long), true}; pctx->type__ullong = {TYPE_ULLONG, sizeof(unsigned long long), __alignof(unsigned long long), true};
pctx->type__short = {TYPE_SHORT, sizeof(short), __alignof(short)}; pctx->type__short = {TYPE_SHORT, sizeof(short), __alignof(short)};
pctx->type__ushort = {TYPE_USHORT, sizeof(unsigned short), __alignof(unsigned short), true}; pctx->type__ushort = {TYPE_USHORT, sizeof(unsigned short), __alignof(unsigned short), true};
pctx->type_char = &pctx->type__char; pctx->type_char = &pctx->type__char;
pctx->type_uchar = &pctx->type__uchar; pctx->type_uchar = &pctx->type__uchar;
pctx->type_int = &pctx->type__int; pctx->type_int = &pctx->type__int;
pctx->type_uint = &pctx->type__uint; pctx->type_uint = &pctx->type__uint;
pctx->type_long = &pctx->type__long; pctx->type_long = &pctx->type__long;
pctx->type_ulong = &pctx->type__ulong; pctx->type_ulong = &pctx->type__ulong;
pctx->type_llong = &pctx->type__llong; pctx->type_llong = &pctx->type__llong;
pctx->type_ullong = &pctx->type__ullong; pctx->type_ullong = &pctx->type__ullong;
pctx->type_short = &pctx->type__short; pctx->type_short = &pctx->type__short;
pctx->type_ushort = &pctx->type__ushort; pctx->type_ushort = &pctx->type__ushort;
pctx->type_void = &pctx->type__void; pctx->type_void = &pctx->type__void;
// pctx->type__string = {TYPE_STRING, sizeof(String), __alignof(String)}; // pctx->type__string = {TYPE_STRING, sizeof(String), __alignof(String)};
// pctx->type_any; // Needs to be inited at runtime // pctx->type_any; // Needs to be inited at runtime
// pctx->type_string = &pctx->type__string; // pctx->type_string = &pctx->type__string;
pctx->type_type = &pctx->type__type; pctx->type_type = &pctx->type__type;
pctx->type_bool = &pctx->type__bool; pctx->type_bool = &pctx->type__bool;
pctx->type_f32 = &pctx->type__f32; pctx->type_f32 = &pctx->type__f32;
pctx->type_f64 = &pctx->type__f64; pctx->type_f64 = &pctx->type__f64;
pctx->type_s8 = &pctx->type__s8; pctx->type_s8 = &pctx->type__s8;
pctx->type_s16 = &pctx->type__s16; pctx->type_s16 = &pctx->type__s16;
pctx->type_s32 = &pctx->type__s32; pctx->type_s32 = &pctx->type__s32;
pctx->type_s64 = &pctx->type__s64; pctx->type_s64 = &pctx->type__s64;
pctx->type_u8 = &pctx->type__u8; pctx->type_u8 = &pctx->type__u8;
pctx->type_u16 = &pctx->type__u16; pctx->type_u16 = &pctx->type__u16;
pctx->type_u32 = &pctx->type__u32; pctx->type_u32 = &pctx->type__u32;
pctx->type_u64 = &pctx->type__u64; pctx->type_u64 = &pctx->type__u64;
pctx->untyped_string = &pctx->type__untyped_string; pctx->untyped_string = &pctx->type__untyped_string;
pctx->untyped_bool = &pctx->type__untyped_bool; pctx->untyped_bool = &pctx->type__untyped_bool;
pctx->untyped_int = &pctx->type__untyped_int; pctx->untyped_int = &pctx->type__untyped_int;
pctx->untyped_float = &pctx->type__untyped_float; pctx->untyped_float = &pctx->type__untyped_float;
pctx->type__vargs = {TYPE_VARGS}; pctx->type__vargs = {TYPE_VARGS};
pctx->type_vargs = &pctx->type__vargs; pctx->type_vargs = &pctx->type__vargs;
pctx->type_pointer_to_char = type_pointer(pctx->type_char); pctx->type_pointer_to_char = type_pointer(pctx->type_char);
pctx->type_pointer_to_void = type_pointer(pctx->type_void); pctx->type_pointer_to_void = type_pointer(pctx->type_void);
// Init paths // Init paths
ctx->exe_folder = os_get_exe_dir(ctx->perm); ctx->exe_folder = os_get_exe_dir(ctx->perm);
ctx->working_folder = os_get_working_dir(ctx->perm); ctx->working_folder = os_get_working_dir(ctx->perm);
String main_module = string_fmt(ctx->perm, "%Q/modules", ctx->exe_folder); String main_module = string_fmt(ctx->perm, "%Q/modules", ctx->exe_folder);
add(ctx->perm, &ctx->module_folders, main_module); add(ctx->perm, &ctx->module_folders, main_module);
ctx->time.init_context = os_time() - ctx->time.init_context; ctx->time.init_context = os_time() - ctx->time.init_context;
} }
// apifn // apifn
CORE_Static void CORE_Static void
core_bootstrap_compiler(Allocator *allocator) { core_bootstrap_compiler(Allocator *allocator) {
Core_Ctx *ctx = allocate_struct(allocator, Core_Ctx); Core_Ctx *ctx = allocate_struct(allocator, Core_Ctx);
core_init_compiler(ctx, allocator); core_init_compiler(ctx, allocator);
} }
CORE_Static void CORE_Static void
insert_builtin_type_into_scope(Ast_Scope *p, String name, Ast_Type *type) { insert_builtin_type_into_scope(Ast_Scope *p, String name, Ast_Type *type) {
Intern_String string = pctx->intern(name); Intern_String string = pctx->intern(name);
Ast_Decl *decl = ast_type(0, string, type); Ast_Decl *decl = ast_type(0, string, type);
type->type_id = pctx->type_ids++; type->type_id = pctx->type_ids++;
decl->parent_scope = p; decl->parent_scope = p;
decl->state = DECL_RESOLVED; decl->state = DECL_RESOLVED;
insert_into_scope(p, decl); insert_into_scope(p, decl);
add(pctx->perm, &pctx->all_types, type); add(pctx->perm, &pctx->all_types, type);
} }
CORE_Static void CORE_Static void
parse_all_modules() { parse_all_modules() {
pctx->time.parsing = os_time(); pctx->time.parsing = os_time();
For2(pctx->modules, module) { For2(pctx->modules, module) {
if (module->state != MODULE_REGISTERED) if (module->state != MODULE_REGISTERED)
continue; continue;
For(module->all_loaded_files) { For(module->all_loaded_files) {
parse_file(it); parse_file(it);
} }
if (module != pctx->language_base_module) { if (module != pctx->language_base_module) {
add(pctx->perm, &module->implicit_imports, (Ast_Scope *)pctx->language_base_module); add(pctx->perm, &module->implicit_imports, (Ast_Scope *)pctx->language_base_module);
} }
module->state = MODULE_PARSED; module->state = MODULE_PARSED;
} }
pctx->time.parsing = os_time() - pctx->time.parsing; pctx->time.parsing = os_time() - pctx->time.parsing;
} }
CORE_Static Ast_Module * CORE_Static Ast_Module *
add_module(Token *pos, Intern_String filename, B32 command_line_module, bool string_only_module) { add_module(Token *pos, Intern_String filename, B32 command_line_module, bool string_only_module) {
Arena *scratch = pctx->scratch; Arena *scratch = pctx->scratch;
Scoped_Arena _scope(scratch); Scoped_Arena _scope(scratch);
String absolute_file_path = {}; String absolute_file_path = {};
String absolute_base_folder = {}; String absolute_base_folder = {};
if (string_only_module) { if (string_only_module) {
absolute_file_path = filename.s; absolute_file_path = filename.s;
absolute_base_folder = filename.s; absolute_base_folder = filename.s;
} }
else { else {
// //
// Find in working directory // Find in working directory
// //
if (command_line_module) { if (command_line_module) {
if (os_does_file_exist(filename.s)) { if (os_does_file_exist(filename.s)) {
String path = os_get_absolute_path(scratch, filename.s); String path = os_get_absolute_path(scratch, filename.s);
string_path_normalize(path); string_path_normalize(path);
absolute_file_path = string_copy(scratch, path); absolute_file_path = string_copy(scratch, path);
absolute_base_folder = string_chop_last_slash(path); absolute_base_folder = string_chop_last_slash(path);
} }
} }
// //
// Find in module folder // Find in module folder
// //
else { else {
For(pctx->module_folders) { For(pctx->module_folders) {
String path = string_fmt(scratch, "%Q/%Q", it, filename); String path = string_fmt(scratch, "%Q/%Q", it, filename);
if (os_does_file_exist(path)) { if (os_does_file_exist(path)) {
absolute_file_path = path; absolute_file_path = path;
absolute_base_folder = string_chop_last_slash(path); absolute_base_folder = string_chop_last_slash(path);
break; break;
} }
} }
} }
if (absolute_file_path.len == 0) { if (absolute_file_path.len == 0) {
compiler_error(pos, "Couldn't find the module with name %Q", filename); compiler_error(pos, "Couldn't find the module with name %Q", filename);
} }
} }
For(pctx->modules) { For(pctx->modules) {
if (string_compare(it->absolute_file_path, absolute_file_path)) { if (string_compare(it->absolute_file_path, absolute_file_path)) {
log_trace("Returning registered module: %Q\n", absolute_file_path); log_trace("Returning registered module: %Q\n", absolute_file_path);
return it; return it;
} }
} }
log_trace("Adding module: %Q\n", filename); log_trace("Adding module: %Q\n", filename);
Ast_Module *result = ast_new(Ast_Module, AST_MODULE, pos, 0); Ast_Module *result = ast_new(Ast_Module, AST_MODULE, pos, 0);
result->absolute_file_path = string_copy(pctx->perm, absolute_file_path); result->absolute_file_path = string_copy(pctx->perm, absolute_file_path);
result->absolute_base_folder = string_copy(pctx->perm, absolute_base_folder); result->absolute_base_folder = string_copy(pctx->perm, absolute_base_folder);
result->debug_name = string_skip_to_last_slash(result->absolute_file_path); result->debug_name = string_skip_to_last_slash(result->absolute_file_path);
result->module = result; // @warning: self referential result->module = result; // @warning: self referential
result->file = result; // @warning: self referential result->file = result; // @warning: self referential
result->parent_scope = 0; result->parent_scope = 0;
result->scope_id = pctx->scope_ids++; result->scope_id = pctx->scope_ids++;
register_ast_file(pos, result->absolute_file_path, result, GLOBAL_IMPLICIT_LOAD); register_ast_file(pos, result->absolute_file_path, result, GLOBAL_IMPLICIT_LOAD);
add(pctx->perm, &pctx->modules, result); add(pctx->perm, &pctx->modules, result);
return result; return result;
} }
CORE_Static Ast_File * CORE_Static Ast_File *
custom_parse_string(String string) { custom_parse_string(String string) {
Ast_Module *module = pctx->custom_module; Ast_Module *module = pctx->custom_module;
Ast_File *file = get(&module->all_loaded_files, 0); Ast_File *file = get(&module->all_loaded_files, 0);
file->filecontent = string; file->filecontent = string;
parse_file(file); parse_file(file);
return file; return file;
} }
CORE_Static void CORE_Static void
resolve_everything_in_module(Ast_Module *module) { resolve_everything_in_module(Ast_Module *module) {
if (module->state == MODULE_RESOLVED) if (module->state == MODULE_RESOLVED)
return; return;
pctx->time.typechecking = os_time(); pctx->time.typechecking = os_time();
For2(module->all_loaded_files, file) { For2(module->all_loaded_files, file) {
For2(file->decls, decl) { For2(file->decls, decl) {
if (decl->flags & AST_POLYMORPH) continue; if (decl->flags & AST_POLYMORPH) continue;
resolve_decl(decl); resolve_decl(decl);
if (decl->kind == AST_STRUCT || decl->kind == AST_UNION) type_complete(decl->type_val); if (decl->kind == AST_STRUCT || decl->kind == AST_UNION) type_complete(decl->type_val);
} }
} }
module->state = MODULE_RESOLVED; module->state = MODULE_RESOLVED;
pctx->time.typechecking = os_time() - pctx->time.typechecking; pctx->time.typechecking = os_time() - pctx->time.typechecking;
} }
CORE_Static void CORE_Static void
init_language_core() { init_language_core() {
pctx->custom_module = add_module(0, pctx->intern("Custom.core"_s), false, true); pctx->custom_module = add_module(0, pctx->intern("Custom.core"_s), false, true);
pctx->custom_module->state = MODULE_RESOLVED; pctx->custom_module->state = MODULE_RESOLVED;
Ast_Module *module = add_module(0, pctx->intern("Language.core"_s), false, true); Ast_Module *module = add_module(0, pctx->intern("Language.core"_s), false, true);
get(&module->all_loaded_files, 0)->filecontent = get(&module->all_loaded_files, 0)->filecontent =
R"( R"(
Any :: struct Any :: struct
data: *void data: *void
type: Type type: Type
String :: struct String :: struct
data: *U8 data: *U8
len: int len: int
Two :: struct($A: Type, $B: Type) Two :: struct($A: Type, $B: Type)
a: A a: A
b: B b: B
Type_Info_Kind :: enum Type_Info_Kind :: enum
S64 // FIRST_NUMERIC S64 // FIRST_NUMERIC
S32 S32
S16 S16
S8 S8
INT INT
CHAR CHAR
U64 U64
U32 U32
U16 U16
U8 U8
F32 F32
F64 F64
POINTER POINTER
BOOL // LAST_NUMERIC BOOL // LAST_NUMERIC
STRING STRING
VOID VOID
ARRAY ARRAY
LAMBDA LAMBDA
STRUCT STRUCT
UNION UNION
ENUM ENUM
TYPE TYPE
SLICE SLICE
TUPLE TUPLE
Type_Info_Struct_Member :: struct Type_Info_Struct_Member :: struct
name: String name: String
type: Type type: Type
offset: int offset: int
Type_Info :: struct Type_Info :: struct
kind: Type_Info_Kind kind: Type_Info_Kind
size: int size: int
align: int align: int
is_unsigned: bool is_unsigned: bool
type: Type type: Type
base_type: Type base_type: Type
array_size: int array_size: int
struct_members: []Type_Info_Struct_Member struct_members: []Type_Info_Struct_Member
lambda_arguments: []Type_Info lambda_arguments: []Type_Info
lambda_return: Type lambda_return: Type
type_infos_len: int #foreign type_infos_len: int #foreign
type_infos : *Type_Info #foreign type_infos : *Type_Info #foreign
GetTypeInfo :: (type: Type): *Type_Info GetTypeInfo :: (type: Type): *Type_Info
id := type->int id := type->int
if id >= type_infos_len if id >= type_infos_len
return 0 return 0
return type_infos + id return type_infos + id
)"_s; )"_s;
{ {
insert_builtin_type_into_scope(module, "char"_s, pctx->type_char); insert_builtin_type_into_scope(module, "char"_s, pctx->type_char);
insert_builtin_type_into_scope(module, "uchar"_s, pctx->type_uchar); insert_builtin_type_into_scope(module, "uchar"_s, pctx->type_uchar);
insert_builtin_type_into_scope(module, "int"_s, pctx->type_int); insert_builtin_type_into_scope(module, "int"_s, pctx->type_int);
insert_builtin_type_into_scope(module, "uint"_s, pctx->type_uint); insert_builtin_type_into_scope(module, "uint"_s, pctx->type_uint);
insert_builtin_type_into_scope(module, "long"_s, pctx->type_long); insert_builtin_type_into_scope(module, "long"_s, pctx->type_long);
insert_builtin_type_into_scope(module, "ulong"_s, pctx->type_ulong); insert_builtin_type_into_scope(module, "ulong"_s, pctx->type_ulong);
insert_builtin_type_into_scope(module, "llong"_s, pctx->type_llong); insert_builtin_type_into_scope(module, "llong"_s, pctx->type_llong);
insert_builtin_type_into_scope(module, "ullong"_s, pctx->type_ullong); insert_builtin_type_into_scope(module, "ullong"_s, pctx->type_ullong);
insert_builtin_type_into_scope(module, "short"_s, pctx->type_short); insert_builtin_type_into_scope(module, "short"_s, pctx->type_short);
insert_builtin_type_into_scope(module, "ushort"_s, pctx->type_ushort); insert_builtin_type_into_scope(module, "ushort"_s, pctx->type_ushort);
insert_builtin_type_into_scope(module, "S64"_s, pctx->type_s64); insert_builtin_type_into_scope(module, "S64"_s, pctx->type_s64);
insert_builtin_type_into_scope(module, "S32"_s, pctx->type_s32); insert_builtin_type_into_scope(module, "S32"_s, pctx->type_s32);
insert_builtin_type_into_scope(module, "S16"_s, pctx->type_s16); insert_builtin_type_into_scope(module, "S16"_s, pctx->type_s16);
insert_builtin_type_into_scope(module, "S8"_s, pctx->type_s8); insert_builtin_type_into_scope(module, "S8"_s, pctx->type_s8);
insert_builtin_type_into_scope(module, "U64"_s, pctx->type_u64); insert_builtin_type_into_scope(module, "U64"_s, pctx->type_u64);
insert_builtin_type_into_scope(module, "U32"_s, pctx->type_u32); insert_builtin_type_into_scope(module, "U32"_s, pctx->type_u32);
insert_builtin_type_into_scope(module, "U16"_s, pctx->type_u16); insert_builtin_type_into_scope(module, "U16"_s, pctx->type_u16);
insert_builtin_type_into_scope(module, "U8"_s, pctx->type_u8); insert_builtin_type_into_scope(module, "U8"_s, pctx->type_u8);
insert_builtin_type_into_scope(module, "F64"_s, pctx->type_f64); insert_builtin_type_into_scope(module, "F64"_s, pctx->type_f64);
insert_builtin_type_into_scope(module, "F32"_s, pctx->type_f32); insert_builtin_type_into_scope(module, "F32"_s, pctx->type_f32);
insert_builtin_type_into_scope(module, "void"_s, pctx->type_void); insert_builtin_type_into_scope(module, "void"_s, pctx->type_void);
insert_builtin_type_into_scope(module, "bool"_s, pctx->type_bool); insert_builtin_type_into_scope(module, "bool"_s, pctx->type_bool);
// insert_builtin_type_into_scope(module, "String"_s, pctx->type_string); // insert_builtin_type_into_scope(module, "String"_s, pctx->type_string);
insert_builtin_type_into_scope(module, "Type"_s, pctx->type_type); insert_builtin_type_into_scope(module, "Type"_s, pctx->type_type);
} }
{ {
Ast_File *file = get(&module->all_loaded_files, 0); Ast_File *file = get(&module->all_loaded_files, 0);
Ast_Scope *scope = ast_decl_scope(&pctx->null_token, pctx->perm, file); Ast_Scope *scope = ast_decl_scope(&pctx->null_token, pctx->perm, file);
scope->parent_scope = file; scope->parent_scope = file;
scope->module = module; scope->module = module;
Ast_Decl *decl = ast_namespace(&pctx->null_token, scope, pctx->intern("Const"_s)); Ast_Decl *decl = ast_namespace(&pctx->null_token, scope, pctx->intern("Const"_s));
decl->state = DECL_RESOLVED; decl->state = DECL_RESOLVED;
Value v1 = {}; Value v1 = {};
v1.type = pctx->untyped_string; v1.type = pctx->untyped_string;
v1.intern_val = pctx->intern(OS_NAME); v1.intern_val = pctx->intern(OS_NAME);
Ast_Decl *const_os1 = ast_const(&pctx->null_token, pctx->intern("OSName"_s), v1); Ast_Decl *const_os1 = ast_const(&pctx->null_token, pctx->intern("OSName"_s), v1);
const_os1->state = DECL_RESOLVED; const_os1->state = DECL_RESOLVED;
insert_into_scope(scope, const_os1); insert_into_scope(scope, const_os1);
Value v2 = {}; Value v2 = {};
v1.type = pctx->untyped_string; v1.type = pctx->untyped_string;
v1.intern_val = pctx->intern(OS_NAME_LOWER); v1.intern_val = pctx->intern(OS_NAME_LOWER);
Ast_Decl *const_os2 = ast_const(&pctx->null_token, pctx->intern("OSNameLower"_s), v2); Ast_Decl *const_os2 = ast_const(&pctx->null_token, pctx->intern("OSNameLower"_s), v2);
const_os2->state = DECL_RESOLVED; const_os2->state = DECL_RESOLVED;
insert_into_scope(scope, const_os2); insert_into_scope(scope, const_os2);
insert_into_scope(module, decl); insert_into_scope(module, decl);
} }
pctx->language_base_module = module; pctx->language_base_module = module;
parse_all_modules(); parse_all_modules();
resolve_everything_in_module(module); resolve_everything_in_module(module);
// @note: language stuff needs to be declared before type_info data // @note: language stuff needs to be declared before type_info data
// so we mark where it ends // so we mark where it ends
pctx->base_language_ordered_decl_len = length(&pctx->ordered_decls); pctx->base_language_ordered_decl_len = length(&pctx->ordered_decls);
Ast_Decl *any_decl = search_for_single_decl(module, pctx->intern("Any"_s)); Ast_Decl *any_decl = search_for_single_decl(module, pctx->intern("Any"_s));
assert(any_decl->type == pctx->type_type); assert(any_decl->type == pctx->type_type);
pctx->type_any = any_decl->type_val; pctx->type_any = any_decl->type_val;
Ast_Decl *string_decl = search_for_single_decl(module, pctx->intern("String"_s)); Ast_Decl *string_decl = search_for_single_decl(module, pctx->intern("String"_s));
assert(string_decl->type == pctx->type_type); assert(string_decl->type == pctx->type_type);
pctx->type_string = string_decl->type_val; pctx->type_string = string_decl->type_val;
} }
CORE_Static String CORE_Static String
compile_file_to_string(Allocator *allocator, String filename) { compile_file_to_string(Allocator *allocator, String filename) {
F64 total_time = os_time(); F64 total_time = os_time();
core_bootstrap_compiler(allocator); core_bootstrap_compiler(allocator);
pctx->time.total = total_time; pctx->time.total = total_time;
pctx->time.start = total_time; pctx->time.start = total_time;
init_language_core(); init_language_core();
Ast_Module *module = add_module(0, pctx->intern(filename), true); Ast_Module *module = add_module(0, pctx->intern(filename), true);
parse_all_modules(); parse_all_modules();
assert(module); assert(module);
resolve_everything_in_module(module); resolve_everything_in_module(module);
String result = compile_to_c_code(); String result = compile_to_c_code();
pctx->time.total = os_time() - pctx->time.total; pctx->time.total = os_time() - pctx->time.total;
return result; return result;
} }

View File

@@ -1,234 +1,234 @@
struct Lex_Stream { struct Lex_Stream {
String stream; String stream;
S64 iter; S64 iter;
U8 *line_begin; U8 *line_begin;
Intern_String file; Intern_String file;
S32 line; S32 line;
S32 inside_brace_paren; S32 inside_brace_paren;
Array<Token *> indent_stack; // @scratch_allocated Array<Token *> indent_stack; // @scratch_allocated
}; };
struct Core_Ctx { struct Core_Ctx {
Allocator *heap; Allocator *heap;
Arena perm_push_only; Arena perm_push_only;
Arena *perm; // Stores: AST, tokens, interns Arena *perm; // Stores: AST, tokens, interns
Arena *scratch; Arena *scratch;
Arena scratch_; Arena scratch_;
Arena stage_arena_; Arena stage_arena_;
Arena *stage_arena; Arena *stage_arena;
Arena token_arena; Arena token_arena;
String_Builder helper_builder; String_Builder helper_builder;
int errors_occured; int errors_occured;
int warnings_occured; int warnings_occured;
Core_Message *first_message; Core_Message *first_message;
Core_Message *last_message; Core_Message *last_message;
// Lexer stuff // Lexer stuff
Lex_Stream stream; Lex_Stream stream;
Array<Token> tokens; Array<Token> tokens;
Intern_Table interns; Intern_Table interns;
S64 token_iter; S64 token_iter;
U32 token_debug_ids; U32 token_debug_ids;
// Types // Types
List<Ast_Type *> all_types; List<Ast_Type *> all_types;
S32 type_ids; S32 type_ids;
int global_decl_ids; int global_decl_ids;
U64 unique_ids; // @Debug U64 unique_ids; // @Debug
Map type_map; Map type_map;
Ast_Module *custom_module; Ast_Module *custom_module;
Ast_Module *language_base_module; Ast_Module *language_base_module;
List<Ast_File *> files; List<Ast_File *> files;
List<Ast_Module *> modules; List<Ast_Module *> modules;
List<Ast_Decl *> ordered_decls; List<Ast_Decl *> ordered_decls;
S32 base_language_ordered_decl_len; S32 base_language_ordered_decl_len;
Ast_Scope *currently_parsed_scope; Ast_Scope *currently_parsed_scope;
Ast_File *currently_parsed_file; Ast_File *currently_parsed_file;
U32 scope_ids; U32 scope_ids;
U32 scope_visit_id; U32 scope_visit_id;
List<String> module_folders; List<String> module_folders;
String module_folder; String module_folder;
String exe_folder; String exe_folder;
String working_folder; String working_folder;
List<Token *> files_to_link; List<Token *> files_to_link;
struct { struct {
F64 typechecking; F64 typechecking;
F64 code_generation; F64 code_generation;
F64 total; F64 total;
F64 init_context; F64 init_context;
F64 parsing; F64 parsing;
F64 start; F64 start;
} time; } time;
int lines_lexed; int lines_lexed;
bool debugger_break_on_compiler_error; bool debugger_break_on_compiler_error;
// Codegen stage mostly // Codegen stage mostly
S64 indent; S64 indent;
String_Builder gen; String_Builder gen;
// Codegen stage configurables // Codegen stage configurables
bool emit_line_directives; bool emit_line_directives;
bool emit_type_info; bool emit_type_info;
bool single_header_library_mode; bool single_header_library_mode;
String single_header_library_name; String single_header_library_name;
Token same_scope_token; Token same_scope_token;
Token null_token; Token null_token;
/*#import meta /*#import meta
for i in meta.keywords: print(f'Intern_String keyword_{i.lower()};') for i in meta.keywords: print(f'Intern_String keyword_{i.lower()};')
for i in meta.interns: print(f'Intern_String intern_{i.lower()};') for i in meta.interns: print(f'Intern_String intern_{i.lower()};')
*/ */
Intern_String keyword_struct; Intern_String keyword_struct;
Intern_String keyword_union; Intern_String keyword_union;
Intern_String keyword_true; Intern_String keyword_true;
Intern_String keyword_default; Intern_String keyword_default;
Intern_String keyword_continue; Intern_String keyword_continue;
Intern_String keyword_break; Intern_String keyword_break;
Intern_String keyword_false; Intern_String keyword_false;
Intern_String keyword_return; Intern_String keyword_return;
Intern_String keyword_switch; Intern_String keyword_switch;
Intern_String keyword_assert; Intern_String keyword_assert;
Intern_String keyword_if; Intern_String keyword_if;
Intern_String keyword_elif; Intern_String keyword_elif;
Intern_String keyword_pass; Intern_String keyword_pass;
Intern_String keyword_else; Intern_String keyword_else;
Intern_String keyword_for; Intern_String keyword_for;
Intern_String keyword_enum; Intern_String keyword_enum;
Intern_String keyword_goto; Intern_String keyword_goto;
Intern_String keyword_defer; Intern_String keyword_defer;
Intern_String intern_typeof; Intern_String intern_typeof;
Intern_String intern_sizeof; Intern_String intern_sizeof;
Intern_String intern_len; Intern_String intern_len;
Intern_String intern_alignof; Intern_String intern_alignof;
Intern_String intern_foreign; Intern_String intern_foreign;
Intern_String intern_strict; Intern_String intern_strict;
Intern_String intern_void; Intern_String intern_void;
Intern_String intern_flag; Intern_String intern_flag;
Intern_String intern_it; Intern_String intern_it;
Intern_String intern_load; Intern_String intern_load;
Intern_String intern_import; Intern_String intern_import;
Intern_String intern_link; Intern_String intern_link;
Intern_String intern_compiler_breakpoint; Intern_String intern_compiler_breakpoint;
/*END*/ /*END*/
/*#import meta /*#import meta
size = 0 size = 0
for i in meta.token_simple_expr: for i in meta.token_simple_expr:
if i[1] != "SPECIAL": if i[1] != "SPECIAL":
size += 1 size += 1
print(f"Ast_Operator_Info op_info_table[{size}];") print(f"Ast_Operator_Info op_info_table[{size}];")
*/ */
Ast_Operator_Info op_info_table[20]; Ast_Operator_Info op_info_table[20];
/*END*/ /*END*/
Ast_Type type__void; Ast_Type type__void;
Ast_Type type__string; Ast_Type type__string;
Ast_Type type__bool; Ast_Type type__bool;
Ast_Type type__type; Ast_Type type__type;
Ast_Type type__f32; Ast_Type type__f32;
Ast_Type type__f64; Ast_Type type__f64;
Ast_Type type__s8; Ast_Type type__s8;
Ast_Type type__s16; Ast_Type type__s16;
Ast_Type type__s32; Ast_Type type__s32;
Ast_Type type__s64; Ast_Type type__s64;
Ast_Type type__u8; Ast_Type type__u8;
Ast_Type type__u16; Ast_Type type__u16;
Ast_Type type__u32; Ast_Type type__u32;
Ast_Type type__u64; Ast_Type type__u64;
Ast_Type type__untyped_bool; Ast_Type type__untyped_bool;
Ast_Type type__untyped_int; Ast_Type type__untyped_int;
Ast_Type type__untyped_string; Ast_Type type__untyped_string;
Ast_Type type__untyped_float; Ast_Type type__untyped_float;
Ast_Type type__char; Ast_Type type__char;
Ast_Type type__uchar; Ast_Type type__uchar;
Ast_Type type__int; Ast_Type type__int;
Ast_Type type__uint; Ast_Type type__uint;
Ast_Type type__long; Ast_Type type__long;
Ast_Type type__ulong; Ast_Type type__ulong;
Ast_Type type__llong; Ast_Type type__llong;
Ast_Type type__ullong; Ast_Type type__ullong;
Ast_Type type__short; Ast_Type type__short;
Ast_Type type__ushort; Ast_Type type__ushort;
Ast_Type *type_char; Ast_Type *type_char;
Ast_Type *type_uchar; Ast_Type *type_uchar;
Ast_Type *type_int; Ast_Type *type_int;
Ast_Type *type_uint; Ast_Type *type_uint;
Ast_Type *type_long; Ast_Type *type_long;
Ast_Type *type_ulong; Ast_Type *type_ulong;
Ast_Type *type_llong; Ast_Type *type_llong;
Ast_Type *type_ullong; Ast_Type *type_ullong;
Ast_Type *type_short; Ast_Type *type_short;
Ast_Type *type_ushort; Ast_Type *type_ushort;
Ast_Type *type_void; Ast_Type *type_void;
Ast_Type *type_pointer_to_char; Ast_Type *type_pointer_to_char;
Ast_Type *type_pointer_to_void; Ast_Type *type_pointer_to_void;
Ast_Type *type_any; // Needs to be inited at runtime Ast_Type *type_any; // Needs to be inited at runtime
Ast_Type *type_type; Ast_Type *type_type;
Ast_Type *type_string; Ast_Type *type_string;
Ast_Type *type_bool; Ast_Type *type_bool;
Ast_Type *type_f32; Ast_Type *type_f32;
Ast_Type *type_f64; Ast_Type *type_f64;
Ast_Type *type_s8; Ast_Type *type_s8;
Ast_Type *type_s16; Ast_Type *type_s16;
Ast_Type *type_s32; Ast_Type *type_s32;
Ast_Type *type_s64; Ast_Type *type_s64;
Ast_Type *type_u8; Ast_Type *type_u8;
Ast_Type *type_u16; Ast_Type *type_u16;
Ast_Type *type_u32; Ast_Type *type_u32;
Ast_Type *type_u64; Ast_Type *type_u64;
Ast_Type *untyped_string; Ast_Type *untyped_string;
Ast_Type *untyped_bool; Ast_Type *untyped_bool;
Ast_Type *untyped_int; Ast_Type *untyped_int;
Ast_Type *untyped_float; Ast_Type *untyped_float;
Ast_Type type__vargs; Ast_Type type__vargs;
Ast_Type *type_vargs; Ast_Type *type_vargs;
Intern_String intern(String string) { Intern_String intern(String string) {
assert(string.len > 0); assert(string.len > 0);
return intern_string(&interns, string); return intern_string(&interns, string);
} }
Intern_String internf(char *str, ...) { Intern_String internf(char *str, ...) {
STRING_FMT(this->stage_arena, str, result); STRING_FMT(this->stage_arena, str, result);
return intern_string(&interns, result); return intern_string(&interns, result);
} }
String fmt(char *str, ...) { String fmt(char *str, ...) {
STRING_FMT(this->stage_arena, str, result); STRING_FMT(this->stage_arena, str, result);
return result; return result;
} }
}; };
CORE_Static String compile_to_c_code(); CORE_Static String compile_to_c_code();
CORE_Static Ast_Module *ast_module(Token *pos, Intern_String filename); CORE_Static Ast_Module *ast_module(Token *pos, Intern_String filename);
CORE_Static void insert_builtin_types_into_scope(Ast_Scope *p); CORE_Static void insert_builtin_types_into_scope(Ast_Scope *p);
CORE_Static void insert_into_scope(Ast_Scope *scope, Ast_Decl *decl); CORE_Static void insert_into_scope(Ast_Scope *scope, Ast_Decl *decl);
CORE_Static Ast_Type *type_incomplete(Ast *ast); CORE_Static Ast_Type *type_incomplete(Ast *ast);
CORE_Static Ast_Expr *parse_expr(S64 minbp = 0); CORE_Static Ast_Expr *parse_expr(S64 minbp = 0);

View File

@@ -1,34 +1,34 @@
#include "base.cpp" #include "../base/base.cpp"
#define STB_SPRINTF_IMPLEMENTATION #define STB_SPRINTF_IMPLEMENTATION
#include "stb_sprintf.h" #include "../base/stb_sprintf.h"
#include "base_unicode.cpp" #include "../base/base_unicode.cpp"
#include "base_arena.cpp" #include "../base/base_arena.cpp"
#include "base_data_structures.cpp" #include "../base/base_data_structures.cpp"
#include "base_string.cpp" #include "../base/base_string.cpp"
#include "os.h" #include "../os/os.h"
#if OS_WINDOWS #if OS_WINDOWS
#include "os_windows.cpp" #include "../os/os_windows.cpp"
#elif OS_LINUX #elif OS_LINUX
#include "os_linux.cpp" #include "../os/os_linux.cpp"
#else #else
#error Couldnt figure out OS using macros #error Couldnt figure out OS using macros
#endif #endif
#include "core_compiler_interface.hpp" #include "core_compiler_interface.hpp"
#include "c3_big_int.h" #include "c3_big_int.h"
#include "core_compiler.h" #include "core_compiler.h"
#include "core_types.h" #include "core_types.h"
#include "core_globals.cpp" #include "core_globals.cpp"
#include "core_generated.cpp" #include "core_generated.cpp"
#include "c3_big_int.cpp" #include "c3_big_int.cpp"
#include "core_lexing.cpp" #include "core_lexing.cpp"
#include "core_ast.cpp" #include "core_ast.cpp"
#include "core_parsing.cpp" #include "core_parsing.cpp"
#include "core_typechecking.h" #include "core_typechecking.h"
#include "core_types.cpp" #include "core_types.cpp"
#include "core_polymorph.cpp" #include "core_polymorph.cpp"
#include "core_typechecking.cpp" #include "core_typechecking.cpp"
#include "core_compiler.cpp" #include "core_compiler.cpp"
#include "core_codegen_c_language.cpp" #include "core_codegen_c_language.cpp"
#include "core_printer.cpp" #include "core_printer.cpp"

View File

@@ -1,82 +1,82 @@
/*#import meta /*#import meta
print("""CORE_Static Ast_Operator_Info * print("""CORE_Static Ast_Operator_Info *
get_operator_info(Token_Kind op){ get_operator_info(Token_Kind op){
switch(op){""") switch(op){""")
index = 0 index = 0
for i in meta.token_simple_expr: for i in meta.token_simple_expr:
if i[1] != "SPECIAL": if i[1] != "SPECIAL":
print(f""" case TK_{i[0]}: return pctx->op_info_table + {index};""") print(f""" case TK_{i[0]}: return pctx->op_info_table + {index};""")
index += 1 index += 1
print(" default: {}\n }") print(" default: {}\n }")
print(" return 0;\n}") print(" return 0;\n}")
print("""CORE_Static Ast_Operator_Info * print("""CORE_Static Ast_Operator_Info *
get_operator_info(Intern_String op){ get_operator_info(Intern_String op){
if(0){}""") if(0){}""")
index = 0 index = 0
for i in meta.token_simple_expr: for i in meta.token_simple_expr:
if i[1] != "SPECIAL": if i[1] != "SPECIAL":
print(f""" else if(pctx->op_info_table[{index}].op.str == op.str) return pctx->op_info_table + {index};""") print(f""" else if(pctx->op_info_table[{index}].op.str == op.str) return pctx->op_info_table + {index};""")
index += 1 index += 1
print(" return 0;\n}") print(" return 0;\n}")
*/ */
CORE_Static Ast_Operator_Info * CORE_Static Ast_Operator_Info *
get_operator_info(Token_Kind op) { get_operator_info(Token_Kind op) {
switch (op) { switch (op) {
case TK_Mul: return pctx->op_info_table + 0; case TK_Mul: return pctx->op_info_table + 0;
case TK_Div: return pctx->op_info_table + 1; case TK_Div: return pctx->op_info_table + 1;
case TK_Mod: return pctx->op_info_table + 2; case TK_Mod: return pctx->op_info_table + 2;
case TK_LeftShift: return pctx->op_info_table + 3; case TK_LeftShift: return pctx->op_info_table + 3;
case TK_RightShift: return pctx->op_info_table + 4; case TK_RightShift: return pctx->op_info_table + 4;
case TK_Add: return pctx->op_info_table + 5; case TK_Add: return pctx->op_info_table + 5;
case TK_Sub: return pctx->op_info_table + 6; case TK_Sub: return pctx->op_info_table + 6;
case TK_Equals: return pctx->op_info_table + 7; case TK_Equals: return pctx->op_info_table + 7;
case TK_LesserThenOrEqual: return pctx->op_info_table + 8; case TK_LesserThenOrEqual: return pctx->op_info_table + 8;
case TK_GreaterThenOrEqual: return pctx->op_info_table + 9; case TK_GreaterThenOrEqual: return pctx->op_info_table + 9;
case TK_LesserThen: return pctx->op_info_table + 10; case TK_LesserThen: return pctx->op_info_table + 10;
case TK_GreaterThen: return pctx->op_info_table + 11; case TK_GreaterThen: return pctx->op_info_table + 11;
case TK_NotEquals: return pctx->op_info_table + 12; case TK_NotEquals: return pctx->op_info_table + 12;
case TK_BitAnd: return pctx->op_info_table + 13; case TK_BitAnd: return pctx->op_info_table + 13;
case TK_BitOr: return pctx->op_info_table + 14; case TK_BitOr: return pctx->op_info_table + 14;
case TK_BitXor: return pctx->op_info_table + 15; case TK_BitXor: return pctx->op_info_table + 15;
case TK_And: return pctx->op_info_table + 16; case TK_And: return pctx->op_info_table + 16;
case TK_Or: return pctx->op_info_table + 17; case TK_Or: return pctx->op_info_table + 17;
case TK_Neg: return pctx->op_info_table + 18; case TK_Neg: return pctx->op_info_table + 18;
case TK_Not: return pctx->op_info_table + 19; case TK_Not: return pctx->op_info_table + 19;
default: { default: {
} }
} }
return 0; return 0;
} }
CORE_Static Ast_Operator_Info * CORE_Static Ast_Operator_Info *
get_operator_info(Intern_String op) { get_operator_info(Intern_String op) {
if (0) { if (0) {
} }
else if (pctx->op_info_table[0].op.str == op.str) return pctx->op_info_table + 0; else if (pctx->op_info_table[0].op.str == op.str) return pctx->op_info_table + 0;
else if (pctx->op_info_table[1].op.str == op.str) return pctx->op_info_table + 1; else if (pctx->op_info_table[1].op.str == op.str) return pctx->op_info_table + 1;
else if (pctx->op_info_table[2].op.str == op.str) return pctx->op_info_table + 2; else if (pctx->op_info_table[2].op.str == op.str) return pctx->op_info_table + 2;
else if (pctx->op_info_table[3].op.str == op.str) return pctx->op_info_table + 3; else if (pctx->op_info_table[3].op.str == op.str) return pctx->op_info_table + 3;
else if (pctx->op_info_table[4].op.str == op.str) return pctx->op_info_table + 4; else if (pctx->op_info_table[4].op.str == op.str) return pctx->op_info_table + 4;
else if (pctx->op_info_table[5].op.str == op.str) return pctx->op_info_table + 5; else if (pctx->op_info_table[5].op.str == op.str) return pctx->op_info_table + 5;
else if (pctx->op_info_table[6].op.str == op.str) return pctx->op_info_table + 6; else if (pctx->op_info_table[6].op.str == op.str) return pctx->op_info_table + 6;
else if (pctx->op_info_table[7].op.str == op.str) return pctx->op_info_table + 7; else if (pctx->op_info_table[7].op.str == op.str) return pctx->op_info_table + 7;
else if (pctx->op_info_table[8].op.str == op.str) return pctx->op_info_table + 8; else if (pctx->op_info_table[8].op.str == op.str) return pctx->op_info_table + 8;
else if (pctx->op_info_table[9].op.str == op.str) return pctx->op_info_table + 9; else if (pctx->op_info_table[9].op.str == op.str) return pctx->op_info_table + 9;
else if (pctx->op_info_table[10].op.str == op.str) return pctx->op_info_table + 10; else if (pctx->op_info_table[10].op.str == op.str) return pctx->op_info_table + 10;
else if (pctx->op_info_table[11].op.str == op.str) return pctx->op_info_table + 11; else if (pctx->op_info_table[11].op.str == op.str) return pctx->op_info_table + 11;
else if (pctx->op_info_table[12].op.str == op.str) return pctx->op_info_table + 12; else if (pctx->op_info_table[12].op.str == op.str) return pctx->op_info_table + 12;
else if (pctx->op_info_table[13].op.str == op.str) return pctx->op_info_table + 13; else if (pctx->op_info_table[13].op.str == op.str) return pctx->op_info_table + 13;
else if (pctx->op_info_table[14].op.str == op.str) return pctx->op_info_table + 14; else if (pctx->op_info_table[14].op.str == op.str) return pctx->op_info_table + 14;
else if (pctx->op_info_table[15].op.str == op.str) return pctx->op_info_table + 15; else if (pctx->op_info_table[15].op.str == op.str) return pctx->op_info_table + 15;
else if (pctx->op_info_table[16].op.str == op.str) return pctx->op_info_table + 16; else if (pctx->op_info_table[16].op.str == op.str) return pctx->op_info_table + 16;
else if (pctx->op_info_table[17].op.str == op.str) return pctx->op_info_table + 17; else if (pctx->op_info_table[17].op.str == op.str) return pctx->op_info_table + 17;
else if (pctx->op_info_table[18].op.str == op.str) return pctx->op_info_table + 18; else if (pctx->op_info_table[18].op.str == op.str) return pctx->op_info_table + 18;
else if (pctx->op_info_table[19].op.str == op.str) return pctx->op_info_table + 19; else if (pctx->op_info_table[19].op.str == op.str) return pctx->op_info_table + 19;
return 0; return 0;
} }
/*END*/ /*END*/

View File

@@ -1,7 +1,7 @@
thread_local Core_Ctx *pctx; thread_local Core_Ctx *pctx;
Allocator *bigint_allocator; Allocator *bigint_allocator;
global S64 bigint_allocation_count; global S64 bigint_allocation_count;
const uintptr_t pointer_size = sizeof(uintptr_t); const uintptr_t pointer_size = sizeof(uintptr_t);
const uintptr_t pointer_align = __alignof(uintptr_t); const uintptr_t pointer_align = __alignof(uintptr_t);

File diff suppressed because it is too large Load Diff

View File

@@ -1,175 +1,176 @@
/* /*
Features Features
- Add := for default arguments in lambda. (a := false, b := false) - Add := for default arguments in lambda. (a := false, b := false)
- Add struct default values. - Add struct default values.
- Add for loop: - Add for loop:
- for i: int = 0, i < 10, i+=1 - for i: int = 0, i < 10, i+=1
- for diff: array - for diff: array
- iterator how to do this without function poly ? for it := iter_begin(), iter_valid(), iter_advance() - iterator how to do this without function poly ? for it := iter_begin(), iter_valid(), iter_advance()
- Expand macros - Expand macros
- Using directive to bring symbols into local scope - Using directive to bring symbols into local scope
- Other kinds of casts, a cast from structs of same layout, a cast without conversion - Other kinds of casts, a cast from structs of same layout, a cast without conversion
- Inject symbols into a declaration / namespace ?? - Inject symbols into a declaration / namespace ??
- Optionally pass size and alignment calculations to C ? - Optionally pass size and alignment calculations to C ?
Cleanup Cleanup
- Look into unifying lambda expressions and lambda declarations - Look into unifying lambda expressions and lambda declarations
- Ast_Module shouldn't require Ast_File to hold declarations etc. I think - Ast_Module shouldn't require Ast_File to hold declarations etc. I think
- Look into a different way of passing arguments in typechecking - Look into a different way of passing arguments in typechecking
- Separate out the codegen stage cause that can change - Separate out the codegen stage cause that can change
- Robust c declaration generation - Robust c declaration generation
- Nicer / more readable expression generation - Nicer / more readable expression generation
- Detecting if return was called - Detecting if return was called
- Look into String_Builders in Core_Ctx - Look into String_Builders in Core_Ctx
- Look into stage allocator and perhaps - Look into stage allocator and perhaps
use it more often to reduce scenarios use it more often to reduce scenarios
with 2 allocators, and simplify stuff with 2 allocators, and simplify stuff
- Clean way to free all memory and reset the compiler - Clean way to free all memory and reset the compiler
- Bring the table? - Bring the table?
- Nice way of creating valid declarations programatically - Nice way of creating valid declarations programatically
core_create_namespace("memes", { core_create_namespace("memes", {
core_basic_type( core_basic_type(
}, 4); }, 4);
Robustness Robustness
- Test suite that expects test to error out - Test suite that expects test to error out
- Fix and decide what to do when initializing global variable using not constants C:/AProgramming/cparse/compiler/modules/Language.core:180:28: error: initializer element is not a compile-time constant - Fix and decide what to do when initializing global variable using not constants C:/AProgramming/cparse/compiler/modules/Language.core:180:28: error: initializer element is not a compile-time constant
- Test and bulletproof any, slices - Test and bulletproof any, slices
- This error is valid error case when someone creates a compound out of basic type C:/AProgramming/cparse/compiler/examples/arms_race/arms_race.core:137 Internal compiler error: Invalid type was passed to the compound expression, should have been an array, struct or slice - This error is valid error case when someone creates a compound out of basic type C:/AProgramming/cparse/compiler/examples/arms_race/arms_race.core:137 Internal compiler error: Invalid type was passed to the compound expression, should have been an array, struct or slice
result := String{data, filesize} result := String{data, filesize}
Bytecode interpreter Bytecode interpreter
- Ir - Ir
- Interpreter - Interpreter
- Code generation - Code generation
Fun Fun
- Inject stack traces into the program - Inject stack traces into the program
- Inject instrumentation into the program - Inject instrumentation into the program
Ideas Ideas
- Constant arrays that evaluate fully at compile time - Constant arrays that evaluate fully at compile time
- Rust like enum where you associate values(other structs) with key - Rust like enum where you associate values(other structs) with key
*/ */
#include "core_compiler_includes.cpp" #include "core_compiler_includes.cpp"
const U32 COMPILE_NULL = 0x0; const U32 COMPILE_NULL = 0x0;
const U32 COMPILE_PRINT_STATS = 0x1; const U32 COMPILE_PRINT_STATS = 0x1;
const U32 COMPILE_PRINT_ALLOCATOR_STATS_BEFORE_DESTROY = 0x2; const U32 COMPILE_PRINT_ALLOCATOR_STATS_BEFORE_DESTROY = 0x2;
const U32 COMPILE_AND_RUN = 0x4; const U32 COMPILE_AND_RUN = 0x4;
const U32 COMPILE_TESTING = 0x8; const U32 COMPILE_TESTING = 0x8;
const U32 DONT_USE_C_COMPILER = 0x10; const U32 DONT_USE_C_COMPILER = 0x10;
static void compile_file(Allocator *allocator, String filename, U32 compile_flags = COMPILE_NULL) { static void compile_file(Allocator *allocator, String filename, U32 compile_flags = COMPILE_NULL) {
if (is_flag_set(compile_flags, COMPILE_AND_RUN)) { if (is_flag_set(compile_flags, COMPILE_AND_RUN)) {
printf("%s - ", filename.str); printf("%s - ", filename.str);
} }
String result = compile_file_to_string(allocator, filename); String result = compile_file_to_string(allocator, filename);
B32 r = os_write_file("generated_main.c"_s, result); B32 r = os_write_file("generated_main.c"_s, result);
assert(r); assert(r);
F64 total_compiler_time = os_time() - pctx->time.start; F64 total_compiler_time = os_time() - pctx->time.start;
printf("%f - ", total_compiler_time); printf("%f - ", total_compiler_time);
Scoped_Arena scratch(pctx->scratch); Scoped_Arena scratch(pctx->scratch);
F64 begin = os_time(); F64 begin = os_time();
if (!is_flag_set(compile_flags, DONT_USE_C_COMPILER)) { if (!is_flag_set(compile_flags, DONT_USE_C_COMPILER)) {
String_Builder builder = {scratch.arena}; String_Builder builder = {scratch.arena};
builder.addf("clang generated_main.c -Wall -Wno-unused-function -Wno-parentheses-equality -g -o a" OS_EXE " "); builder.addf("clang generated_main.c -Wall -Wno-unused-function -Wno-parentheses-equality -g -o a" OS_EXE " ");
For(pctx->files_to_link) { For(pctx->files_to_link) {
builder.addf("-l%Q ", it->intern_val); builder.addf("-l%Q ", it->intern_val);
} }
String compiler_call = string_flatten(scratch.arena, &builder); String compiler_call = string_flatten(scratch.arena, &builder);
system((const char *)compiler_call.str); system((const char *)compiler_call.str);
printf("%s\n", compiler_call.str); printf("%s\n", compiler_call.str);
} }
F64 end = os_time(); F64 end = os_time();
if (is_flag_set(compile_flags, COMPILE_PRINT_STATS)) { if (is_flag_set(compile_flags, COMPILE_PRINT_STATS)) {
printf("total = %f\n", os_time() - pctx->time.start); F64 total = os_time() - pctx->time.start;
printf("core_total = %f\n", pctx->time.total); printf("total = %f\n", total);
if (!is_flag_set(compile_flags, DONT_USE_C_COMPILER)) printf("clang = %f\n", end - begin); printf("core_total = %f\n", pctx->time.total);
printf("parsing = %f\n", pctx->time.parsing); if (!is_flag_set(compile_flags, DONT_USE_C_COMPILER)) printf("clang = %f\n", end - begin);
printf("typecheck = %f\n", pctx->time.typechecking); printf("parsing = %f\n", pctx->time.parsing);
printf("generatin = %f\n", pctx->time.code_generation); printf("typecheck = %f\n", pctx->time.typechecking);
printf("lines lexed= %d\n", pctx->lines_lexed); printf("generatin = %f\n", pctx->time.code_generation);
} printf("lines lexed= %d\n", pctx->lines_lexed);
}
if (is_flag_set(compile_flags, COMPILE_PRINT_ALLOCATOR_STATS_BEFORE_DESTROY)) {
// @! Allocator stats if (is_flag_set(compile_flags, COMPILE_PRINT_ALLOCATOR_STATS_BEFORE_DESTROY)) {
} // @! Allocator stats
}
if (is_flag_set(compile_flags, COMPILE_AND_RUN)) {
String testing = compile_flags & COMPILE_TESTING ? "testing"_s : ""_s; if (is_flag_set(compile_flags, COMPILE_AND_RUN)) {
#if OS_WINDOWS String testing = compile_flags & COMPILE_TESTING ? "testing"_s : ""_s;
String sys = string_fmt(scratch.arena, "a.exe %Q", testing); #if OS_WINDOWS
#else String sys = string_fmt(scratch.arena, "a.exe %Q", testing);
String sys = string_fmt(scratch.arena, "./a.out %Q", testing); #else
#endif String sys = string_fmt(scratch.arena, "./a.out %Q", testing);
int result = system((char *)sys.str); #endif
assert(result != -1); int result = system((char *)sys.str);
if (result == 0) { assert(result != -1);
printf(PRINTF_GREEN "OK!" PRINTF_RESET); if (result == 0) {
} printf(PRINTF_GREEN "OK!" PRINTF_RESET);
if (result != 0) { }
printf(PRINTF_RED "ERROR!" PRINTF_RESET); if (result != 0) {
} printf(PRINTF_RED "ERROR!" PRINTF_RESET);
printf("\n"); }
} printf("\n");
} }
}
int main(int argument_count, char **arguments) {
os_enable_console_colors(); int main(int argument_count, char **arguments) {
Arena arena = {}; os_enable_console_colors();
Arena scratch = {}; Arena arena = {};
arena_init(&arena, "Pernament arena"_s); Arena scratch = {};
arena_init(&scratch, "Pernament scratch arena"_s); arena_init(&arena, "Pernament arena"_s);
arena_init(&scratch, "Pernament scratch arena"_s);
Array<String> args = {&scratch};
for (int i = 1; i < argument_count; i += 1) { Array<String> args = {&scratch};
String arg = string_from_cstring(arguments[i]); for (int i = 1; i < argument_count; i += 1) {
args.add(arg); String arg = string_from_cstring(arguments[i]);
} args.add(arg);
}
if (!args.len) {
printf("Please specify a file to compile!"); if (!args.len) {
return 0; printf("Please specify a file to compile!");
} return 0;
}
For(args) {
if (it == "-testing"_s) { For(args) {
Scoped_Arena _scope(&scratch); if (it == "-testing"_s) {
Array<OS_File_Info> examples = os_list_dir(&scratch, &scratch, "examples"_s); Scoped_Arena _scope(&scratch);
Array<OS_File_Info> tests = os_list_dir(&scratch, &scratch, "tests"_s); Array<OS_File_Info> examples = os_list_dir(&scratch, &scratch, "examples"_s);
For(examples) { Array<OS_File_Info> tests = os_list_dir(&scratch, &scratch, "tests"_s);
if (it.is_directory) continue; For(examples) {
String filename = string_skip_to_last_slash(it.relative_path); if (it.is_directory) continue;
if (filename.len && filename.str[0] == '_') continue; String filename = string_skip_to_last_slash(it.relative_path);
compile_file(&arena, it.absolute_path, COMPILE_AND_RUN | COMPILE_TESTING); if (filename.len && filename.str[0] == '_') continue;
} compile_file(&arena, it.absolute_path, COMPILE_AND_RUN | COMPILE_TESTING);
For(tests) { }
if (it.is_directory) continue; For(tests) {
compile_file(&arena, it.absolute_path, COMPILE_AND_RUN | COMPILE_TESTING); if (it.is_directory) continue;
} compile_file(&arena, it.absolute_path, COMPILE_AND_RUN | COMPILE_TESTING);
} }
}
else {
String program_name = string_from_cstring(arguments[1]); else {
compile_file(&arena, program_name, COMPILE_PRINT_STATS | DONT_USE_C_COMPILER); String program_name = string_from_cstring(arguments[1]);
} compile_file(&arena, program_name, COMPILE_PRINT_STATS | DONT_USE_C_COMPILER);
} }
printf("End of program\n"); }
if (IsDebuggerPresent()) { printf("End of program\n");
Breakpoint; if (IsDebuggerPresent()) {
} Breakpoint;
}
return 0;
} return 0;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,375 +1,375 @@
// @todo @cleanup ?? // @todo @cleanup ??
// :PrinterCleanup // :PrinterCleanup
// Instead of relying on global state, this probably should // Instead of relying on global state, this probably should
// use a String_Builder or some kind of Builder context + macros // use a String_Builder or some kind of Builder context + macros
CORE_Static String CORE_Static String
core_type_to_string(Ast_Type *type) { core_type_to_string(Ast_Type *type) {
// @todo: use get_name_of_type instead of duplicating the typename dispatch table // @todo: use get_name_of_type instead of duplicating the typename dispatch table
switch (type->kind) { switch (type->kind) {
case TYPE_NONE: return "<NONE>"_s; break; case TYPE_NONE: return "<NONE>"_s; break;
case TYPE_S64: return "S64"_s; break; case TYPE_S64: return "S64"_s; break;
case TYPE_S32: return "S32"_s; break; case TYPE_S32: return "S32"_s; break;
case TYPE_S16: return "S16"_s; break; case TYPE_S16: return "S16"_s; break;
case TYPE_S8: return "S8"_s; break; case TYPE_S8: return "S8"_s; break;
case TYPE_CHAR: return "char"_s; case TYPE_CHAR: return "char"_s;
case TYPE_UCHAR: return "uchar"_s; case TYPE_UCHAR: return "uchar"_s;
case TYPE_INT: return "int"_s; case TYPE_INT: return "int"_s;
case TYPE_UINT: return "uint"_s; case TYPE_UINT: return "uint"_s;
case TYPE_LONG: return "long"_s; case TYPE_LONG: return "long"_s;
case TYPE_ULONG: return "ulong"_s; case TYPE_ULONG: return "ulong"_s;
case TYPE_LLONG: return "llong"_s; case TYPE_LLONG: return "llong"_s;
case TYPE_ULLONG: return "ullong"_s; case TYPE_ULLONG: return "ullong"_s;
case TYPE_SHORT: return "short"_s; case TYPE_SHORT: return "short"_s;
case TYPE_USHORT: return "ushort"_s; case TYPE_USHORT: return "ushort"_s;
case TYPE_U64: return "U64"_s; break; case TYPE_U64: return "U64"_s; break;
case TYPE_U32: return "U32"_s; break; case TYPE_U32: return "U32"_s; break;
case TYPE_U16: return "U16"_s; break; case TYPE_U16: return "U16"_s; break;
case TYPE_U8: return "U8"_s; break; case TYPE_U8: return "U8"_s; break;
case TYPE_F32: return "F32"_s; break; case TYPE_F32: return "F32"_s; break;
case TYPE_F64: return "F64"_s; break; case TYPE_F64: return "F64"_s; break;
case TYPE_BOOL: return "bool"_s; break; case TYPE_BOOL: return "bool"_s; break;
case TYPE_STRING: return "String"_s; break; case TYPE_STRING: return "String"_s; break;
case TYPE_VOID: return "void"_s; break; case TYPE_VOID: return "void"_s; break;
case TYPE_POINTER: { case TYPE_POINTER: {
String base = core_type_to_string(type->base); String base = core_type_to_string(type->base);
return pctx->fmt("*%Q", base); return pctx->fmt("*%Q", base);
} break; } break;
case TYPE_LAMBDA: { case TYPE_LAMBDA: {
String_Builder *b = &pctx->helper_builder; String_Builder *b = &pctx->helper_builder;
b->addf("("); b->addf("(");
Array<Ast_Type *> &args = type->func.args; Array<Ast_Type *> &args = type->func.args;
For(args) { For(args) {
String t = core_type_to_string(it); String t = core_type_to_string(it);
b->addf("%Q", t); b->addf("%Q", t);
if (!args.is_last(it)) b->addf(", "); if (!args.is_last(it)) b->addf(", ");
} }
b->addf(")"); b->addf(")");
if (type->func.ret) { if (type->func.ret) {
String t = core_type_to_string(type->func.ret); String t = core_type_to_string(type->func.ret);
b->addf("%Q", t); b->addf("%Q", t);
} }
String result = string_flatten(pctx->perm, b); String result = string_flatten(pctx->perm, b);
return result; return result;
} break; } break;
case TYPE_STRUCT: case TYPE_STRUCT:
case TYPE_UNION: case TYPE_UNION:
case TYPE_ENUM: { case TYPE_ENUM: {
// @fixme: we probably want a string on Ast_Type // @fixme: we probably want a string on Ast_Type
// so that we don't have to reach into Ast_Decl // so that we don't have to reach into Ast_Decl
// for Structs Enums etc. // for Structs Enums etc.
Ast_Decl *decl = (Ast_Decl *)type->ast; Ast_Decl *decl = (Ast_Decl *)type->ast;
return decl->name.s; return decl->name.s;
} break; } break;
case TYPE_ARRAY: { case TYPE_ARRAY: {
String base = core_type_to_string(type->base); String base = core_type_to_string(type->base);
return pctx->fmt("[%u]%Q", type->arr.size, base); return pctx->fmt("[%u]%Q", type->arr.size, base);
} break; } break;
case TYPE_SLICE: { case TYPE_SLICE: {
String base = core_type_to_string(type->base); String base = core_type_to_string(type->base);
return pctx->fmt("[]%Q", base); return pctx->fmt("[]%Q", base);
} break; } break;
case TYPE_TYPE: return "Type"_s; break; case TYPE_TYPE: return "Type"_s; break;
case TYPE_UNTYPED_BOOL: return "UntypedBool"_s; break; case TYPE_UNTYPED_BOOL: return "UntypedBool"_s; break;
case TYPE_UNTYPED_INT: return "UntypedInt"_s; break; case TYPE_UNTYPED_INT: return "UntypedInt"_s; break;
case TYPE_UNTYPED_FLOAT: return "UntypedFloat"_s; break; case TYPE_UNTYPED_FLOAT: return "UntypedFloat"_s; break;
case TYPE_UNTYPED_STRING: return "UntypedString"_s; break; case TYPE_UNTYPED_STRING: return "UntypedString"_s; break;
case TYPE_COMPLETING: invalid_codepath; break; case TYPE_COMPLETING: invalid_codepath; break;
case TYPE_INCOMPLETE: invalid_codepath; break; case TYPE_INCOMPLETE: invalid_codepath; break;
case TYPE_POLYMORPH: case TYPE_POLYMORPH:
invalid_codepath; invalid_codepath;
break; break;
invalid_default_case; invalid_default_case;
} }
invalid_return; invalid_return;
} }
void core__stringify(Ast *ast) { void core__stringify(Ast *ast) {
if (!ast) return; if (!ast) return;
gen("@%u", ast->di); gen("@%u", ast->di);
switch (ast->kind) { switch (ast->kind) {
case AST_SCOPE: { case AST_SCOPE: {
Ast_Scope *n = (Ast_Scope *)ast; Ast_Scope *n = (Ast_Scope *)ast;
global_indent += 1; global_indent += 1;
genln("@%u", n->di); genln("@%u", n->di);
For(n->decls) { For(n->decls) {
genln(""); genln("");
core__stringify(it); core__stringify(it);
} }
For(n->stmts) { For(n->stmts) {
genln(""); genln("");
core__stringify(it); core__stringify(it);
} }
global_indent -= 1; global_indent -= 1;
} break; } break;
case AST_MODULE: invalid_codepath; break; case AST_MODULE: invalid_codepath; break;
case AST_FILE: invalid_codepath; break; case AST_FILE: invalid_codepath; break;
case AST_IDENT: { case AST_IDENT: {
Ast_Atom *n = (Ast_Atom *)ast; Ast_Atom *n = (Ast_Atom *)ast;
gen("%Q", n->intern_val); gen("%Q", n->intern_val);
} break; } break;
case AST_VALUE: { case AST_VALUE: {
Ast_Atom *n = (Ast_Atom *)ast; //@todo: proper value Ast_Atom *n = (Ast_Atom *)ast; //@todo: proper value
gen("%Q", n->pos->string); gen("%Q", n->pos->string);
} break; } break;
case AST_INDEX: { case AST_INDEX: {
Ast_Index *n = (Ast_Index *)ast; Ast_Index *n = (Ast_Index *)ast;
core__stringify(n->expr); core__stringify(n->expr);
gen("["); gen("[");
core__stringify(n->index); core__stringify(n->index);
gen("]"); gen("]");
} break; } break;
case AST_UNARY: { case AST_UNARY: {
Ast_Unary *n = (Ast_Unary *)ast; Ast_Unary *n = (Ast_Unary *)ast;
gen("%Q", n->pos->string); gen("%Q", n->pos->string);
core__stringify(n->expr); core__stringify(n->expr);
} break; } break;
case AST_BINARY: { case AST_BINARY: {
Ast_Binary *n = (Ast_Binary *)ast; Ast_Binary *n = (Ast_Binary *)ast;
core__stringify(n->left); core__stringify(n->left);
gen("%Q", n->pos->string); gen("%Q", n->pos->string);
core__stringify(n->right); core__stringify(n->right);
} break; } break;
case AST_CALL_ITEM: { case AST_CALL_ITEM: {
Ast_Call_Item *n = (Ast_Call_Item *)ast; Ast_Call_Item *n = (Ast_Call_Item *)ast;
if (n->call_flags & CALL_INDEX) { if (n->call_flags & CALL_INDEX) {
core__stringify(n->index); core__stringify(n->index);
gen(" = "); gen(" = ");
} }
else if (n->call_flags & CALL_NAME) { else if (n->call_flags & CALL_NAME) {
core__stringify(n->name); core__stringify(n->name);
gen(" = "); gen(" = ");
} }
core__stringify(n->item); core__stringify(n->item);
} break; } break;
case AST_CALL: { case AST_CALL: {
Ast_Call *n = (Ast_Call *)ast; Ast_Call *n = (Ast_Call *)ast;
core__stringify(n->name); core__stringify(n->name);
gen("("); gen("(");
For(n->exprs) { For(n->exprs) {
core__stringify(it); core__stringify(it);
if (!n->exprs.is_last(it)) gen(","); if (!n->exprs.is_last(it)) gen(",");
} }
gen(")"); gen(")");
} break; } break;
case AST_COMPOUND: { case AST_COMPOUND: {
Ast_Call *n = (Ast_Call *)ast; Ast_Call *n = (Ast_Call *)ast;
core__stringify(n->name); core__stringify(n->name);
gen("{"); gen("{");
global_indent += 1; global_indent += 1;
For(n->exprs) { For(n->exprs) {
genln(""); genln("");
core__stringify(it); core__stringify(it);
gen(","); gen(",");
} }
global_indent -= 1; global_indent -= 1;
genln("}"); genln("}");
} break; } break;
case AST_TYPE_OF: case AST_TYPE_OF:
gen("typeof"); gen("typeof");
goto builtin; goto builtin;
case AST_LENGTH_OF: case AST_LENGTH_OF:
gen("LengthOf"); gen("LengthOf");
goto builtin; goto builtin;
case AST_ALIGN_OF: case AST_ALIGN_OF:
gen("alignof"); gen("alignof");
goto builtin; goto builtin;
case AST_SIZE_OF: case AST_SIZE_OF:
gen("sizeof"); gen("sizeof");
goto builtin; goto builtin;
case AST_RUNTIME_ASSERT: case AST_RUNTIME_ASSERT:
gen("Assert"); gen("Assert");
goto builtin; goto builtin;
case AST_CONSTANT_ASSERT: case AST_CONSTANT_ASSERT:
gen("#Assert"); gen("#Assert");
goto builtin; goto builtin;
builtin : { builtin : {
Ast_Builtin *n = (Ast_Builtin *)ast; Ast_Builtin *n = (Ast_Builtin *)ast;
gen("("); gen("(");
core__stringify(n->expr); core__stringify(n->expr);
gen(")"); gen(")");
} break; } break;
case AST_SWITCH: { case AST_SWITCH: {
Ast_Switch *n = (Ast_Switch *)ast; Ast_Switch *n = (Ast_Switch *)ast;
core__stringify(n->value); core__stringify(n->value);
For(n->cases) { For(n->cases) {
core__stringify(it); core__stringify(it);
} }
core__stringify(n->default_scope); core__stringify(n->default_scope);
} break; } break;
case AST_SWITCH_CASE: { case AST_SWITCH_CASE: {
Ast_Switch_Case *n = (Ast_Switch_Case *)ast; Ast_Switch_Case *n = (Ast_Switch_Case *)ast;
For(n->labels) { For(n->labels) {
core__stringify(it); core__stringify(it);
} }
core__stringify(n->scope); core__stringify(n->scope);
} break; } break;
case AST_VAR_UNPACK: { case AST_VAR_UNPACK: {
Ast_Var_Unpack *n = (Ast_Var_Unpack *)ast; Ast_Var_Unpack *n = (Ast_Var_Unpack *)ast;
For(n->vars) { For(n->vars) {
core__stringify(it); core__stringify(it);
if (!n->vars.is_last(it)) gen(","); if (!n->vars.is_last(it)) gen(",");
} }
gen(" = "); gen(" = ");
core__stringify(n->expr); core__stringify(n->expr);
} break; } break;
case AST_DEFER: { case AST_DEFER: {
auto n = (Ast_Defer *)ast; auto n = (Ast_Defer *)ast;
genln("defer"); genln("defer");
core__stringify(n->scope); core__stringify(n->scope);
} break; } break;
case AST_PASS: { case AST_PASS: {
genln("pass"); genln("pass");
} break; } break;
case AST_CONTINUE: { case AST_CONTINUE: {
genln("continue"); genln("continue");
} break; } break;
case AST_BREAK: { case AST_BREAK: {
genln("break"); genln("break");
} break; } break;
case AST_NAMESPACE: { case AST_NAMESPACE: {
Ast_Decl *n = (Ast_Decl *)ast; Ast_Decl *n = (Ast_Decl *)ast;
gen("%Q :: NAMESPACE", n->name); gen("%Q :: NAMESPACE", n->name);
} break; } break;
case AST_UNION: case AST_UNION:
case AST_STRUCT: { case AST_STRUCT: {
Ast_Decl *n = (Ast_Decl *)ast; Ast_Decl *n = (Ast_Decl *)ast;
genln("%Q :: %s", n->name, n->kind == AST_STRUCT ? "struct" : "union"); genln("%Q :: %s", n->name, n->kind == AST_STRUCT ? "struct" : "union");
core__stringify(n->scope); core__stringify(n->scope);
} break; } break;
case AST_ENUM: { case AST_ENUM: {
Ast_Decl *n = (Ast_Decl *)ast; Ast_Decl *n = (Ast_Decl *)ast;
genln("%Q :: enum", n->name); genln("%Q :: enum", n->name);
core__stringify(n->scope); core__stringify(n->scope);
} break; } break;
case AST_LAMBDA: { case AST_LAMBDA: {
Ast_Decl *n = (Ast_Decl *)ast; Ast_Decl *n = (Ast_Decl *)ast;
genln("%Q :: ", n->name); genln("%Q :: ", n->name);
core__stringify(n->lambda); // @cleanup core__stringify(n->lambda); // @cleanup
} break; } break;
// @cleanup: what is this used for? // @cleanup: what is this used for?
case AST_TYPE: { case AST_TYPE: {
invalid_codepath; invalid_codepath;
} break; } break;
case AST_CONST: { case AST_CONST: {
Ast_Decl *n = (Ast_Decl *)ast; Ast_Decl *n = (Ast_Decl *)ast;
gen("%Q :: CONST value @todo", n->name); gen("%Q :: CONST value @todo", n->name);
} break; } break;
case AST_VAR: { case AST_VAR: {
Ast_Decl *n = (Ast_Decl *)ast; Ast_Decl *n = (Ast_Decl *)ast;
gen("%Q: %Q", n->name, core_type_to_string(n->type)); gen("%Q: %Q", n->name, core_type_to_string(n->type));
if (n->expr) { if (n->expr) {
gen(" = "); gen(" = ");
core__stringify(n->expr); core__stringify(n->expr);
} }
} break; } break;
case AST_ARRAY: { case AST_ARRAY: {
Ast_Array *n = (Ast_Array *)ast; Ast_Array *n = (Ast_Array *)ast;
gen("["); gen("[");
core__stringify(n->expr); core__stringify(n->expr);
gen("]"); gen("]");
core__stringify(n->base); core__stringify(n->base);
} break; } break;
case AST_FOR: { case AST_FOR: {
Ast_For *n = (Ast_For *)ast; Ast_For *n = (Ast_For *)ast;
gen("for "); gen("for ");
core__stringify(n->init); core__stringify(n->init);
if (n->cond) gen(", "); if (n->cond) gen(", ");
core__stringify(n->cond); core__stringify(n->cond);
if (n->iter) gen(", "); if (n->iter) gen(", ");
core__stringify(n->iter); core__stringify(n->iter);
core__stringify(n->scope); core__stringify(n->scope);
} break; } break;
case AST_IF: { case AST_IF: {
Ast_If *n = (Ast_If *)ast; Ast_If *n = (Ast_If *)ast;
int i = 0; int i = 0;
For(n->ifs) { For(n->ifs) {
if (i == 0) gen("if "); if (i == 0) gen("if ");
else if (it->expr) gen("elif "); else if (it->expr) gen("elif ");
else gen("else "); else gen("else ");
core__stringify(it->expr); core__stringify(it->expr);
if (it->init) gen(", "); if (it->init) gen(", ");
core__stringify(it->init); core__stringify(it->init);
core__stringify(it->scope); core__stringify(it->scope);
i += 1; i += 1;
} }
} break; } break;
case AST_RETURN: { case AST_RETURN: {
Ast_Return *n = (Ast_Return *)ast; Ast_Return *n = (Ast_Return *)ast;
gen("return "); gen("return ");
core__stringify(n->expr); core__stringify(n->expr);
} break; } break;
case AST_LAMBDA_EXPR: { case AST_LAMBDA_EXPR: {
Ast_Lambda *n = (Ast_Lambda *)ast; Ast_Lambda *n = (Ast_Lambda *)ast;
gen("("); gen("(");
For(n->args) { For(n->args) {
core__stringify(it); core__stringify(it);
if (!n->args.is_last(it)) gen(", "); if (!n->args.is_last(it)) gen(", ");
} }
gen(")"); gen(")");
if (n->ret) gen(": "); if (n->ret) gen(": ");
core__stringify(n->ret); core__stringify(n->ret);
core__stringify(n->scope); core__stringify(n->scope);
} break; } break;
default: assert(!"Invalid default case"); default: assert(!"Invalid default case");
} }
} }
String core_stringify(Ast *ast) { String core_stringify(Ast *ast) {
core__stringify(ast); core__stringify(ast);
String result = string_flatten(pctx->perm, &pctx->gen); String result = string_flatten(pctx->perm, &pctx->gen);
pctx->gen.reset(); pctx->gen.reset();
return result; return result;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,71 +1,71 @@
struct Operand { struct Operand {
/*#import meta /*#import meta
meta.inline_value_fields() meta.inline_value_fields()
*/ */
union { union {
Value value; Value value;
struct { struct {
Ast_Type *type; Ast_Type *type;
Ast_Decl *resolved_decl; Ast_Decl *resolved_decl;
union { union {
bool bool_val; bool bool_val;
double f64_val; double f64_val;
Intern_String intern_val; Intern_String intern_val;
BigInt big_int_val; BigInt big_int_val;
Ast_Type *type_val; Ast_Type *type_val;
}; };
}; };
}; };
/*END*/ /*END*/
// is_const is used to rewrite the tree and bound // is_const is used to rewrite the tree and bound
// something to the const name at the end // something to the const name at the end
U8 is_const : 1; U8 is_const : 1;
U8 is_lvalue : 1; U8 is_lvalue : 1;
U8 pound_strict : 1; U8 pound_strict : 1;
}; };
struct Scope_Search { struct Scope_Search {
Array<Ast_Decl *> results; Array<Ast_Decl *> results;
Intern_String name; Intern_String name;
Array<Ast_Scope *> scopes; Array<Ast_Scope *> scopes;
bool exit_on_find; bool exit_on_find;
bool search_only_current_scope; bool search_only_current_scope;
U32 scope_visit_id; U32 scope_visit_id;
}; };
typedef U32 Typecheck_Flag; typedef U32 Typecheck_Flag;
enum { enum {
TYPE_AND_EXPR_REQUIRED = 0, TYPE_AND_EXPR_REQUIRED = 0,
TYPE_CAN_BE_NULL = 1, TYPE_CAN_BE_NULL = 1,
EXPR_CAN_BE_NULL = 2 EXPR_CAN_BE_NULL = 2
}; };
typedef U32 Resolve_Flag; typedef U32 Resolve_Flag;
enum { enum {
AST_CANT_BE_NULL = bit_flag(0), AST_CANT_BE_NULL = bit_flag(0),
AST_CAN_BE_NULL = bit_flag(1), AST_CAN_BE_NULL = bit_flag(1),
RESOLVE_TYPESPEC_COMPLETE = bit_flag(2), RESOLVE_TYPESPEC_COMPLETE = bit_flag(2),
RESOLVE_TYPESPEC = bit_flag(3), RESOLVE_TYPESPEC = bit_flag(3),
}; };
typedef U32 Search_Flag; typedef U32 Search_Flag;
enum { enum {
SEARCH_ONLY_CURRENT_SCOPE = bit_flag(1), SEARCH_ONLY_CURRENT_SCOPE = bit_flag(1),
RESOLVE_NAME_MAKE_SURE_OPERATOR_OVERLOAD_IS_NOT_EVER_CALLED = bit_flag(2), RESOLVE_NAME_MAKE_SURE_OPERATOR_OVERLOAD_IS_NOT_EVER_CALLED = bit_flag(2),
}; };
CORE_Static void try_converting_untyped_to_default_type(Operand *op); CORE_Static void try_converting_untyped_to_default_type(Operand *op);
CORE_Static void try_propagating_resolved_type_to_untyped_literals(Ast *ast, Ast_Type *type, Ast_Type *additional_not_bool_type = 0); CORE_Static void try_propagating_resolved_type_to_untyped_literals(Ast *ast, Ast_Type *type, Ast_Type *additional_not_bool_type = 0);
CORE_Static Operand resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_context, Ast_Scope *field_access_scope); CORE_Static Operand resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_context, Ast_Scope *field_access_scope);
CORE_Static void resolve_decl(Ast_Decl *ast); CORE_Static void resolve_decl(Ast_Decl *ast);
CORE_Static Ast_Decl *resolve_name(Ast_Scope *parent_scope, Token *pos, Intern_String name, Search_Flag search_flags = 0); CORE_Static Ast_Decl *resolve_name(Ast_Scope *parent_scope, Token *pos, Intern_String name, Search_Flag search_flags = 0);
#define CASE(kind, type) \ #define CASE(kind, type) \
case AST_##kind: { \ case AST_##kind: { \
Ast_##type *node = (Ast_##type *)ast; Ast_##type *node = (Ast_##type *)ast;
#define BREAK() \ #define BREAK() \
} \ } \
break break

View File

@@ -1,359 +1,359 @@
CORE_Static const char * CORE_Static const char *
get_name_of_type(Ast_Type *type) { get_name_of_type(Ast_Type *type) {
switch (type->kind) { switch (type->kind) {
case TYPE_VOID: return "void"; case TYPE_VOID: return "void";
case TYPE_BOOL: return "bool"; case TYPE_BOOL: return "bool";
case TYPE_F32: return "F32"; case TYPE_F32: return "F32";
case TYPE_F64: return "F64"; case TYPE_F64: return "F64";
case TYPE_S8: return "S8"; case TYPE_S8: return "S8";
case TYPE_CHAR: return "char"; case TYPE_CHAR: return "char";
case TYPE_UCHAR: return "uchar"; case TYPE_UCHAR: return "uchar";
case TYPE_INT: return "int"; case TYPE_INT: return "int";
case TYPE_UINT: return "uint"; case TYPE_UINT: return "uint";
case TYPE_LONG: return "long"; case TYPE_LONG: return "long";
case TYPE_ULONG: return "ulong"; case TYPE_ULONG: return "ulong";
case TYPE_LLONG: return "llong"; case TYPE_LLONG: return "llong";
case TYPE_ULLONG: return "ullong"; case TYPE_ULLONG: return "ullong";
case TYPE_SHORT: return "short"; case TYPE_SHORT: return "short";
case TYPE_USHORT: return "ushort"; case TYPE_USHORT: return "ushort";
case TYPE_S16: return "S16"; case TYPE_S16: return "S16";
case TYPE_S32: return "S32"; case TYPE_S32: return "S32";
case TYPE_S64: return "S64"; case TYPE_S64: return "S64";
case TYPE_U8: return "U8"; case TYPE_U8: return "U8";
case TYPE_U16: return "U16"; case TYPE_U16: return "U16";
case TYPE_U32: return "U32"; case TYPE_U32: return "U32";
case TYPE_U64: return "U64"; case TYPE_U64: return "U64";
case TYPE_TYPE: case TYPE_TYPE:
return "Type"; return "Type";
case TYPE_POLYMORPH: case TYPE_POLYMORPH:
return "<Polymorph>"; return "<Polymorph>";
invalid_default_case; invalid_default_case;
} }
return "<unknown_type>"; return "<unknown_type>";
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Type constructors and utillities // Type constructors and utillities
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
force_inline B32 is_any(Ast_Type *a) { return a == pctx->type_any; } force_inline B32 is_any(Ast_Type *a) { return a == pctx->type_any; }
force_inline B32 is_struct(Ast_Type *a) { return a->kind == TYPE_STRUCT; } force_inline B32 is_struct(Ast_Type *a) { return a->kind == TYPE_STRUCT; }
force_inline B32 is_union(Ast_Type *a) { return a->kind == TYPE_UNION; } force_inline B32 is_union(Ast_Type *a) { return a->kind == TYPE_UNION; }
force_inline B32 is_struct_union(Ast_Type *a) { return a->kind == TYPE_UNION || a->kind == TYPE_STRUCT; } force_inline B32 is_struct_union(Ast_Type *a) { return a->kind == TYPE_UNION || a->kind == TYPE_STRUCT; }
force_inline B32 is_lambda(Ast_Type *a) { return a->kind == TYPE_LAMBDA; } force_inline B32 is_lambda(Ast_Type *a) { return a->kind == TYPE_LAMBDA; }
force_inline B32 is_array(Ast_Type *a) { return a->kind == TYPE_ARRAY; } force_inline B32 is_array(Ast_Type *a) { return a->kind == TYPE_ARRAY; }
force_inline B32 is_slice(Ast_Type *a) { return a->kind == TYPE_SLICE; } force_inline B32 is_slice(Ast_Type *a) { return a->kind == TYPE_SLICE; }
force_inline B32 is_enum(Ast_Type *a) { return a->kind == TYPE_ENUM; } force_inline B32 is_enum(Ast_Type *a) { return a->kind == TYPE_ENUM; }
force_inline B32 is_pointer(Ast_Type *a) { return a->kind == TYPE_POINTER; } force_inline B32 is_pointer(Ast_Type *a) { return a->kind == TYPE_POINTER; }
force_inline B32 is_void(Ast_Type *a) { return a->kind == TYPE_VOID; } force_inline B32 is_void(Ast_Type *a) { return a->kind == TYPE_VOID; }
force_inline B32 is_void_pointer(Ast_Type *a) { return a == pctx->type_pointer_to_void; } force_inline B32 is_void_pointer(Ast_Type *a) { return a == pctx->type_pointer_to_void; }
force_inline B32 is_string(Ast_Type *a) { return a == pctx->type_string || a->kind == TYPE_UNTYPED_STRING || a == pctx->type_pointer_to_char; } force_inline B32 is_string(Ast_Type *a) { return a == pctx->type_string || a->kind == TYPE_UNTYPED_STRING || a == pctx->type_pointer_to_char; }
force_inline B32 is_untyped_int(Ast_Type *a) { return a->kind == TYPE_UNTYPED_INT; } force_inline B32 is_untyped_int(Ast_Type *a) { return a->kind == TYPE_UNTYPED_INT; }
force_inline B32 is_typed_int(Ast_Type *a) { return (a->kind >= TYPE_S64 && a->kind <= TYPE_U8); } force_inline B32 is_typed_int(Ast_Type *a) { return (a->kind >= TYPE_S64 && a->kind <= TYPE_U8); }
force_inline B32 is_int(Ast_Type *a) { return (a->kind >= TYPE_S64 && a->kind <= TYPE_U8) || a->kind == TYPE_UNTYPED_INT; } force_inline B32 is_int(Ast_Type *a) { return (a->kind >= TYPE_S64 && a->kind <= TYPE_U8) || a->kind == TYPE_UNTYPED_INT; }
force_inline B32 is_signed_int(Ast_Type *a) { return !a->is_unsigned; } force_inline B32 is_signed_int(Ast_Type *a) { return !a->is_unsigned; }
force_inline B32 is_unsigned_int(Ast_Type *a) { return a->is_unsigned; } force_inline B32 is_unsigned_int(Ast_Type *a) { return a->is_unsigned; }
force_inline B32 is_float(Ast_Type *a) { return a->kind == TYPE_F32 || a->kind == TYPE_F64 || a->kind == TYPE_UNTYPED_FLOAT; } force_inline B32 is_float(Ast_Type *a) { return a->kind == TYPE_F32 || a->kind == TYPE_F64 || a->kind == TYPE_UNTYPED_FLOAT; }
force_inline B32 is_f32(Ast_Type *a) { return a->kind == TYPE_F32; } force_inline B32 is_f32(Ast_Type *a) { return a->kind == TYPE_F32; }
force_inline B32 is_f64(Ast_Type *a) { return a->kind == TYPE_F64; } force_inline B32 is_f64(Ast_Type *a) { return a->kind == TYPE_F64; }
force_inline B32 is_bool(Ast_Type *a) { return a->kind == TYPE_BOOL || a->kind == TYPE_UNTYPED_BOOL; } force_inline B32 is_bool(Ast_Type *a) { return a->kind == TYPE_BOOL || a->kind == TYPE_UNTYPED_BOOL; }
force_inline B32 is_untyped(Ast_Type *a) { return a->kind >= TYPE_UNTYPED_FIRST && a->kind <= TYPE_UNTYPED_LAST; } force_inline B32 is_untyped(Ast_Type *a) { return a->kind >= TYPE_UNTYPED_FIRST && a->kind <= TYPE_UNTYPED_LAST; }
force_inline B32 is_typed(Ast_Type *a) { return !is_untyped(a); } force_inline B32 is_typed(Ast_Type *a) { return !is_untyped(a); }
force_inline B32 is_numeric(Ast_Type *type) { force_inline B32 is_numeric(Ast_Type *type) {
return (type->kind >= TYPE_UNTYPED_FIRST_NUMERIC && type->kind <= TYPE_UNTYPED_LAST_NUMERIC) || return (type->kind >= TYPE_UNTYPED_FIRST_NUMERIC && type->kind <= TYPE_UNTYPED_LAST_NUMERIC) ||
(type->kind >= TYPE_FIRST_NUMERIC && type->kind <= TYPE_LAST_NUMERIC); (type->kind >= TYPE_FIRST_NUMERIC && type->kind <= TYPE_LAST_NUMERIC);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Hash consed types // Hash consed types
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
CORE_Static Ast_Type * CORE_Static Ast_Type *
type_new(Allocator *allocator, Ast_Type_Kind kind, int32_t size, int32_t align, bool generate_type_id = true) { type_new(Allocator *allocator, Ast_Type_Kind kind, int32_t size, int32_t align, bool generate_type_id = true) {
Ast_Type *result = allocate_struct(allocator, Ast_Type, true); Ast_Type *result = allocate_struct(allocator, Ast_Type, true);
result->kind = kind; result->kind = kind;
result->size = size; result->size = size;
result->align = align; result->align = align;
if (generate_type_id) result->type_id = pctx->type_ids++; if (generate_type_id) result->type_id = pctx->type_ids++;
add(pctx->perm, &pctx->all_types, result); add(pctx->perm, &pctx->all_types, result);
return result; return result;
} }
CORE_Static Ast_Type * CORE_Static Ast_Type *
type_copy(Allocator *a, Ast_Type *type) { type_copy(Allocator *a, Ast_Type *type) {
// @warning: This changes type id !!!! // @warning: This changes type id !!!!
Ast_Type *result = allocate_struct(a, Ast_Type); Ast_Type *result = allocate_struct(a, Ast_Type);
memory_copy(result, type, sizeof(Ast_Type)); memory_copy(result, type, sizeof(Ast_Type));
result->type_id = pctx->type_ids++; result->type_id = pctx->type_ids++;
add(pctx->perm, &pctx->all_types, result); add(pctx->perm, &pctx->all_types, result);
return result; return result;
} }
CORE_Static Ast_Type * CORE_Static Ast_Type *
type_pointer(Ast_Type *base) { type_pointer(Ast_Type *base) {
Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, (void *)base); Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, (void *)base);
if (!result) { if (!result) {
result = type_new(pctx->perm, TYPE_POINTER, pointer_size, pointer_align); result = type_new(pctx->perm, TYPE_POINTER, pointer_size, pointer_align);
result->base = base; result->base = base;
result->is_unsigned = true; result->is_unsigned = true;
map_insert(&pctx->type_map, base, result); map_insert(&pctx->type_map, base, result);
} }
assert(result->kind == TYPE_POINTER); assert(result->kind == TYPE_POINTER);
return result; return result;
} }
CORE_Static Ast_Type * CORE_Static Ast_Type *
type_slice(Ast_Type *base, Ast *ast) { type_slice(Ast_Type *base, Ast *ast) {
U64 hash_base = hash_ptr(base); U64 hash_base = hash_ptr(base);
U64 hash = hash_mix(hash_base, hash_u64(ARRAY_SIZE_SLICE)); U64 hash = hash_mix(hash_base, hash_u64(ARRAY_SIZE_SLICE));
Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, hash); Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, hash);
if (result) { if (result) {
assert(result->kind == TYPE_SLICE); assert(result->kind == TYPE_SLICE);
assert(result->arr.base == base); assert(result->arr.base == base);
return result; return result;
} }
struct Slice { struct Slice {
void *p; void *p;
S64 len; S64 len;
}; };
result = type_new(pctx->perm, TYPE_SLICE, sizeof(Slice), alignof(Slice)); result = type_new(pctx->perm, TYPE_SLICE, sizeof(Slice), alignof(Slice));
result->arr.base = base; result->arr.base = base;
result->arr.slice_hash = hash; result->arr.slice_hash = hash;
result->ast = ast; result->ast = ast;
map_insert(&pctx->type_map, hash, result); map_insert(&pctx->type_map, hash, result);
return result; return result;
} }
CORE_Static Ast_Type * CORE_Static Ast_Type *
type_array(Ast_Type *base, S32 size) { type_array(Ast_Type *base, S32 size) {
U64 hash_base = hash_ptr(base); U64 hash_base = hash_ptr(base);
U64 hash = hash_mix(hash_base, hash_u64(size)); U64 hash = hash_mix(hash_base, hash_u64(size));
Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, hash); Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, hash);
if (result) { if (result) {
assert(result->kind == TYPE_ARRAY); assert(result->kind == TYPE_ARRAY);
assert(result->arr.size == size); assert(result->arr.size == size);
assert(result->arr.base == base); assert(result->arr.base == base);
return result; return result;
} }
result = type_new(pctx->perm, TYPE_ARRAY, size * base->size, pointer_align); result = type_new(pctx->perm, TYPE_ARRAY, size * base->size, pointer_align);
result->arr.base = base; result->arr.base = base;
result->arr.size = size; result->arr.size = size;
result->arr.slice_hash = hash_mix(hash_base, hash_u64(ARRAY_SIZE_SLICE)); result->arr.slice_hash = hash_mix(hash_base, hash_u64(ARRAY_SIZE_SLICE));
map_insert(&pctx->type_map, hash, result); map_insert(&pctx->type_map, hash, result);
return result; return result;
} }
inline U64 calculate_hash_for_arguments(Ast_Type *a, Ast_Type *b) { inline U64 calculate_hash_for_arguments(Ast_Type *a, Ast_Type *b) {
U64 result = 13; U64 result = 13;
result = hash_mix(result, hash_ptr(a)); result = hash_mix(result, hash_ptr(a));
result = hash_mix(result, hash_ptr(b)); result = hash_mix(result, hash_ptr(b));
return result; return result;
} }
inline U64 calculate_hash_for_arguments(Ast_Type *a) { inline U64 calculate_hash_for_arguments(Ast_Type *a) {
U64 result = 13; U64 result = 13;
result = hash_mix(result, hash_ptr(a)); result = hash_mix(result, hash_ptr(a));
return result; return result;
} }
CORE_Static Ast_Type * CORE_Static Ast_Type *
type_lambda(Ast *ast, Ast_Type *ret, Array<Ast_Type *> args) { type_lambda(Ast *ast, Ast_Type *ret, Array<Ast_Type *> args) {
U64 hash_without_ret = 13; U64 hash_without_ret = 13;
For(args) hash_without_ret = hash_mix(hash_without_ret, hash_ptr(it)); For(args) hash_without_ret = hash_mix(hash_without_ret, hash_ptr(it));
U64 hash = hash_mix(hash_ptr(ret), hash_without_ret); U64 hash = hash_mix(hash_ptr(ret), hash_without_ret);
Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, hash); Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, hash);
if (result) { if (result) {
assert(result->kind == TYPE_LAMBDA); assert(result->kind == TYPE_LAMBDA);
assert(result->func.args.len == args.len); assert(result->func.args.len == args.len);
return result; return result;
} }
result = type_new(pctx->perm, TYPE_LAMBDA, pointer_size, pointer_align); result = type_new(pctx->perm, TYPE_LAMBDA, pointer_size, pointer_align);
result->ast = ast; result->ast = ast;
result->func.ret = ret; result->func.ret = ret;
result->func.args = args.tight_copy(pctx->perm); result->func.args = args.tight_copy(pctx->perm);
result->func.hash_without_ret = hash_without_ret; result->func.hash_without_ret = hash_without_ret;
map_insert(&pctx->type_map, hash, result); map_insert(&pctx->type_map, hash, result);
return result; return result;
} }
CORE_Static Ast_Type * CORE_Static Ast_Type *
type_enum(Ast_Decl *ast, Ast_Type *type) { type_enum(Ast_Decl *ast, Ast_Type *type) {
if (!type) { if (!type) {
type = pctx->type_int; type = pctx->type_int;
} }
Ast_Type *result = type_new(pctx->perm, TYPE_ENUM, type->size, type->align); Ast_Type *result = type_new(pctx->perm, TYPE_ENUM, type->size, type->align);
result->base = type; result->base = type;
result->ast = ast; result->ast = ast;
return result; return result;
} }
CORE_Static Ast_Type * CORE_Static Ast_Type *
type_incomplete(Ast *ast) { type_incomplete(Ast *ast) {
Ast_Type_Kind kind = TYPE_INCOMPLETE; Ast_Type_Kind kind = TYPE_INCOMPLETE;
bool generate_type_id = true; bool generate_type_id = true;
if (is_flag_set(ast->flags, AST_POLYMORPH)) { if (is_flag_set(ast->flags, AST_POLYMORPH)) {
kind = TYPE_POLYMORPH; kind = TYPE_POLYMORPH;
generate_type_id = false; generate_type_id = false;
} }
Ast_Type *result = type_new(pctx->perm, kind, 0, 0, generate_type_id); Ast_Type *result = type_new(pctx->perm, kind, 0, 0, generate_type_id);
result->ast = ast; result->ast = ast;
return result; return result;
} }
CORE_Static void resolve_name_for_global_decl(Ast_Decl *node); CORE_Static void resolve_name_for_global_decl(Ast_Decl *node);
CORE_Static void type_complete(Ast_Type *type); CORE_Static void type_complete(Ast_Type *type);
CORE_Static void CORE_Static void
type_struct_complete(Ast_Type *type, Ast_Decl *node) { type_struct_complete(Ast_Type *type, Ast_Decl *node) {
assert(node->kind == AST_STRUCT || node->kind == AST_UNION); assert(node->kind == AST_STRUCT || node->kind == AST_UNION);
if (is_flag_set(node->flags, AST_COMPILER_BREAKPOINT)) Breakpoint; if (is_flag_set(node->flags, AST_COMPILER_BREAKPOINT)) Breakpoint;
Scoped_Arena scratch(pctx->scratch); Scoped_Arena scratch(pctx->scratch);
if (node->kind == AST_STRUCT) { if (node->kind == AST_STRUCT) {
// First resolve and compute sizes of struct members // First resolve and compute sizes of struct members
// //
Array<Ast_Resolved_Member> members = {scratch.arena}; Array<Ast_Resolved_Member> members = {scratch.arena};
type->kind = TYPE_COMPLETING; type->kind = TYPE_COMPLETING;
S32 members_size = 0; S32 members_size = 0;
For(node->scope->decls) { For(node->scope->decls) {
resolve_decl(it); resolve_decl(it);
assert(it->type->kind != TYPE_INCOMPLETE); assert(it->type->kind != TYPE_INCOMPLETE);
assert(is_pow2(it->type->align)); assert(is_pow2(it->type->align));
Ast_Resolved_Member m = {}; Ast_Resolved_Member m = {};
m.offset = type->size; m.offset = type->size;
members_size += it->type->size; members_size += it->type->size;
type->align = max(type->align, it->type->align); type->align = max(type->align, it->type->align);
type->size = it->type->size + (S32)align_up(type->size, it->type->align); type->size = it->type->size + (S32)align_up(type->size, it->type->align);
m.name = it->name; m.name = it->name;
m.value = it->value; m.value = it->value;
members.add(m); members.add(m);
} }
// //
// Then compute size of struct itself // Then compute size of struct itself
// //
type->size = (S32)align_up(type->size, type->align); type->size = (S32)align_up(type->size, type->align);
type->padding = type->size - members_size; type->padding = type->size - members_size;
type->agg.members = members.tight_copy(pctx->perm); type->agg.members = members.tight_copy(pctx->perm);
type->kind = TYPE_STRUCT; type->kind = TYPE_STRUCT;
} }
else { else {
assert(node->kind == AST_UNION); assert(node->kind == AST_UNION);
// First resolve and compute sizes of union members // First resolve and compute sizes of union members
// //
Array<Ast_Resolved_Member> members = {scratch.arena}; Array<Ast_Resolved_Member> members = {scratch.arena};
type->kind = TYPE_COMPLETING; type->kind = TYPE_COMPLETING;
For(node->scope->decls) { For(node->scope->decls) {
resolve_decl(it); resolve_decl(it);
assert(it->type->kind != TYPE_INCOMPLETE); assert(it->type->kind != TYPE_INCOMPLETE);
assert(is_pow2(it->type->align)); assert(is_pow2(it->type->align));
type->align = max(type->align, it->type->align); type->align = max(type->align, it->type->align);
type->size = max(it->type->size, type->size); type->size = max(it->type->size, type->size);
Ast_Resolved_Member m = {}; Ast_Resolved_Member m = {};
m.name = it->name; m.name = it->name;
m.value = it->value; m.value = it->value;
members.add(m); members.add(m);
} }
// //
// Then compute size of union itself // Then compute size of union itself
// //
type->size = (S32)align_up(type->size, type->align); type->size = (S32)align_up(type->size, type->align);
type->agg.members = members.tight_copy(pctx->perm); type->agg.members = members.tight_copy(pctx->perm);
type->kind = TYPE_UNION; type->kind = TYPE_UNION;
} }
resolve_name_for_global_decl(node); resolve_name_for_global_decl(node);
} }
CORE_Static void CORE_Static void
type_complete(Ast_Type *type) { type_complete(Ast_Type *type) {
if (!type) { if (!type) {
return; return;
} }
if (type->kind == TYPE_COMPLETING) { if (type->kind == TYPE_COMPLETING) {
compiler_error(type->ast->pos, "Cyclic type dependency"); compiler_error(type->ast->pos, "Cyclic type dependency");
} }
else if (type->kind != TYPE_INCOMPLETE) { else if (type->kind != TYPE_INCOMPLETE) {
return; return;
} }
type_struct_complete(type, (Ast_Decl *)type->ast); type_struct_complete(type, (Ast_Decl *)type->ast);
add(pctx->perm, &pctx->ordered_decls, (Ast_Decl *)type->ast); add(pctx->perm, &pctx->ordered_decls, (Ast_Decl *)type->ast);
} }
CORE_Static void CORE_Static void
typename_base(String_Builder *sb, Ast_Type *type) { typename_base(String_Builder *sb, Ast_Type *type) {
switch (type->kind) { switch (type->kind) {
case TYPE_INCOMPLETE: sb->addf("INCOMPLETE"); break; case TYPE_INCOMPLETE: sb->addf("INCOMPLETE"); break;
case TYPE_COMPLETING: sb->addf("COMPLETING"); break; case TYPE_COMPLETING: sb->addf("COMPLETING"); break;
case TYPE_TYPE: sb->addf("TYPE"); break; case TYPE_TYPE: sb->addf("TYPE"); break;
case TYPE_POINTER: case TYPE_POINTER:
sb->addf("*"); sb->addf("*");
typename_base(sb, type->base); typename_base(sb, type->base);
break; break;
case TYPE_LAMBDA: case TYPE_LAMBDA:
sb->addf("("); sb->addf("(");
For(type->func.args) { For(type->func.args) {
typename_base(sb, it); typename_base(sb, it);
if (!type->func.args.is_last(it)) sb->addf(", "); if (!type->func.args.is_last(it)) sb->addf(", ");
} }
sb->addf("):"); sb->addf("):");
typename_base(sb, type->func.ret); typename_base(sb, type->func.ret);
break; break;
case TYPE_ARRAY: case TYPE_ARRAY:
sb->addf("[%d]", (int)type->arr.size); sb->addf("[%d]", (int)type->arr.size);
typename_base(sb, type->arr.base); typename_base(sb, type->arr.base);
break; break;
case TYPE_SLICE: case TYPE_SLICE:
sb->addf("[]"); sb->addf("[]");
typename_base(sb, type->base); typename_base(sb, type->base);
break; break;
case TYPE_UNION: case TYPE_UNION:
case TYPE_STRUCT: case TYPE_STRUCT:
case TYPE_ENUM: { case TYPE_ENUM: {
// @todo direct access // @todo direct access
auto constant = (Ast_Decl *)type->ast; auto constant = (Ast_Decl *)type->ast;
auto name = constant->name; auto name = constant->name;
sb->addf("%Q", name); sb->addf("%Q", name);
break; break;
} }
case TYPE_VARGS: { case TYPE_VARGS: {
sb->addf("..."); sb->addf("...");
} break; } break;
case TYPE_UNTYPED_BOOL: sb->addf("Untyped_Bool"); break; case TYPE_UNTYPED_BOOL: sb->addf("Untyped_Bool"); break;
case TYPE_UNTYPED_INT: sb->addf("Untyped_Int"); break; case TYPE_UNTYPED_INT: sb->addf("Untyped_Int"); break;
case TYPE_UNTYPED_FLOAT: sb->addf("Untyped_Float"); break; case TYPE_UNTYPED_FLOAT: sb->addf("Untyped_Float"); break;
case TYPE_UNTYPED_STRING: sb->addf("Untyped_String"); break; case TYPE_UNTYPED_STRING: sb->addf("Untyped_String"); break;
default: { default: {
sb->addf("%s", get_name_of_type(type)); sb->addf("%s", get_name_of_type(type));
} }
} }
} }
CORE_Static String CORE_Static String
get_typename(Ast_Type *type) { get_typename(Ast_Type *type) {
pctx->helper_builder.addf("["); pctx->helper_builder.addf("[");
typename_base(&pctx->helper_builder, type); typename_base(&pctx->helper_builder, type);
pctx->helper_builder.addf("]"); pctx->helper_builder.addf("]");
String result = string_flatten(pctx->stage_arena, &pctx->helper_builder); String result = string_flatten(pctx->stage_arena, &pctx->helper_builder);
pctx->helper_builder.reset(); pctx->helper_builder.reset();
return result; return result;
} }
CORE_Static String CORE_Static String
typestring(Ast_Type *type) { typestring(Ast_Type *type) {
return get_typename(type); return get_typename(type);
} }

View File

@@ -1,45 +1,45 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Resolved Types // Resolved Types
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#define CASE_SINT \ #define CASE_SINT \
case TYPE_S8: \ case TYPE_S8: \
case TYPE_S16: \ case TYPE_S16: \
case TYPE_S32: \ case TYPE_S32: \
case TYPE_S64: \ case TYPE_S64: \
case TYPE_CHAR: \ case TYPE_CHAR: \
case TYPE_LONG: \ case TYPE_LONG: \
case TYPE_LLONG: \ case TYPE_LLONG: \
case TYPE_SHORT: \ case TYPE_SHORT: \
case TYPE_INT case TYPE_INT
#define CASE_UINT \ #define CASE_UINT \
case TYPE_UINT: \ case TYPE_UINT: \
case TYPE_ULONG: \ case TYPE_ULONG: \
case TYPE_ULLONG: \ case TYPE_ULLONG: \
case TYPE_USHORT: \ case TYPE_USHORT: \
case TYPE_UCHAR: \ case TYPE_UCHAR: \
case TYPE_U8: \ case TYPE_U8: \
case TYPE_U16: \ case TYPE_U16: \
case TYPE_U32: \ case TYPE_U32: \
case TYPE_U64 case TYPE_U64
#define CASE_INT \ #define CASE_INT \
case TYPE_UNTYPED_INT: \ case TYPE_UNTYPED_INT: \
CASE_SINT: \ CASE_SINT: \
CASE_UINT CASE_UINT
#define CASE_BOOL \ #define CASE_BOOL \
case TYPE_UNTYPED_BOOL: \ case TYPE_UNTYPED_BOOL: \
case TYPE_BOOL case TYPE_BOOL
#define CASE_FLOAT \ #define CASE_FLOAT \
case TYPE_UNTYPED_FLOAT: \ case TYPE_UNTYPED_FLOAT: \
case TYPE_F32: \ case TYPE_F32: \
case TYPE_F64 case TYPE_F64
#define CASE_STRING \ #define CASE_STRING \
case TYPE_UNTYPED_STRING: \ case TYPE_UNTYPED_STRING: \
case TYPE_STRUCT: \ case TYPE_STRUCT: \
case TYPE_POINTER case TYPE_POINTER
#define CASE_UNTYPED \ #define CASE_UNTYPED \
case TYPE_UNTYPED_INT: \ case TYPE_UNTYPED_INT: \
case TYPE_UNTYPED_BOOL: \ case TYPE_UNTYPED_BOOL: \
case TYPE_UNTYPED_FLOAT: \ case TYPE_UNTYPED_FLOAT: \
case TYPE_UNTYPED_STRING case TYPE_UNTYPED_STRING
#define ARRAY_SIZE_SLICE (-1) #define ARRAY_SIZE_SLICE (-1)

View File

@@ -1,9 +1,9 @@
const U32 LIST_NO_FLAGS = 0; const U32 LIST_NO_FLAGS = 0;
const U32 LIST_RECURSE_INTO_DIRS = 1; const U32 LIST_RECURSE_INTO_DIRS = 1;
struct OS_File_Info { struct OS_File_Info {
String relative_path; String relative_path;
String absolute_path; String absolute_path;
B32 is_directory; B32 is_directory;
}; };

View File

@@ -1,196 +1,196 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
#include <dirent.h> #include <dirent.h>
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <linux/limits.h> #include <linux/limits.h>
#include <stdio.h> #include <stdio.h>
#define POSIX_PAGE_SIZE 4096 #define POSIX_PAGE_SIZE 4096
CORE_Static B32 CORE_Static B32
os_write_file(String filename, String filecontent) { os_write_file(String filename, String filecontent) {
FILE *f = fopen((const char *)filename.str, "w"); FILE *f = fopen((const char *)filename.str, "w");
if (f) { if (f) {
fwrite(filecontent.str, 1, filecontent.len, f); fwrite(filecontent.str, 1, filecontent.len, f);
fclose(f); fclose(f);
return true; return true;
} }
return false; return false;
} }
CORE_Static String CORE_Static String
os_read_file(Alloator *a, String name) { os_read_file(Alloator *a, String name) {
String result = {0}; String result = {0};
FILE *f = fopen((char *)name.str, "rb"); FILE *f = fopen((char *)name.str, "rb");
if (f) { if (f) {
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
result.len = ftell(f); result.len = ftell(f);
fseek(f, 0, SEEK_SET); fseek(f, 0, SEEK_SET);
result.str = (U8 *)allocate_size(a, result.len + 1, false); result.str = (U8 *)allocate_size(a, result.len + 1, false);
fread(result.str, result.len, 1, f); fread(result.str, result.len, 1, f);
fclose(f); fclose(f);
result.str[result.len] = 0; result.str[result.len] = 0;
} }
return result; return result;
} }
CORE_Static String CORE_Static String
os_get_exe_dir(Allocator *a) { os_get_exe_dir(Allocator *a) {
char buffer[PATH_MAX] = {}; char buffer[PATH_MAX] = {};
if (readlink("/proc/self/exe", buffer, PATH_MAX) == -1) { if (readlink("/proc/self/exe", buffer, PATH_MAX) == -1) {
log_info("Failed to retrieve the path of the executable, the method used is fetching /proc/self/exe, very likely you are using an OS that doesn't follow this convention and as such it is currently not supported"); log_info("Failed to retrieve the path of the executable, the method used is fetching /proc/self/exe, very likely you are using an OS that doesn't follow this convention and as such it is currently not supported");
} }
String exe = string_from_cstring(buffer); String exe = string_from_cstring(buffer);
exe = string_chop_last_slash(exe); exe = string_chop_last_slash(exe);
String result = string_copy(a, exe); String result = string_copy(a, exe);
log_trace("Retrieved executable path %Q", result); log_trace("Retrieved executable path %Q", result);
return result; return result;
} }
CORE_Static String CORE_Static String
os_get_absolute_path(Allocator *a, String path) { os_get_absolute_path(Allocator *a, String path) {
assert(path.str[path.len] == 0); assert(path.str[path.len] == 0);
char buffer[PATH_MAX] = {}; char buffer[PATH_MAX] = {};
realpath((char *)path.str, buffer); realpath((char *)path.str, buffer);
String abs = string_from_cstring(buffer); String abs = string_from_cstring(buffer);
String result = string_copy(a, abs); String result = string_copy(a, abs);
return result; return result;
} }
CORE_Static B32 CORE_Static B32
os_does_file_exist(String path) { os_does_file_exist(String path) {
B32 result = false; B32 result = false;
assert(path.str[path.len] == 0); assert(path.str[path.len] == 0);
if (access((char *)path.str, F_OK) == 0) { if (access((char *)path.str, F_OK) == 0) {
result = true; result = true;
} }
log_trace("Does file exist? %Q %d", path, result); log_trace("Does file exist? %Q %d", path, result);
return result; return result;
} }
CORE_Static String CORE_Static String
os_get_working_dir(Allocator *allocator) { os_get_working_dir(Allocator *allocator) {
char *buffer = allocate_array(allocator, char, PATH_MAX, false); char *buffer = allocate_array(allocator, char, PATH_MAX, false);
char *result = getcwd(buffer, PATH_MAX); char *result = getcwd(buffer, PATH_MAX);
return string_from_cstring(result); return string_from_cstring(result);
} }
CORE_Static Array<OS_File_Info> CORE_Static Array<OS_File_Info>
os_list_dir(Scratch_Arena *scratch, Allocator *a, String dir, U32 flags = LIST_RECURSE_INTO_DIRS) { os_list_dir(Scratch_Arena *scratch, Allocator *a, String dir, U32 flags = LIST_RECURSE_INTO_DIRS) {
Scoped_Arena _scope(scratch); Scoped_Arena _scope(scratch);
Array<String> dirs_to_read = {scratch}; Array<String> dirs_to_read = {scratch};
dirs_to_read.add(dir); dirs_to_read.add(dir);
Array<OS_File_Info> result = {a}; Array<OS_File_Info> result = {a};
for (auto it = dirs_to_read.begin(); it != dirs_to_read.end(); it++) { for (auto it = dirs_to_read.begin(); it != dirs_to_read.end(); it++) {
assert(it->str[it->len] == 0); assert(it->str[it->len] == 0);
dirent *dir; dirent *dir;
DIR *d = opendir((char *)it->str); DIR *d = opendir((char *)it->str);
if (d) { if (d) {
while ((dir = readdir(d)) != NULL) { while ((dir = readdir(d)) != NULL) {
if (dir->d_name[0] == '.') { if (dir->d_name[0] == '.') {
if (dir->d_name[1] == '.') { if (dir->d_name[1] == '.') {
if (dir->d_name[2] == 0) if (dir->d_name[2] == 0)
continue; continue;
} }
if (dir->d_name[1] == 0) if (dir->d_name[1] == 0)
continue; continue;
} }
OS_File_Info entry = {}; OS_File_Info entry = {};
entry.relative_path = string_fmt(a, "%Q/%s", *it, dir->d_name); entry.relative_path = string_fmt(a, "%Q/%s", *it, dir->d_name);
entry.absolute_path = os_get_absolute_path(a, entry.relative_path); entry.absolute_path = os_get_absolute_path(a, entry.relative_path);
if (dir->d_type == DT_DIR) { if (dir->d_type == DT_DIR) {
entry.is_directory = true; entry.is_directory = true;
if (flags & LIST_RECURSE_INTO_DIRS) { if (flags & LIST_RECURSE_INTO_DIRS) {
dirs_to_read.add(entry.absolute_path); dirs_to_read.add(entry.absolute_path);
} }
} }
result.add(entry); result.add(entry);
log_trace("%Q %d", entry.absolute_path, entry.is_directory); log_trace("%Q %d", entry.absolute_path, entry.is_directory);
} }
closedir(d); closedir(d);
} }
else { else {
log_info("ERROR Failed to read dir: %Q, errno: %s", *it, strerror(errno)); log_info("ERROR Failed to read dir: %Q, errno: %s", *it, strerror(errno));
} }
} }
return result; return result;
} }
CORE_Static U8 * CORE_Static U8 *
os_advance_commit(OS_Memory *m, size_t *commit_size, size_t page_size) { os_advance_commit(OS_Memory *m, size_t *commit_size, size_t page_size) {
size_t aligned_up_commit = align_up(*commit_size, page_size); size_t aligned_up_commit = align_up(*commit_size, page_size);
size_t to_be_total_commited_size = aligned_up_commit + m->commit; size_t to_be_total_commited_size = aligned_up_commit + m->commit;
size_t to_be_total_commited_size_clamped_to_reserve = clamp_top(to_be_total_commited_size, m->reserve); size_t to_be_total_commited_size_clamped_to_reserve = clamp_top(to_be_total_commited_size, m->reserve);
size_t adjusted_to_boundary_commit = to_be_total_commited_size_clamped_to_reserve - m->commit; size_t adjusted_to_boundary_commit = to_be_total_commited_size_clamped_to_reserve - m->commit;
assert_message(adjusted_to_boundary_commit, "Debug WIN32 Error: Reached the virtual memory reserved boundary"); assert_message(adjusted_to_boundary_commit, "Debug WIN32 Error: Reached the virtual memory reserved boundary");
U8 *result = m->data + m->commit; U8 *result = m->data + m->commit;
if (adjusted_to_boundary_commit == 0) if (adjusted_to_boundary_commit == 0)
result = 0; result = 0;
*commit_size = adjusted_to_boundary_commit; *commit_size = adjusted_to_boundary_commit;
return result; return result;
} }
CORE_Static OS_Memory CORE_Static OS_Memory
os_reserve(size_t size) { os_reserve(size_t size) {
OS_Memory result = {}; OS_Memory result = {};
size_t size_aligned = align_up(size, POSIX_PAGE_SIZE); size_t size_aligned = align_up(size, POSIX_PAGE_SIZE);
result.data = (U8 *)mmap(0, size_aligned, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); result.data = (U8 *)mmap(0, size_aligned, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
assert_message(result.data, POSIX_ERROR "Failed to reserve memory using mmap!!"); assert_message(result.data, POSIX_ERROR "Failed to reserve memory using mmap!!");
if (result.data) { if (result.data) {
result.reserve = size_aligned; result.reserve = size_aligned;
} }
return result; return result;
} }
CORE_Static B32 CORE_Static B32
os_commit(OS_Memory *m, size_t commit) { os_commit(OS_Memory *m, size_t commit) {
B32 result = false; B32 result = false;
U8 *pointer = os_advance_commit(m, &commit, POSIX_PAGE_SIZE); U8 *pointer = os_advance_commit(m, &commit, POSIX_PAGE_SIZE);
if (pointer) { if (pointer) {
int mprotect_result = mprotect(pointer, commit, PROT_READ | PROT_WRITE); int mprotect_result = mprotect(pointer, commit, PROT_READ | PROT_WRITE);
assert_message(mprotect_result == 0, "OS1 POSIX Debug Error: Failed to commit more memory using mmap"); assert_message(mprotect_result == 0, "OS1 POSIX Debug Error: Failed to commit more memory using mmap");
if (mprotect_result == 0) { if (mprotect_result == 0) {
m->commit += commit; m->commit += commit;
result = true; result = true;
} }
} }
return result; return result;
} }
CORE_Static void CORE_Static void
os_release(OS_Memory *m) { os_release(OS_Memory *m) {
int result = munmap(m->data, m->reserve); int result = munmap(m->data, m->reserve);
assert_message(result == 0, "OS1 POSIX Debug Error: Failed to release virtual memory using munmap"); assert_message(result == 0, "OS1 POSIX Debug Error: Failed to release virtual memory using munmap");
if (result == 0) { if (result == 0) {
memory_zero(m, sizeof(*m)); memory_zero(m, sizeof(*m));
} }
} }
CORE_Static U64 CORE_Static U64
os_get_microseconds() { os_get_microseconds() {
timespec ts; timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts); clock_gettime(CLOCK_MONOTONIC, &ts);
U64 result = (((U64)ts.tv_sec) * 1000000ull) + ((U64)ts.tv_nsec) / 1000ull; U64 result = (((U64)ts.tv_sec) * 1000000ull) + ((U64)ts.tv_nsec) / 1000ull;
return result; return result;
} }
CORE_Static F64 CORE_Static F64
os_time() { os_time() {
F64 time = (F64)os_get_microseconds(); F64 time = (F64)os_get_microseconds();
F64 result = time / 1000000.0; // Microseconds to seconds F64 result = time / 1000000.0; // Microseconds to seconds
return result; return result;
} }
bool os_enable_console_colors() { return true; } bool os_enable_console_colors() { return true; }

View File

@@ -1,242 +1,242 @@
#include <stdio.h> #include <stdio.h>
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Memory // Memory
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
const size_t os_page_size = 4096; const size_t os_page_size = 4096;
CORE_Static OS_Memory CORE_Static OS_Memory
os_reserve(size_t size) { os_reserve(size_t size) {
OS_Memory result = {}; OS_Memory result = {};
size_t adjusted_size = align_up(size, os_page_size); size_t adjusted_size = align_up(size, os_page_size);
result.data = (U8 *)VirtualAlloc(0, adjusted_size, MEM_RESERVE, PAGE_READWRITE); result.data = (U8 *)VirtualAlloc(0, adjusted_size, MEM_RESERVE, PAGE_READWRITE);
assert_message(result.data, "Failed to reserve virtual memory"); assert_message(result.data, "Failed to reserve virtual memory");
result.reserve = adjusted_size; result.reserve = adjusted_size;
return result; return result;
} }
CORE_Static B32 CORE_Static B32
os_commit(OS_Memory *m, size_t size) { os_commit(OS_Memory *m, size_t size) {
size_t commit = align_up(size, os_page_size); size_t commit = align_up(size, os_page_size);
size_t total_commit = m->commit + commit; size_t total_commit = m->commit + commit;
total_commit = clamp_top(total_commit, m->reserve); total_commit = clamp_top(total_commit, m->reserve);
size_t adjusted_commit = total_commit - m->commit; size_t adjusted_commit = total_commit - m->commit;
if (adjusted_commit != 0) { if (adjusted_commit != 0) {
void *result = VirtualAlloc((U8 *)m->data + m->commit, adjusted_commit, MEM_COMMIT, PAGE_READWRITE); void *result = VirtualAlloc((U8 *)m->data + m->commit, adjusted_commit, MEM_COMMIT, PAGE_READWRITE);
assert_message(result, "Failed to commit more memory"); assert_message(result, "Failed to commit more memory");
m->commit += adjusted_commit; m->commit += adjusted_commit;
return true; return true;
} }
return false; return false;
} }
CORE_Static void CORE_Static void
os_release(OS_Memory *m) { os_release(OS_Memory *m) {
BOOL result = VirtualFree(m->data, 0, MEM_RELEASE); BOOL result = VirtualFree(m->data, 0, MEM_RELEASE);
assert_message(result != 0, "Failed to release OS_Memory"); assert_message(result != 0, "Failed to release OS_Memory");
if (result) { if (result) {
m->data = 0; m->data = 0;
m->commit = 0; m->commit = 0;
m->reserve = 0; m->reserve = 0;
} }
} }
CORE_Static B32 CORE_Static B32
os_decommit_pos(OS_Memory *m, size_t pos) { os_decommit_pos(OS_Memory *m, size_t pos) {
size_t aligned = align_down(pos, os_page_size); size_t aligned = align_down(pos, os_page_size);
size_t adjusted_pos = clamp_top(aligned, m->commit); size_t adjusted_pos = clamp_top(aligned, m->commit);
size_t size_to_decommit = m->commit - adjusted_pos; size_t size_to_decommit = m->commit - adjusted_pos;
if (size_to_decommit) { if (size_to_decommit) {
U8 *base_address = m->data + adjusted_pos; U8 *base_address = m->data + adjusted_pos;
BOOL result = VirtualFree(base_address, size_to_decommit, MEM_DECOMMIT); BOOL result = VirtualFree(base_address, size_to_decommit, MEM_DECOMMIT);
if (result) { if (result) {
m->commit -= size_to_decommit; m->commit -= size_to_decommit;
return true; return true;
} }
} }
return false; return false;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Time // Time
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
global S64 Global_counts_per_second; global S64 Global_counts_per_second;
api F64 os_time() { api F64 os_time() {
if (Global_counts_per_second == 0) { if (Global_counts_per_second == 0) {
LARGE_INTEGER freq; LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq); QueryPerformanceFrequency(&freq);
Global_counts_per_second = freq.QuadPart; Global_counts_per_second = freq.QuadPart;
} }
LARGE_INTEGER time; LARGE_INTEGER time;
QueryPerformanceCounter(&time); QueryPerformanceCounter(&time);
F64 result = (F64)time.QuadPart / (F64)Global_counts_per_second; F64 result = (F64)time.QuadPart / (F64)Global_counts_per_second;
return result; return result;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Filesystem // Filesystem
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
CORE_Static B32 CORE_Static B32
os_write_file(String filename, String filecontent) { os_write_file(String filename, String filecontent) {
FILE *f = fopen((const char *)filename.str, "w"); FILE *f = fopen((const char *)filename.str, "w");
if (f) { if (f) {
fwrite(filecontent.str, 1, filecontent.len, f); fwrite(filecontent.str, 1, filecontent.len, f);
fclose(f); fclose(f);
return true; return true;
} }
return false; return false;
} }
CORE_Static String CORE_Static String
os_read_file(Allocator *a, String name) { os_read_file(Allocator *a, String name) {
String result = {0}; String result = {0};
FILE *f = fopen((char *)name.str, "rb"); FILE *f = fopen((char *)name.str, "rb");
if (f) { if (f) {
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
result.len = ftell(f); result.len = ftell(f);
fseek(f, 0, SEEK_SET); fseek(f, 0, SEEK_SET);
result.str = (U8 *)allocate_size(a, result.len + 1, false); result.str = (U8 *)allocate_size(a, result.len + 1, false);
fread(result.str, result.len, 1, f); fread(result.str, result.len, 1, f);
fclose(f); fclose(f);
result.str[result.len] = 0; result.str[result.len] = 0;
} }
return result; return result;
} }
CORE_Static String CORE_Static String
os_get_working_dir(Allocator *a) { os_get_working_dir(Allocator *a) {
wchar_t buffer[2048]; wchar_t buffer[2048];
DWORD written = GetCurrentDirectoryW(2048, buffer); DWORD written = GetCurrentDirectoryW(2048, buffer);
assert(written != 0); assert(written != 0);
String16 string16 = string16_from_widechar(buffer); String16 string16 = string16_from_widechar(buffer);
String result = string16_to_string8(a, string16); String result = string16_to_string8(a, string16);
string_path_normalize(result); string_path_normalize(result);
return result; return result;
} }
CORE_Static String CORE_Static String
os_get_exe_dir(Allocator *a) { os_get_exe_dir(Allocator *a) {
wchar_t buffer[2048]; wchar_t buffer[2048];
DWORD written = GetModuleFileNameW(0, buffer, 2048); DWORD written = GetModuleFileNameW(0, buffer, 2048);
assert(written != 0); assert(written != 0);
String16 string16 = string16_from_widechar(buffer); String16 string16 = string16_from_widechar(buffer);
String result = string16_to_string8(a, string16); String result = string16_to_string8(a, string16);
string_path_normalize(result); string_path_normalize(result);
result = string_chop_last_slash(result); result = string_chop_last_slash(result);
if (string16.len > result.len) result.str[result.len] = 0; if (string16.len > result.len) result.str[result.len] = 0;
string_path_normalize(result); string_path_normalize(result);
return result; return result;
} }
CORE_Static String CORE_Static String
os_get_absolute_path(Allocator *a, String path) { os_get_absolute_path(Allocator *a, String path) {
char buff[2048]; char buff[2048];
Arena scratch = arena_from_buffer(buff, 2048); Arena scratch = arena_from_buffer(buff, 2048);
String16 path16 = string8_to_string16(&scratch, path); String16 path16 = string8_to_string16(&scratch, path);
wchar_t *buffer = allocate_array(&scratch, wchar_t, 512); wchar_t *buffer = allocate_array(&scratch, wchar_t, 512);
DWORD written = GetFullPathNameW((wchar_t *)path16.str, 512, buffer, 0); DWORD written = GetFullPathNameW((wchar_t *)path16.str, 512, buffer, 0);
if (written == 0) return {}; if (written == 0) return {};
String16 absolute16 = string16_from_widechar(buffer); String16 absolute16 = string16_from_widechar(buffer);
String absolute = string16_to_string8(a, absolute16); String absolute = string16_to_string8(a, absolute16);
string_path_normalize(absolute); string_path_normalize(absolute);
return absolute; return absolute;
} }
CORE_Static B32 CORE_Static B32
os_does_file_exist(String path) { os_does_file_exist(String path) {
char buff[2048]; char buff[2048];
Arena scratch = arena_from_buffer(buff, buff_cap(buff)); Arena scratch = arena_from_buffer(buff, buff_cap(buff));
String16 path16 = string8_to_string16(&scratch, path); String16 path16 = string8_to_string16(&scratch, path);
DWORD attribs = GetFileAttributesW((wchar_t *)path16.str); DWORD attribs = GetFileAttributesW((wchar_t *)path16.str);
B32 result = attribs == INVALID_FILE_ATTRIBUTES ? false : true; B32 result = attribs == INVALID_FILE_ATTRIBUTES ? false : true;
return result; return result;
} }
CORE_Static Array<OS_File_Info> CORE_Static Array<OS_File_Info>
os_list_dir(Arena *scratch, Allocator *a, String dir, U32 flags = LIST_NO_FLAGS) { os_list_dir(Arena *scratch, Allocator *a, String dir, U32 flags = LIST_NO_FLAGS) {
Scoped_Arena _scope(scratch); Scoped_Arena _scope(scratch);
Array<String> dirs_to_read = {scratch}; Array<String> dirs_to_read = {scratch};
dirs_to_read.add(dir); dirs_to_read.add(dir);
Array<OS_File_Info> result = {a}; Array<OS_File_Info> result = {a};
for (auto it = dirs_to_read.begin(); it != dirs_to_read.end(); it++) { for (auto it = dirs_to_read.begin(); it != dirs_to_read.end(); it++) {
String modified_path = string_fmt(scratch, "%Q\\*", it); String modified_path = string_fmt(scratch, "%Q\\*", it);
String16 path16 = string8_to_string16(scratch, modified_path); String16 path16 = string8_to_string16(scratch, modified_path);
WIN32_FIND_DATAW ffd; WIN32_FIND_DATAW ffd;
HANDLE handle = FindFirstFileW((wchar_t *)path16.str, &ffd); HANDLE handle = FindFirstFileW((wchar_t *)path16.str, &ffd);
if (handle == INVALID_HANDLE_VALUE) continue; if (handle == INVALID_HANDLE_VALUE) continue;
do { do {
// //
// Skip '.' and '..' // Skip '.' and '..'
// //
if (ffd.cFileName[0] == '.') { if (ffd.cFileName[0] == '.') {
if (ffd.cFileName[1] == '.') { if (ffd.cFileName[1] == '.') {
if (ffd.cFileName[2] == 0) if (ffd.cFileName[2] == 0)
continue; continue;
} }
if (ffd.cFileName[1] == 0) if (ffd.cFileName[1] == 0)
continue; continue;
} }
String16 filename16 = string16_from_widechar(ffd.cFileName); String16 filename16 = string16_from_widechar(ffd.cFileName);
String filename = string16_to_string8(scratch, filename16); String filename = string16_to_string8(scratch, filename16);
String full_file_path = string_fmt(a, "%Q/%Q", dir, filename); String full_file_path = string_fmt(a, "%Q/%Q", dir, filename);
OS_File_Info listing = {full_file_path, os_get_absolute_path(a, full_file_path)}; OS_File_Info listing = {full_file_path, os_get_absolute_path(a, full_file_path)};
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
listing.is_directory = true; listing.is_directory = true;
if (flags & LIST_RECURSE_INTO_DIRS) { if (flags & LIST_RECURSE_INTO_DIRS) {
dirs_to_read.add(full_file_path); dirs_to_read.add(full_file_path);
} }
} }
result.add(listing); result.add(listing);
} while (FindNextFileW(handle, &ffd) != 0); } while (FindNextFileW(handle, &ffd) != 0);
DWORD error = GetLastError(); DWORD error = GetLastError();
if (error != ERROR_NO_MORE_FILES) { if (error != ERROR_NO_MORE_FILES) {
// Not sure what to do here hmmm // Not sure what to do here hmmm
} }
FindClose(handle); FindClose(handle);
} }
return result; return result;
} }
bool GLOBAL_EnabledConsoleColors; bool GLOBAL_EnabledConsoleColors;
bool os_enable_console_colors() { bool os_enable_console_colors() {
// Set output mode to handle virtual terminal sequences // Set output mode to handle virtual terminal sequences
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hOut != INVALID_HANDLE_VALUE) { if (hOut != INVALID_HANDLE_VALUE) {
DWORD dwMode = 0; DWORD dwMode = 0;
if (GetConsoleMode(hOut, &dwMode)) { if (GetConsoleMode(hOut, &dwMode)) {
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if (SetConsoleMode(hOut, dwMode)) { if (SetConsoleMode(hOut, dwMode)) {
GLOBAL_EnabledConsoleColors = true; GLOBAL_EnabledConsoleColors = true;
return true; return true;
} }
else { else {
printf("Failed to enable colored terminal output C\n"); printf("Failed to enable colored terminal output C\n");
} }
} }
else { else {
printf("Failed to enable colored terminal output B\n"); printf("Failed to enable colored terminal output B\n");
} }
} }
else { else {
printf("Failed to enable colored terminal output A\n"); printf("Failed to enable colored terminal output A\n");
} }
return false; return false;
} }

View File

@@ -1,4 +1,4 @@
@echo off @echo off
call meta_run.bat preprocess cpp call meta_run.bat preprocess cpp
clang-format -i *.cpp *.hpp *.h clang-format -i *.cpp *.hpp *.h

View File

@@ -1,159 +1,159 @@
import re import re
snake_case_pattern = re.compile(r'(?<!^)(?=[A-Z])') snake_case_pattern = re.compile(r'(?<!^)(?=[A-Z])')
def pascal_to_snake(v): def pascal_to_snake(v):
name = snake_case_pattern.sub('_', v).lower() name = snake_case_pattern.sub('_', v).lower()
return name return name
BINARY_EXPR = 1 BINARY_EXPR = 1
UNARY_EXPR = 2 UNARY_EXPR = 2
token_simple_expr = [ token_simple_expr = [
["Mul", "*", BINARY_EXPR], ["Mul", "*", BINARY_EXPR],
["Div", "/", BINARY_EXPR], ["Div", "/", BINARY_EXPR],
["Mod", "%", BINARY_EXPR], ["Mod", "%", BINARY_EXPR],
["LeftShift", "<<", BINARY_EXPR], ["LeftShift", "<<", BINARY_EXPR],
["RightShift", ">>", BINARY_EXPR], ["RightShift", ">>", BINARY_EXPR],
["FirstMul = TK_Mul", "SPECIAL"], ["FirstMul = TK_Mul", "SPECIAL"],
["LastMul = TK_RightShift", "SPECIAL"], ["LastMul = TK_RightShift", "SPECIAL"],
["Add", "+", BINARY_EXPR | UNARY_EXPR], ["Add", "+", BINARY_EXPR | UNARY_EXPR],
["Sub", "-", BINARY_EXPR | UNARY_EXPR], ["Sub", "-", BINARY_EXPR | UNARY_EXPR],
["FirstAdd = TK_Add", "SPECIAL"], ["FirstAdd = TK_Add", "SPECIAL"],
["LastAdd = TK_Sub", "SPECIAL"], ["LastAdd = TK_Sub", "SPECIAL"],
["Equals", "==", BINARY_EXPR], ["Equals", "==", BINARY_EXPR],
["LesserThenOrEqual", "<=", BINARY_EXPR], ["LesserThenOrEqual", "<=", BINARY_EXPR],
["GreaterThenOrEqual", ">=", BINARY_EXPR], ["GreaterThenOrEqual", ">=", BINARY_EXPR],
["LesserThen", "<", BINARY_EXPR], ["LesserThen", "<", BINARY_EXPR],
["GreaterThen", ">", BINARY_EXPR], ["GreaterThen", ">", BINARY_EXPR],
["NotEquals", "!=", BINARY_EXPR], ["NotEquals", "!=", BINARY_EXPR],
["FirstCompare = TK_Equals", "SPECIAL"], ["FirstCompare = TK_Equals", "SPECIAL"],
["LastCompare = TK_NotEquals", "SPECIAL"], ["LastCompare = TK_NotEquals", "SPECIAL"],
["BitAnd", "&", BINARY_EXPR], ["BitAnd", "&", BINARY_EXPR],
["BitOr", "|", BINARY_EXPR], ["BitOr", "|", BINARY_EXPR],
["BitXor", "^", BINARY_EXPR], ["BitXor", "^", BINARY_EXPR],
["And", "&&", BINARY_EXPR], ["And", "&&", BINARY_EXPR],
["Or", "||", BINARY_EXPR], ["Or", "||", BINARY_EXPR],
["FirstLogical = TK_BitAnd", "SPECIAL"], ["FirstLogical = TK_BitAnd", "SPECIAL"],
["LastLogical = TK_Or", "SPECIAL"], ["LastLogical = TK_Or", "SPECIAL"],
["Neg", "~", UNARY_EXPR], ["Neg", "~", UNARY_EXPR],
["Not", "!", UNARY_EXPR], ["Not", "!", UNARY_EXPR],
] ]
token_inc_expr = [ token_inc_expr = [
["Decrement", "--", UNARY_EXPR], ["Decrement", "--", UNARY_EXPR],
["Increment", "++", UNARY_EXPR], ["Increment", "++", UNARY_EXPR],
["PostDecrement", "--", UNARY_EXPR], ["PostDecrement", "--", UNARY_EXPR],
["PostIncrement", "++", UNARY_EXPR], ["PostIncrement", "++", UNARY_EXPR],
] ]
token_assign_expr = [ token_assign_expr = [
["Assign", "="], ["Assign", "="],
["ColonAssign", ":="], ["ColonAssign", ":="],
["DivAssign", "/="], ["DivAssign", "/="],
["MulAssign", "*="], ["MulAssign", "*="],
["ModAssign", "%="], ["ModAssign", "%="],
["SubAssign", "-="], ["SubAssign", "-="],
["AddAssign", "+="], ["AddAssign", "+="],
["AndAssign", "&="], ["AndAssign", "&="],
["OrAssign", "|="], ["OrAssign", "|="],
["XorAssign", "^="], ["XorAssign", "^="],
["LeftShiftAssign", "<<="], ["LeftShiftAssign", "<<="],
["RightShiftAssign", ">>="], ["RightShiftAssign", ">>="],
["FirstAssign = TK_Assign", "SPECIAL"], ["FirstAssign = TK_Assign", "SPECIAL"],
["LastAssign = TK_RightShiftAssign", "SPECIAL"], ["LastAssign = TK_RightShiftAssign", "SPECIAL"],
] ]
token_rest = [ token_rest = [
["OpenParen", "("], ["OpenParen", "("],
["CloseParen", ")"], ["CloseParen", ")"],
["OpenBrace", "{"], ["OpenBrace", "{"],
["CloseBrace", "}"], ["CloseBrace", "}"],
["OpenBracket", "["], ["OpenBracket", "["],
["CloseBracket", "]"], ["CloseBracket", "]"],
["Comma", ","], ["Comma", ","],
["Pound", "#"], ["Pound", "#"],
["Question", "?"], ["Question", "?"],
["ThreeDots", "..."], ["ThreeDots", "..."],
["Semicolon", ";"], ["Semicolon", ";"],
["Dot", "."], ["Dot", "."],
["TwoDots", ".."], ["TwoDots", ".."],
["NewLine", "[NewLine]"], ["NewLine", "[NewLine]"],
["Colon", ":"], ["Colon", ":"],
["DoubleColon", "::"], ["DoubleColon", "::"],
["At", "@"], ["At", "@"],
["Arrow", "->"], ["Arrow", "->"],
["Polymorph", "$"], ["Polymorph", "$"],
["ExprSizeof", "[sizeof]"], ["ExprSizeof", "[sizeof]"],
["DocComment", "[///]"], ["DocComment", "[///]"],
["Comment", "//"], ["Comment", "//"],
["Identifier", "[Ident]"], ["Identifier", "[Ident]"],
["UnicodeLit", "[Unicode]"], ["UnicodeLit", "[Unicode]"],
["StringLit", "[String]"], ["StringLit", "[String]"],
["Error", "[Error]"], ["Error", "[Error]"],
["Float", "[Float]"], ["Float", "[Float]"],
["Integer", "[Int]"], ["Integer", "[Int]"],
["Keyword", "[Keyword]"], ["Keyword", "[Keyword]"],
] ]
token_kinds = token_simple_expr + token_inc_expr + token_assign_expr + token_rest token_kinds = token_simple_expr + token_inc_expr + token_assign_expr + token_rest
keywords = [ keywords = [
"struct", "struct",
"union", "union",
"true", "true",
"default", "default",
"continue", "continue",
"break", "break",
"false", "false",
"return", "return",
"switch", "switch",
"Assert", "Assert",
"if", "if",
"elif", "elif",
"pass", "pass",
"else", "else",
"for", "for",
"enum", "enum",
"goto", "goto",
"defer", "defer",
] ]
interns = [ interns = [
"typeof", "typeof",
"sizeof", "sizeof",
"Len", "Len",
"alignof", "alignof",
"foreign", "foreign",
"strict", "strict",
"void", "void",
"flag", "flag",
"it", "it",
"load", "load",
"import", "import",
"link", "link",
"compiler_breakpoint", "compiler_breakpoint",
] ]
value_struct_content = """ value_struct_content = """
Ast_Type *type; Ast_Type *type;
Ast_Decl *resolved_decl; Ast_Decl *resolved_decl;
union { union {
bool bool_val; bool bool_val;
double f64_val; double f64_val;
Intern_String intern_val; Intern_String intern_val;
BigInt big_int_val; BigInt big_int_val;
Ast_Type *type_val; Ast_Type *type_val;
}; };
""".strip() """.strip()
def inline_value_fields(): def inline_value_fields():
print(f""" print(f"""
union {{ union {{
Value value; Value value;
struct {{ struct {{
{value_struct_content} {value_struct_content}
}}; }};
}}; }};
""".strip()) """.strip())

View File

@@ -1,65 +1,65 @@
import subprocess import subprocess
import sys import sys
import os import os
files = os.listdir(".") files = os.listdir(".")
files = [i for i in files if (i.endswith(".cpp") or i.endswith(".h")) and i != "test.cpp"] files = [i for i in files if (i.endswith(".cpp") or i.endswith(".h")) and i != "test.cpp"]
for file_to_modify in files: for file_to_modify in files:
print(file_to_modify) print(file_to_modify)
fd = open(file_to_modify, "r+") fd = open(file_to_modify, "r+")
f = fd.read() f = fd.read()
END = "/*END*/" END = "/*END*/"
START = "/*#" START = "/*#"
STOP = "*/" STOP = "*/"
program_counter = 0 program_counter = 0
valid = True valid = True
index = 0 index = 0
while True: while True:
begin = f.find(START, index) begin = f.find(START, index)
if begin == -1: if begin == -1:
break break
index = begin index = begin
begin += 3 begin += 3
end = f.find(STOP, index) end = f.find(STOP, index)
if end == -1: if end == -1:
valid = False valid = False
print(f"One of the registered comments inside {file_to_modify} doesn't have an end") print(f"One of the registered comments inside {file_to_modify} doesn't have an end")
break break
gen_end = f.find(END, end) gen_end = f.find(END, end)
next_block = f.find(START, end) next_block = f.find(START, end)
if next_block != -1 and gen_end > next_block: if next_block != -1 and gen_end > next_block:
gen_end = -1 gen_end = -1
before = f[:begin] before = f[:begin]
program = f[begin:end] program = f[begin:end]
if gen_end == -1: if gen_end == -1:
after = f[end+2:] after = f[end+2:]
else: else:
after = f[gen_end+len(END):] after = f[gen_end+len(END):]
temp_filename = "_metaprogram" + str(program_counter) + ".py" temp_filename = "_metaprogram" + str(program_counter) + ".py"
if os.path.isfile(temp_filename): if os.path.isfile(temp_filename):
print(temp_filename + " exists, dont want to risk overwriting something important") print(temp_filename + " exists, dont want to risk overwriting something important")
valid = False valid = False
break break
program_counter += 1 program_counter += 1
with open(temp_filename, "w") as meta_file: with open(temp_filename, "w") as meta_file:
meta_file.write(program) meta_file.write(program)
result = subprocess.run([sys.executable, temp_filename], stdout=subprocess.PIPE) result = subprocess.run([sys.executable, temp_filename], stdout=subprocess.PIPE)
program_result = result.stdout.decode('utf-8').replace('\r\n', '\n') + END program_result = result.stdout.decode('utf-8').replace('\r\n', '\n') + END
f = before + program + "*/\n" + program_result + after f = before + program + "*/\n" + program_result + after
os.remove(temp_filename) os.remove(temp_filename)
index = end index = end
if valid: if valid:
fd.seek(0) fd.seek(0)
fd.write(f) fd.write(f)
fd.truncate() fd.truncate()
fd.close() fd.close()