Previously it wasnt working but now its working, TRUST ME
This commit is contained in:
293
build/examples/_demo1.core
Normal file
293
build/examples/_demo1.core
Normal file
@@ -0,0 +1,293 @@
|
||||
/* 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://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.
|
||||
* 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/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://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
|
||||
//
|
||||
// * Inspired by: Per Vognsen(Ion), Jonathan Blow(Jai)
|
||||
// * Standard programming constructs
|
||||
// * No forward declarations needed
|
||||
// * Named function arguments
|
||||
// * Enum values are nicely namespaced
|
||||
#import "Multimedia.core"
|
||||
|
||||
main :: (): int
|
||||
StartMultimedia(title = "Hello people!")
|
||||
DrawYellowFill()
|
||||
DrawCoolGradient()
|
||||
DrawCircleWithGradient()
|
||||
AnimateTransmorphingCircle()
|
||||
RaymarchSphere()
|
||||
|
||||
DrawYellowFill :: ()
|
||||
for y := 0, y < Mu.window.y, y+=1
|
||||
for x := 0, x < Mu.window.x, x+=1
|
||||
Mu.screen[x + y*Mu.window.x] = 0xFFFFFF00
|
||||
|
||||
for UpdateMultimedia()
|
||||
if Mu.key[Key.Escape].down
|
||||
Mu.key[Key.Escape].down = false
|
||||
break
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// #2
|
||||
//
|
||||
// * Modules
|
||||
// * User names the imports
|
||||
// * Aliasing
|
||||
// * Operator overloads
|
||||
F :: #import "MathF32.core"
|
||||
V3 :: #import "MathVec3.core"
|
||||
V2 :: #import "MathVec2.core"
|
||||
Vec3 :: V3.Vec3
|
||||
|
||||
DrawCoolGradient :: ()
|
||||
for y := 0, y < Mu.window.y, y+=1
|
||||
for x := 0, x < Mu.window.x, x+=1
|
||||
|
||||
// Normalize to range {0, 1}
|
||||
uv := V2.Vec2{x->F32, y->F32} / Mu.window.sizef
|
||||
|
||||
// Move to range {-1, 1}
|
||||
uv = uv*2->F32 - 1->F32
|
||||
Assert(uv.x >= -1 && uv.x <= 1)
|
||||
Assert(uv.y >= -1 && uv.y <= 1)
|
||||
|
||||
color := Vec3{uv.x, uv.y, 1}
|
||||
Mu.screen[x + y*Mu.window.x] = V3.ConvertToARGB(color)
|
||||
|
||||
for UpdateMultimedia()
|
||||
if Mu.key[Key.Escape].down
|
||||
Mu.key[Key.Escape].down = false
|
||||
break
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// #3
|
||||
//
|
||||
// * The ';;' operator
|
||||
// * The ';' operator
|
||||
// * Compound expressions, named parameters!
|
||||
DrawCircleWithGradient :: ()
|
||||
default_color := V3.ConvertToARGB({x = 1, y = 1, z = 1})
|
||||
ratio := Mu.window.sizef.x / Mu.window.sizef.y
|
||||
for y := 0, y < Mu.window.y, y+=1
|
||||
for x := 0, x < Mu.window.x, x+=1
|
||||
|
||||
// Normalize to range {0, 1}
|
||||
uv := V2.Vec2{x->F32, y->F32} / Mu.window.sizef
|
||||
|
||||
// Move to range {-1, 1}
|
||||
uv = uv*2->F32 - 1->F32
|
||||
uv.x *= ratio
|
||||
|
||||
if uv.x*uv.x + uv.y*uv.y < 0.5
|
||||
color := Vec3{uv.x, uv.y, 1}
|
||||
Mu.screen[x + y*Mu.window.x] = V3.ConvertToARGB(color)
|
||||
else;; Mu.screen[x + y*Mu.window.x] = default_color
|
||||
|
||||
for UpdateMultimedia()
|
||||
if Mu.key[Key.Escape].down
|
||||
Mu.key[Key.Escape].down = false
|
||||
break
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// #4
|
||||
//
|
||||
AnimateTransmorphingCircle :: ()
|
||||
for UpdateMultimedia()
|
||||
if Mu.key[Key.Escape].down
|
||||
Mu.key[Key.Escape].down = false
|
||||
break
|
||||
|
||||
default_color := V3.ConvertToARGB({x = 1, y = 1, z = 1})
|
||||
ratio := Mu.window.sizef.x / Mu.window.sizef.y
|
||||
for y := 0, y < Mu.window.y, y+=1
|
||||
for x := 0, x < Mu.window.x, x+=1
|
||||
|
||||
// Normalize to range {0, 1}
|
||||
uv := V2.Vec2{x->F32, y->F32} / Mu.window.sizef
|
||||
|
||||
// Move to range {-1, 1}
|
||||
uv = uv*2->F32 - 1->F32
|
||||
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
|
||||
color := Vec3{uv.x, uv.y, 1}
|
||||
Mu.screen[x + y*Mu.window.x] = V3.ConvertToARGB(color)
|
||||
else ;; Mu.screen[x + y*Mu.window.x] = default_color
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// #5
|
||||
//
|
||||
Epsilon :: 0.00001
|
||||
|
||||
SphereSDF :: (pos: Vec3): F32
|
||||
result := V3.Length(pos) - 1.0
|
||||
return result
|
||||
|
||||
RaymarchSphere :: ()
|
||||
for UpdateMultimedia()
|
||||
if Mu.key[Key.Escape].down
|
||||
Mu.key[Key.Escape].down = false
|
||||
break
|
||||
|
||||
up := Vec3{0, 1, 0}
|
||||
forward := Vec3{0, 0, -1}
|
||||
side := V3.Normalize(V3.Cross(forward, up))
|
||||
|
||||
LightPos := Vec3{2,4,2}
|
||||
LightPos.x = F.Cos(Mu.time.total->F32)*4
|
||||
LightPos.y = F.Sin(Mu.time.total->F32)*4
|
||||
|
||||
ambient_color := Vec3{0.2,0.2,0.2}
|
||||
diffuse_color := Vec3{0.7,0.2,0.2}
|
||||
eye := Vec3{0, 0, 2}
|
||||
light_intensity :: 1.2->F32
|
||||
|
||||
Xf := 1 / Mu.window.sizef.x
|
||||
Yf := 1 / Mu.window.sizef.y
|
||||
ratio := Mu.window.sizef.x / Mu.window.sizef.y
|
||||
for y := 0, y < Mu.window.y, y+=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.x *= ratio
|
||||
dir := V3.Normalize(Vec3{V3.Dot(side, uv), V3.Dot(up, uv), V3.Dot(forward, uv)})
|
||||
|
||||
t: F32
|
||||
end: F32 = 100.0
|
||||
hit := true
|
||||
p: Vec3
|
||||
for i := 0, i < 255, i+=1
|
||||
p = eye + dir*t
|
||||
|
||||
distance := SphereSDF(p)
|
||||
if distance < Epsilon
|
||||
break
|
||||
|
||||
t += distance
|
||||
if distance >= end
|
||||
hit = false
|
||||
break
|
||||
|
||||
if hit
|
||||
normal := V3.Normalize(Vec3{
|
||||
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, p.z + Epsilon}) - SphereSDF({p.x, p.y, p.z - Epsilon}),
|
||||
})
|
||||
|
||||
light_to_point := V3.Normalize(LightPos - p)
|
||||
|
||||
ambient :: 0.2->F32
|
||||
diffuse := V3.Dot(normal, light_to_point)
|
||||
|
||||
color := ambient_color*ambient->F32
|
||||
if diffuse > Epsilon
|
||||
color = color + diffuse_color*diffuse
|
||||
color = color * light_intensity
|
||||
|
||||
// Gamma correction
|
||||
color.x = F.SquareRoot(color.x)
|
||||
color.y = F.SquareRoot(color.y)
|
||||
color.z = F.SquareRoot(color.z)
|
||||
Mu.screen[x + y*Mu.window.x] = V3.ConvertToARGB(color)
|
||||
|
||||
else;; Mu.screen[x + y*Mu.window.x] = 0
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
90
build/examples/_polymorphism.core
Normal file
90
build/examples/_polymorphism.core
Normal file
@@ -0,0 +1,90 @@
|
||||
|
||||
/*
|
||||
PushStruct :: (a: *MA.Arena, $T: Type): *$T
|
||||
size := size_of(Type)
|
||||
result := PushSize(a, size)
|
||||
return result
|
||||
|
||||
Array(int)
|
||||
|
||||
QueueAddSLL(list: $List, node: $Node, first: #Identifier = first, last: #Identifier = last, next: #Identifier = next)
|
||||
|
||||
ArrayAdd(array: $Array, item: $Item, data: #Identifier = data, len: #Identifier = len, len: #Identifier = cap)
|
||||
|
||||
QueueAddSLL(list: $List, node: $Node, $first = first, $last = last, $next = next)
|
||||
if list.first == 0
|
||||
list.first = list.last = node
|
||||
else
|
||||
list.last = list.last.next = node
|
||||
*/
|
||||
|
||||
Array :: struct($T: Type)
|
||||
data: *T
|
||||
len: int
|
||||
cap: int
|
||||
|
||||
Tuple :: struct($A: Type, $B: Type)
|
||||
a: A
|
||||
b: B
|
||||
Triple :: struct($A: Type, $B: Type, $C: Type)
|
||||
a: A
|
||||
b: B
|
||||
c: C
|
||||
Variant :: union($A: Type, $B: Type, $C: Type)
|
||||
a: A
|
||||
b: B
|
||||
c: C
|
||||
|
||||
MakeArray :: (a: *int, count: int): Array(int)
|
||||
result := Array(int) {
|
||||
data = a,
|
||||
len = count,
|
||||
cap = count
|
||||
}
|
||||
return result
|
||||
|
||||
// :Multiple arguments
|
||||
// @todo: maybe disallow multiple arguments in current form
|
||||
// and use polimorphism. Then we could make var unpacking,
|
||||
// unpack structs making it more powerful
|
||||
MultipleArgs :: (): Tuple(int, F32)
|
||||
return {32, 32}
|
||||
|
||||
PolyLambda :: ($T: Type): T
|
||||
return 32
|
||||
|
||||
GetCount :: (a: int): int
|
||||
return a
|
||||
|
||||
// @todo: this is allowed, shouldn't be
|
||||
// Test :: (a: int, b: int = 10, c: int???)
|
||||
|
||||
Test :: (a: int, b: int = 10, c: int = 20)
|
||||
pass
|
||||
|
||||
main :: (argc: int, argv: **char): int
|
||||
buff: *int
|
||||
array: Array(int) = {len = 10, cap = 10, data = buff}
|
||||
second_array: Array(int)
|
||||
third_array: Array(int)
|
||||
fourth: Array(F32)
|
||||
fifth: Array(F32)
|
||||
sixth: Array(Array(F32))
|
||||
seventh: Variant(int, F32, S64)
|
||||
// d: int(32)
|
||||
|
||||
// c := MakeArray(buff, GetCount(GetCount(32)))
|
||||
|
||||
// a,b := MultipleArgs()
|
||||
a := MultipleArgs()
|
||||
|
||||
Test(10)
|
||||
Test(10, 20)
|
||||
Test(10, 20, 30)
|
||||
Test(10, b = 10)
|
||||
Test(10, b = 10, c = 20)
|
||||
Test(a = 10, b = 10, c = 20)
|
||||
|
||||
value := PolyLambda(int)
|
||||
|
||||
return 0
|
||||
97
build/examples/any_and_variadic_args.core
Normal file
97
build/examples/any_and_variadic_args.core
Normal file
@@ -0,0 +1,97 @@
|
||||
|
||||
VariadicArguments :: (string: *char, args: []Any): Any
|
||||
return args[0]
|
||||
|
||||
AnyArguments :: (values: []Any)
|
||||
for values
|
||||
Assert(it.type == S64)
|
||||
Assert(*(values[0].data->*S64) == 10)
|
||||
Assert(*(values[1].data->*S64) == 20)
|
||||
|
||||
/**
|
||||
* C++ version 0.4 char* style "itoa":
|
||||
* Written by Lukás Chmela
|
||||
* Released under GPLv3.
|
||||
*/
|
||||
IntegerToString :: (value: S64, result: *U8, base: S64): *U8
|
||||
// check that the base if valid
|
||||
if (base < 2) || (base > 36)
|
||||
*result = 0 // '
|
||||
return result
|
||||
|
||||
ptr := result
|
||||
ptr1 := result
|
||||
tmp_char: U8
|
||||
tmp_value: S64
|
||||
|
||||
for value != 0
|
||||
tmp_value = value
|
||||
value /= base
|
||||
*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + (tmp_value - value * base)]
|
||||
|
||||
// Apply negative sign
|
||||
if tmp_value < 0
|
||||
*ptr++ = '-'
|
||||
*ptr-- = 0
|
||||
for ptr1 < ptr
|
||||
tmp_char = *ptr
|
||||
*ptr-- = *ptr1
|
||||
*ptr1++ = tmp_char
|
||||
return result
|
||||
|
||||
StringToDouble :: (s: String): F64
|
||||
sign: F64 = 1.0
|
||||
i := 0
|
||||
|
||||
if s[i] == '-'
|
||||
sign = -1
|
||||
i += 1
|
||||
elif s[i] == '+'
|
||||
i += 1
|
||||
|
||||
for , i < Len(s), i+= 1
|
||||
pass // BACKUP
|
||||
|
||||
return 0
|
||||
|
||||
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
|
||||
arg_counter := 0
|
||||
out_buffer_len := 0
|
||||
for i := 0, i < Len(string), i+=1
|
||||
if string[i] == '%'
|
||||
Assert(arg_counter < Len(args), "Passed too many [%] to the string formating function")
|
||||
arg := args[arg_counter++]
|
||||
|
||||
if arg.type == S64
|
||||
value := *(arg.data->*S64)
|
||||
itoa_buff: [64]U8
|
||||
p := IntegerToString(value, &itoa_buff[0], 10)
|
||||
|
||||
for *p != 0
|
||||
buffer[out_buffer_len++] = *p++
|
||||
else;; Assert(false)
|
||||
else
|
||||
buffer[out_buffer_len++] = string[i]
|
||||
|
||||
|
||||
main :: (): int
|
||||
a := 10
|
||||
b := 20
|
||||
values := []Any{a, b}
|
||||
|
||||
for values
|
||||
Assert(it.type == S64)
|
||||
AnyArguments({a,b})
|
||||
c := VariadicArguments("Test", args = {a+b,b})
|
||||
Assert(*(c.data->*S64) == 30)
|
||||
d := VariadicArguments("Test", {b,a})
|
||||
Assert(*(d.data->*S64) == b)
|
||||
|
||||
Assert(*(values[0].data->*S64) == 10)
|
||||
Assert(*(values[1].data->*S64) == 20)
|
||||
|
||||
buf: [128]U8
|
||||
FormatString(&buf[0], Len(buf), "Test % %", {32, 156})
|
||||
|
||||
return 0
|
||||
55
build/examples/arrays_and_slices.core
Normal file
55
build/examples/arrays_and_slices.core
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
Static arrays are exactly like c arrays, difference is
|
||||
we can easily then get a slice of that array.
|
||||
|
||||
Slices are static arrays + length, they simplify array handling.
|
||||
This allows us to pass an array into a function easily, then that function
|
||||
can still access that length information easily.
|
||||
|
||||
Passing a pointer to array + length is a common pattern in C. So it would
|
||||
be nice if handling of that was simplified.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
main :: (): int
|
||||
static_array: [8]int
|
||||
|
||||
// We can get size of array using Length builtin
|
||||
#Assert(Len(static_array) == 8)
|
||||
|
||||
// Accessing values is like in C
|
||||
// Variables are zeroed by default
|
||||
Assert(static_array[1] == 0)
|
||||
|
||||
element2 := static_array[2]
|
||||
element0: int = static_array[0]
|
||||
Assert(element0 == 0 && element2 == 0)
|
||||
|
||||
// We can loop through arrays
|
||||
// this implicitly defines 'it' variable
|
||||
for static_array
|
||||
*it = 1
|
||||
|
||||
// We set all variables to 1 so
|
||||
Assert(static_array[6] == 1)
|
||||
|
||||
// This is how slice is defined, no [] index in between brackets
|
||||
// slice is array pointer + length
|
||||
// Other then that it works exactly like regular array
|
||||
slice: []int = static_array
|
||||
|
||||
// We can't do a compile time Assert anymore
|
||||
Assert(Len(slice) == 8)
|
||||
Assert(slice[4] == 1)
|
||||
|
||||
// After we loop and reassign slice values
|
||||
// old static_array gets changed
|
||||
//
|
||||
// In this example, operator ';;' is used
|
||||
// it inserts a new line, allows to write this
|
||||
// example in a single line
|
||||
for slice;; *it = 2
|
||||
|
||||
Assert(static_array[2] == 2)
|
||||
return 0
|
||||
40
build/examples/constant_expressions.core
Normal file
40
build/examples/constant_expressions.core
Normal file
@@ -0,0 +1,40 @@
|
||||
// We can bind module to a name
|
||||
M :: #import "Multimedia.core"
|
||||
|
||||
// You can bind struct to a name
|
||||
MU :: M.MU
|
||||
|
||||
// We can bind a lambda to a name
|
||||
Start :: M.StartMultimedia
|
||||
Update :: M.UpdateMultimedia
|
||||
|
||||
// Other example of binding a lambda to a name
|
||||
SomeOtherLambda :: () ;; pass
|
||||
AliasOf :: SomeOtherLambda
|
||||
|
||||
// We can bind a simple type to name, this type is
|
||||
// exactly the same as int, typechecker doesn't complain
|
||||
NewInt :: int
|
||||
|
||||
// We can force it to complain using a '#strict' directive
|
||||
// this makes a new type that requires casting, good for ids
|
||||
// and stuff like that, normal int operations still work!
|
||||
StrictInt :: #strict int
|
||||
|
||||
SomeStruct :: struct ;; a: int
|
||||
StructAlias :: SomeStruct
|
||||
|
||||
|
||||
main :: (): int
|
||||
some_struct: SomeStruct = {a = 10}
|
||||
struct_alias: StructAlias = some_struct
|
||||
Assert(struct_alias.a == 10)
|
||||
|
||||
#Assert(SomeStruct == StructAlias)
|
||||
#Assert(NewInt == int)
|
||||
#Assert(StrictInt != int)
|
||||
|
||||
Start(x = 1280, y = 720)
|
||||
Update()
|
||||
|
||||
return 0
|
||||
76
build/examples/drawing_to_screen_using_windows_api.core
Normal file
76
build/examples/drawing_to_screen_using_windows_api.core
Normal file
@@ -0,0 +1,76 @@
|
||||
#import "Base.core"
|
||||
#import "Arena.core"
|
||||
#import "KERNEL32.core"
|
||||
#import "GDI32.core"
|
||||
#import "USER32.core"
|
||||
|
||||
WinMain :: (hInstance: HINSTANCE, hPrevInstance: HINSTANCE, lpCmdLine: LPSTR, nShowCmd: int): int
|
||||
screen_size_x: int = 1280
|
||||
screen_size_y: int = 720
|
||||
|
||||
arena: Arena
|
||||
window_name := StringToString16(&arena, "Have a wonderful day!")
|
||||
w := WNDCLASSW{
|
||||
lpfnWndProc = WindowProc,
|
||||
hInstance = hInstance,
|
||||
lpszClassName = window_name.str,
|
||||
}
|
||||
Assert(RegisterClassW(&w) != 0)
|
||||
|
||||
window := CreateWindowExW(
|
||||
dwExStyle = 0, hWndParent = 0, hMenu = 0, lpParam = 0,
|
||||
X = CW_USEDEFAULT, Y = CW_USEDEFAULT, nWidth = screen_size_x, nHeight = screen_size_y,
|
||||
lpClassName = window_name.str,
|
||||
lpWindowName = window_name.str,
|
||||
dwStyle = WS_OVERLAPPEDWINDOW,
|
||||
hInstance = hInstance
|
||||
)
|
||||
Assert(window != 0)
|
||||
ShowWindow(window, nShowCmd)
|
||||
window_dc := GetDC(window)
|
||||
|
||||
header_size: U32 = SizeOf(BITMAPINFOHEADER)
|
||||
Assert(header_size == 40)
|
||||
bminfo := BITMAPINFO{
|
||||
BITMAPINFOHEADER{
|
||||
biSize = header_size,
|
||||
biWidth = screen_size_x->LONG,
|
||||
biHeight = screen_size_y->LONG,
|
||||
biPlanes = 1,
|
||||
biBitCount = 32,
|
||||
biCompression = BI_RGB,
|
||||
biXPelsPerMeter = 1,
|
||||
biYPelsPerMeter = 1,
|
||||
}
|
||||
}
|
||||
|
||||
pixels: *U32
|
||||
bitmap_dib := CreateDIBSection(window_dc, &bminfo, DIB_RGB_COLORS, (&pixels)->**void, 0, 0)
|
||||
bitmap_hdc := CreateCompatibleDC(window_dc)
|
||||
|
||||
for AppIsRunning
|
||||
msg: MSG
|
||||
for PeekMessageW(&msg, window, 0, 0, PM_REMOVE) > 0
|
||||
TranslateMessage(&msg)
|
||||
DispatchMessageW(&msg)
|
||||
|
||||
for y := 0->int, y < screen_size_y, y+=1
|
||||
for x := 0->int, x < screen_size_x, x+=1
|
||||
pixels[x + y*screen_size_x] = 0xFFFF0000
|
||||
|
||||
SelectObject(bitmap_hdc, bitmap_dib)
|
||||
BitBlt(window_dc, 0, 0, screen_size_x, screen_size_y, bitmap_hdc, 0, 0, SRCCOPY)
|
||||
Sleep(100)
|
||||
|
||||
if CStringCompare(lpCmdLine, "testing")
|
||||
return 0
|
||||
return 0
|
||||
|
||||
|
||||
AppIsRunning := true
|
||||
WindowProc :: (hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM): LRESULT
|
||||
if msg == WM_DESTROY
|
||||
PostQuitMessage(0)
|
||||
AppIsRunning = false
|
||||
return 0
|
||||
else;; return DefWindowProcW(hwnd, msg, wparam, lparam)
|
||||
55
build/examples/dynamic_typing.core
Normal file
55
build/examples/dynamic_typing.core
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
Language enables implementing dynamic typing using operator overloads and
|
||||
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
|
||||
Any values, they get implicitly converted to a pointer and a type.
|
||||
|
||||
a: Any = 10 // This sentence allocates 10 on the stack
|
||||
a: Any = a + 10 // This also allocates on stack
|
||||
a: Any = a // Does not allocate, takes pointer to a
|
||||
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
|
||||
something it will take a pointer to it.
|
||||
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.
|
||||
*/
|
||||
|
||||
|
||||
storage: [32]S64
|
||||
len : S64
|
||||
|
||||
"+" :: (a: Any, b: Any): Any
|
||||
result: Any = storage[len++]
|
||||
if a.type == S64 && b.type == S64
|
||||
*(result.data->*S64) = *(a.data->*S64) + *(b.data->*S64)
|
||||
return result
|
||||
|
||||
"+" :: (a: Any, b: S64): Any
|
||||
result: Any = storage[len++]
|
||||
if a.type == S64
|
||||
*(result.data->*S64) = *(a.data->*S64) + b
|
||||
return result
|
||||
|
||||
"==" :: (a: Any, b: S64): Bool
|
||||
result := false
|
||||
if a.type == S64
|
||||
result = *(a.data->*S64) == b
|
||||
return result
|
||||
|
||||
"==" :: (a: Any, b: Any): Bool
|
||||
result := false
|
||||
if a.type == S64 && b.type == S64
|
||||
result = *(a.data->*S64) == *(b.data->*S64)
|
||||
return result
|
||||
|
||||
main :: (): int
|
||||
a: Any = 10
|
||||
b: Any = 20
|
||||
c := a + b
|
||||
|
||||
Assert(c.type == S64 && c == 30)
|
||||
Assert(a+b+a==c+(5+5))
|
||||
|
||||
return 0
|
||||
103
build/examples/language_basics.core
Normal file
103
build/examples/language_basics.core
Normal file
@@ -0,0 +1,103 @@
|
||||
main :: (): int
|
||||
// Language has a bunch of standard builtin types:
|
||||
// Signed integer types
|
||||
s64val: S64 = 0
|
||||
s32val: S32 = 0
|
||||
s16val: S16 = 0
|
||||
s8val : S8 = 0
|
||||
intval: int = 0
|
||||
|
||||
// Unsigned integer types = U64, U32, U16, U8,
|
||||
u64val: U64 = 0
|
||||
u32val: U32 = 0
|
||||
u16val: U16 = 0
|
||||
u8val : U8 = 0
|
||||
|
||||
// Floating point types = F64, F32
|
||||
f64val: F64 = 0
|
||||
f32val: F32 = 0
|
||||
|
||||
// String type = String
|
||||
string_val: String = "String type"
|
||||
cstring_val: *char = "CString type"
|
||||
|
||||
// This is how we can assign variables
|
||||
// There is no need for prefixes, compiler figures
|
||||
// out the format by itself
|
||||
signed_variable: S32 = 10
|
||||
unsigned_variable: U32 = 10
|
||||
|
||||
// We can also tell the compiler to infer the type
|
||||
this_is_s64_by_default := 10
|
||||
this_is_f32_by_default := 10.1251
|
||||
this_is_string_by_default := "Thing"
|
||||
|
||||
// Reassigning values is exactly like in other languages
|
||||
this_is_s64_by_default = 20
|
||||
this_is_string_by_default = "Other_Thing"
|
||||
this_is_f32_by_default = 15.1255
|
||||
|
||||
// @todo: Add type_of operator!!!
|
||||
// Assert(type_of(this_is_string_by_default) == String)
|
||||
// Assert(type_of(this_is_s64_by_default) == S64)
|
||||
|
||||
// There are also constant bindings in the language.
|
||||
// You can bind all sorts of constants to names this way.
|
||||
INT_VALUE :: 10
|
||||
FLOAT_VALUE :: 124.125
|
||||
|
||||
// For constants we can mix and match different types
|
||||
COMBINE_VALUE :: INT_VALUE + FLOAT_VALUE
|
||||
|
||||
// When it comes to runtime variables it's a bit different
|
||||
// To do this we need a cast
|
||||
combining_types := this_is_s64_by_default->F32 + this_is_f32_by_default
|
||||
|
||||
// Compound statements
|
||||
// Struct is at the bottom of the file!
|
||||
data1 := Data{
|
||||
a = 1,
|
||||
d = 2
|
||||
}
|
||||
data2: Data = {
|
||||
a = 4,
|
||||
b = 2,
|
||||
}
|
||||
|
||||
size0 := SizeOf(Data)
|
||||
size1 := SizeOf(data1)
|
||||
align0 := AlignOf(Data)
|
||||
align1 := AlignOf(data1)
|
||||
type0 := TypeOf(Data)
|
||||
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(string_val[0] == 'S')
|
||||
Assert(cstring_val[0] == 'C')
|
||||
Assert(signed_variable == 10 && unsigned_variable == 10)
|
||||
Assert(INT_VALUE == 10)
|
||||
Assert(FLOAT_VALUE == 124.125)
|
||||
Assert(this_is_f32_by_default == 15.1255)
|
||||
Assert(combining_types == 15.1255 + 20)
|
||||
|
||||
Assert(data1.a == 1)
|
||||
Assert(data1.b == 0)
|
||||
Assert(data1.c == 0)
|
||||
Assert(data1.d == 2)
|
||||
Assert(data2.a == 4)
|
||||
Assert(data2.b == 2)
|
||||
Assert(data2.c == 0)
|
||||
Assert(data2.d == 0)
|
||||
|
||||
Assert(size0 == size1)
|
||||
Assert(align0 == align1)
|
||||
Assert(type0 == type1)
|
||||
Assert(TypeOf(data2) == Data)
|
||||
|
||||
return 0
|
||||
|
||||
Data :: struct
|
||||
a: S64
|
||||
b: S32
|
||||
c: S32
|
||||
d: S32
|
||||
26
build/examples/operator_overloading.core
Normal file
26
build/examples/operator_overloading.core
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
Vec3 :: struct;; x: F32; y: F32; z: F32
|
||||
|
||||
// We can define operator overloads for arbitrary types
|
||||
// these are just regular lambdas/functions
|
||||
"+" :: (a: Vec3, b: Vec3): Vec3
|
||||
return {a.x+b.x, a.y+b.y, a.z+b.z}
|
||||
|
||||
// We can make a one liner out of these using ';;' operator
|
||||
// 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): Vec3 ;; return {-a.x, -a.y, -a.z}
|
||||
|
||||
main :: (): int
|
||||
a := Vec3{1,1,1}
|
||||
b := Vec3{2,3,4}
|
||||
|
||||
// The expressions are replaced with the defined lambdas
|
||||
c := a + b
|
||||
Assert(c.x == 3 && c.y == 4 && c.z == 5)
|
||||
d := -c
|
||||
Assert(d.x == -3 && d.y == -4 && d.z == -5)
|
||||
e := c - d
|
||||
Assert(e.x == 6 && e.y == 8 && e.z == 10)
|
||||
|
||||
return 0
|
||||
74
build/examples/order_independent_declarations.core
Normal file
74
build/examples/order_independent_declarations.core
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
Biggest problems with C/C++ are the header files and the fact that
|
||||
top level declarations are required to be ordered.
|
||||
|
||||
In C++ you simply cannot write code like this:
|
||||
|
||||
struct Asset{
|
||||
Asset_Tag asset_tag;
|
||||
};
|
||||
|
||||
enum Asset_Tag{
|
||||
ASSET_SOUND,
|
||||
ASSET_IMAGE,
|
||||
};
|
||||
|
||||
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
|
||||
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,
|
||||
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.
|
||||
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
|
||||
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
|
||||
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
|
||||
to tell the compiler to solve all those issues for us.
|
||||
*/
|
||||
|
||||
// We can have main at the top level, this is something
|
||||
// that is sometimes pretty tricky in C++
|
||||
main :: (): int
|
||||
// Even though Asset is beneath main, this still works
|
||||
// this feature is even nicer when we think about modules etc.
|
||||
asset1 := make_sound()
|
||||
asset2 := make_sound()
|
||||
asset1.next_asset = &asset2
|
||||
return 0
|
||||
|
||||
// @todo: This does not work
|
||||
// asset := []Asset{make_sound(), make_sound()}
|
||||
// asset[0].next_sound = &asset[1]
|
||||
|
||||
|
||||
// Recursion is a pain point for this kinds of algorithms
|
||||
// As can be seen here it works very nicely
|
||||
make_sound :: (should_exit_recursion: Bool = false): Asset
|
||||
if should_exit_recursion == true
|
||||
asset: Asset
|
||||
asset.tag = Asset_Tag.Sound
|
||||
return asset
|
||||
return make_sound(true)
|
||||
|
||||
Asset :: struct
|
||||
tag: Asset_Tag
|
||||
|
||||
// Pointers to self work as expected
|
||||
// this is always a pain point for these kinds of
|
||||
// algorithms
|
||||
next_asset: *Asset
|
||||
|
||||
// enum #flag assigns default values differently from normal enums.
|
||||
// It assigns a unique bit of a value to each enumeration.
|
||||
// Default values go: 1, 2, 4, 8, 16, 32, 64
|
||||
Asset_Tag :: enum #flag
|
||||
Sound
|
||||
Image
|
||||
Text
|
||||
|
||||
|
||||
|
||||
|
||||
15
build/examples/push_struct.core
Normal file
15
build/examples/push_struct.core
Normal file
@@ -0,0 +1,15 @@
|
||||
MA :: #import "Arena.core"
|
||||
|
||||
PushStruct :: (a: *MA.Arena, $K: Type, $T: Type): *T
|
||||
size := SizeOf(T)
|
||||
result := MA.PushSize(a, size->U64)
|
||||
return result->*T
|
||||
|
||||
main :: (argc: int, argv: **char): int
|
||||
arena: MA.Arena
|
||||
a: *int = PushStruct(&arena, int, int)
|
||||
b: *F32 = PushStruct(&arena, int, F32)
|
||||
padding := SizeOf(int)
|
||||
Assert(arena.len->S64 == (SizeOf(int) + SizeOf(F32) + padding))
|
||||
|
||||
return 0
|
||||
210
build/examples/raymarcher.core
Normal file
210
build/examples/raymarcher.core
Normal file
@@ -0,0 +1,210 @@
|
||||
F :: #import "MathF32.core"
|
||||
V3 :: #import "MathVec3.core"; Vec3 :: V3.Vec3
|
||||
V2 :: #import "MathVec2.core"; Vec2 :: V2.Vec2
|
||||
|
||||
Epsilon :: 0.00001
|
||||
Screen : *U32
|
||||
X : S64
|
||||
Y : S64
|
||||
TotalTime: F64
|
||||
LightPos := Vec3{2,4,2}
|
||||
|
||||
SphereSDF :: (pos: Vec3): F32
|
||||
result := V3.Length(pos) - 1.0
|
||||
return result
|
||||
|
||||
Raymarcher_Update :: ()
|
||||
up := Vec3{0, 1, 0}
|
||||
forward := Vec3{0, 0, -1}
|
||||
side := V3.Normalize(V3.Cross(forward, up))
|
||||
|
||||
LightPos.x = F.Cos(TotalTime->F32)*4
|
||||
LightPos.y = F.Sin(TotalTime->F32)*4
|
||||
|
||||
ambient_color := Vec3{0.2,0.2,0.2}
|
||||
diffuse_color := Vec3{0.7,0.2,0.2}
|
||||
specular_color := Vec3{1,1,1}
|
||||
eye := Vec3{0, 0, 2}
|
||||
light_intensity :: 1.2->F32
|
||||
|
||||
Xf := 1 / X->F32
|
||||
Yf := 1 / Y->F32
|
||||
ratio := X->F32 / Y->F32
|
||||
for y := 0, y < Y, y+=1
|
||||
for x := 0, x < X, x+=1
|
||||
uv := Vec3{x->F32 * Xf * 2 - 1, y->F32 * Yf * 2 - 1, 1.0}
|
||||
uv.x *= ratio
|
||||
dir := V3.Normalize(Vec3{V3.Dot(side, uv), V3.Dot(up, uv), V3.Dot(forward, uv)})
|
||||
|
||||
t: F32
|
||||
end: F32 = 100.0
|
||||
hit := true
|
||||
p: Vec3
|
||||
for i := 0, i < 255, i+=1
|
||||
p = eye + dir*t
|
||||
|
||||
distance := SphereSDF(p)
|
||||
if distance < Epsilon
|
||||
break
|
||||
|
||||
t += distance
|
||||
if distance >= end
|
||||
hit = false
|
||||
break
|
||||
|
||||
if hit
|
||||
normal := V3.Normalize(Vec3{
|
||||
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, p.z + Epsilon}) - SphereSDF({p.x, p.y, p.z - Epsilon}),
|
||||
})
|
||||
|
||||
light_to_point := V3.Normalize(LightPos - p)
|
||||
eye_to_point := V3.Normalize(eye - p)
|
||||
reflected_light := V3.Normalize(V3.Reflect(V3.Negate(light_to_point), normal))
|
||||
|
||||
ambient :: 0.2->F32
|
||||
diffuse := V3.Dot(normal, light_to_point)
|
||||
|
||||
color := ambient_color*ambient->F32
|
||||
if diffuse > Epsilon
|
||||
color = color + diffuse_color*diffuse
|
||||
|
||||
specular := V3.Dot(reflected_light, eye_to_point)
|
||||
if specular > Epsilon
|
||||
specular = specular*specular*specular*specular
|
||||
color = color + specular_color*specular*0.2->F32
|
||||
color = color * light_intensity
|
||||
|
||||
// Gamma correction
|
||||
color.x = F.SquareRoot(color.x)
|
||||
color.y = F.SquareRoot(color.y)
|
||||
color.z = F.SquareRoot(color.z)
|
||||
Screen[x + y*X] = V3.ConvertToARGB(color)
|
||||
|
||||
else;; Screen[x + y*X] = 0
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////
|
||||
//
|
||||
// Windows specific code
|
||||
//
|
||||
|
||||
#import "Base.core"
|
||||
#import "Arena.core"
|
||||
#import "OS$OS.core"
|
||||
#import "KERNEL32.core"
|
||||
#import "GDI32.core"
|
||||
#import "USER32.core"
|
||||
#import "WINMM.core"
|
||||
|
||||
|
||||
AppIsRunning := true
|
||||
WindowProc :: (hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM): LRESULT
|
||||
if msg == WM_DESTROY
|
||||
PostQuitMessage(0)
|
||||
AppIsRunning = false
|
||||
return 0
|
||||
else;; return DefWindowProcW(hwnd, msg, wparam, lparam)
|
||||
|
||||
WinMain :: (hInstance: HINSTANCE, hPrevInstance: HINSTANCE, lpCmdLine: LPSTR, nShowCmd: int): int
|
||||
if good_scheduling := false, timeBeginPeriod(1) == TIMERR_NOERROR
|
||||
good_scheduling = true
|
||||
|
||||
dpi_aware_set := SetProcessDPIAware()
|
||||
Assert(dpi_aware_set != 0)
|
||||
|
||||
arena: Arena
|
||||
|
||||
window_name := StringToString16(&arena, "Have a wonderful day! 你好世界 ")
|
||||
w := WNDCLASSW{
|
||||
lpfnWndProc = WindowProc,
|
||||
hInstance = hInstance,
|
||||
lpszClassName = window_name.str,
|
||||
}
|
||||
Assert(RegisterClassW(&w) != 0)
|
||||
|
||||
screen_size: V2.Vec2I = {1280, 720}
|
||||
window := CreateWindowExW(
|
||||
dwExStyle = 0, hWndParent = 0, hMenu = 0, lpParam = 0,
|
||||
X = CW_USEDEFAULT, Y = CW_USEDEFAULT, nWidth = screen_size.x->int, nHeight = screen_size.y->int,
|
||||
lpClassName = window_name.str,
|
||||
lpWindowName = window_name.str,
|
||||
dwStyle = WS_OVERLAPPEDWINDOW,
|
||||
hInstance = hInstance
|
||||
)
|
||||
Assert(window != 0)
|
||||
ShowWindow(window, nShowCmd)
|
||||
|
||||
window_dc := GetDC(window)
|
||||
bitmap := CreateBitmap(screen_size)
|
||||
|
||||
requested_time_per_frame: F64 = 1.0 / 60.0
|
||||
frame_start_time := Time()
|
||||
frame_number: S64
|
||||
for AppIsRunning
|
||||
msg: MSG
|
||||
for PeekMessageW(&msg, window, 0, 0, PM_REMOVE) > 0
|
||||
TranslateMessage(&msg)
|
||||
DispatchMessageW(&msg)
|
||||
|
||||
Screen = bitmap.data; X = bitmap.size.x; Y = bitmap.size.y
|
||||
Raymarcher_Update()
|
||||
|
||||
SelectObject(bitmap.hdc, bitmap.dib)
|
||||
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_number += 1
|
||||
TotalTime += frame_time
|
||||
if frame_time < requested_time_per_frame
|
||||
if good_scheduling
|
||||
time_to_sleep := (requested_time_per_frame - frame_time) * 1000
|
||||
if time_to_sleep > 0
|
||||
time_to_sleep_dword := time_to_sleep->DWORD
|
||||
// @check if time_to_sleep_dword truncates down
|
||||
Sleep(time_to_sleep_dword)
|
||||
|
||||
new_frame_time := Time()
|
||||
for new_frame_time < requested_time_per_frame
|
||||
new_frame_time = Time() - frame_start_time
|
||||
|
||||
frame_time = new_frame_time
|
||||
|
||||
if CStringCompare(lpCmdLine, "testing")
|
||||
return 0
|
||||
return 0
|
||||
|
||||
|
||||
Windows_Bitmap :: struct
|
||||
size: V2.Vec2I
|
||||
data: *U32
|
||||
hdc: HDC
|
||||
dib: HBITMAP
|
||||
|
||||
CreateBitmap :: (size: V2.Vec2I, bottom_up: Bool = true): Windows_Bitmap
|
||||
result: Windows_Bitmap = {size = size}
|
||||
if bottom_up == false
|
||||
result.size.y = -result.size.y
|
||||
|
||||
header_size: U32 = SizeOf(BITMAPINFOHEADER)
|
||||
Assert(header_size == 40)
|
||||
bminfo := BITMAPINFO{
|
||||
BITMAPINFOHEADER{
|
||||
biSize = header_size,
|
||||
biWidth = size.x->LONG,
|
||||
biHeight = size.y->LONG,
|
||||
biPlanes = 1,
|
||||
biBitCount = 32,
|
||||
biCompression = BI_RGB,
|
||||
biXPelsPerMeter = 1,
|
||||
biYPelsPerMeter = 1,
|
||||
}
|
||||
}
|
||||
|
||||
hdc := GetDC(0)
|
||||
result.dib = CreateDIBSection(hdc, &bminfo, DIB_RGB_COLORS, (&result.data)->**void, 0, 0)
|
||||
result.hdc = CreateCompatibleDC(hdc)
|
||||
return result
|
||||
69
build/examples/runtime_type_information.core
Normal file
69
build/examples/runtime_type_information.core
Normal file
@@ -0,0 +1,69 @@
|
||||
main :: (): int
|
||||
// Let's say we have a type
|
||||
some_type := S64
|
||||
|
||||
// this function call allows us to get extensive type information
|
||||
// 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.
|
||||
// Other use cases allow us to do a type safe printf
|
||||
type_info: *Type_Info = GetTypeInfo(some_type)
|
||||
|
||||
// It can be null, requiring the type information would be a bit unwise
|
||||
// this is a lot of data
|
||||
if !type_info
|
||||
return 1
|
||||
|
||||
if type_info.type == S64
|
||||
// We can use SizeOf and AlignOf operators
|
||||
// to figure out the type alignment and it's size
|
||||
Assert(type_info.size == SizeOf(S64))
|
||||
Assert(type_info.align == AlignOf(S64))
|
||||
|
||||
else;; Assert(false, "We expected S64 here! What a boomer!")
|
||||
|
||||
//
|
||||
// @todo: This should work
|
||||
//
|
||||
// any_thing: Any = 10
|
||||
|
||||
|
||||
//
|
||||
// Any type allows us to combine a value pointer and
|
||||
// it's corresponding type_id
|
||||
//
|
||||
value_to_be_wrapped := 10
|
||||
any_value: Any = value_to_be_wrapped
|
||||
|
||||
if any_value.type == S64
|
||||
*(any_value.data->*S64) = 20
|
||||
elif any_value.type == int
|
||||
// Void pointers get implicitly cast
|
||||
value: *int = any_value.data
|
||||
*value = 30
|
||||
elif any_value.type == char;; Assert(false, "No bueno")
|
||||
|
||||
Assert(*(any_value.data->*S64) == 20)
|
||||
|
||||
letter := GetFirstLetterOfType(value_to_be_wrapped)
|
||||
Assert(letter == 'I')
|
||||
return 0
|
||||
|
||||
GetFirstLetterOfType :: (a: Any): U8
|
||||
type_info := GetTypeInfo(a.type)
|
||||
if !type_info
|
||||
return '-'
|
||||
|
||||
result: U8
|
||||
switch type_info.kind
|
||||
Type_Info_Kind.S64, Type_Info_Kind.S32, Type_Info_Kind.S16, Type_Info_Kind.S8, Type_Info_Kind.INT
|
||||
result = 'I'
|
||||
Type_Info_Kind.U64, Type_Info_Kind.U32, Type_Info_Kind.U16, Type_Info_Kind.U8
|
||||
result = 'U'
|
||||
Type_Info_Kind.F64
|
||||
result = 'F'
|
||||
Type_Info_Kind.POINTER
|
||||
result = '*'
|
||||
default;; result = '-'
|
||||
|
||||
return result
|
||||
|
||||
48
build/examples/types_as_first_class_values.core
Normal file
48
build/examples/types_as_first_class_values.core
Normal file
@@ -0,0 +1,48 @@
|
||||
main :: (): int
|
||||
// Types can be evaluated at compile time for equality
|
||||
#Assert(int == int)
|
||||
#Assert(int != char)
|
||||
#Assert(*char == *char)
|
||||
|
||||
// They can also be evaluated at runtime, they basically get
|
||||
// replaced with type ids, which are just unique integers assigned
|
||||
// to each type
|
||||
Assert(int == int)
|
||||
Assert(int != char)
|
||||
Assert(*char == *char)
|
||||
|
||||
// We can assign types to compile time variable constants
|
||||
New_Type :: int
|
||||
|
||||
// This is a loose association
|
||||
thing: int = 10
|
||||
new_type_thing: New_Type = thing
|
||||
#Assert(New_Type == int)
|
||||
|
||||
// to force typechecker to treat$
|
||||
// both of these types as different we need to add a #strict directive
|
||||
Strict_Type :: #strict int
|
||||
|
||||
// new_strict_type_thing: Strict_Type = thing // This produces a compile time type error
|
||||
// But this works
|
||||
strict_thing: Strict_Type = 10
|
||||
#Assert(Strict_Type != int)
|
||||
|
||||
// If we want to use those types together we need to cast
|
||||
Assert(new_type_thing + strict_thing->int != 0)
|
||||
|
||||
// We can also assign types to runtime variables, there is a special type for that
|
||||
some_type: Type = int
|
||||
some_type_implicit := char
|
||||
|
||||
// These can be checked for equality using ifs and switches
|
||||
if some_type == char
|
||||
pass
|
||||
|
||||
elif some_type_implicit == char
|
||||
pass
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
40
build/examples/unions.core
Normal file
40
build/examples/unions.core
Normal file
@@ -0,0 +1,40 @@
|
||||
|
||||
U :: union
|
||||
a: F64
|
||||
b: F32
|
||||
|
||||
C :: struct
|
||||
a: int
|
||||
b: int
|
||||
|
||||
main :: (argc: int, argv: **char): int
|
||||
memes: U
|
||||
memes.b = 10
|
||||
Assert(memes.b == 10)
|
||||
Assert(memes.a != 0)
|
||||
|
||||
compound: U = {b = 10.0}
|
||||
Assert(compound.b == 10)
|
||||
|
||||
t := U
|
||||
ti := GetTypeInfo(t)
|
||||
Assert(ti.size == SizeOf(U))
|
||||
|
||||
for ti.struct_members
|
||||
Assert(it.offset == 0)
|
||||
|
||||
ti_it := GetTypeInfo(it.type)
|
||||
Assert(ti_it.size != 0)
|
||||
|
||||
|
||||
/* @reproduction @todo
|
||||
```
|
||||
examples/unions.core - Error! Couldn't infer type of compound expression
|
||||
c = {10}
|
||||
```
|
||||
|
||||
c: C
|
||||
c = {10}
|
||||
*/
|
||||
|
||||
return 0
|
||||
12
build/examples/using_multimedia.core
Normal file
12
build/examples/using_multimedia.core
Normal file
@@ -0,0 +1,12 @@
|
||||
#import "Multimedia.core"
|
||||
|
||||
main :: (): int
|
||||
StartMultimedia(title = "Hello people!")
|
||||
for UpdateMultimedia()
|
||||
if Mu.key[Key.Escape].down ;; Mu.quit = true
|
||||
|
||||
for y := 0, y < Mu.window.y, y+=1
|
||||
for x := 0, x < Mu.window.x, x+=1
|
||||
Mu.screen[x + y*Mu.window.x] = 0xFFFFFF00
|
||||
|
||||
return 0
|
||||
Reference in New Issue
Block a user