Refresh the repo
This commit is contained in:
44
.gitignore
vendored
44
.gitignore
vendored
@@ -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
226
README.md
@@ -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
|
||||||
|
|||||||
24
build.bat
24
build.bat
@@ -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 ..\..
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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)
|
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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)
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
1
examples/pathfind_visualizer
Submodule
1
examples/pathfind_visualizer
Submodule
Submodule examples/pathfind_visualizer added at caff4aaa2e
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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")
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
*/
|
*/
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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}
|
||||||
@@ -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
|
||||||
@@ -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"
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
@@ -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
306
src/base/array.hpp
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -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)
|
||||||
@@ -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; }
|
||||||
|
};
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
@@ -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
21
src/base/defer.hpp
Normal 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
131
src/base/linked_list.h
Normal 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
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
@@ -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"
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -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*/
|
||||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
@@ -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)
|
||||||
@@ -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;
|
||||||
};
|
};
|
||||||
@@ -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; }
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
@@ -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())
|
||||||
@@ -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()
|
||||||
|
|
||||||
Reference in New Issue
Block a user