mirror of
https://github.com/odin-lang/Odin.git
synced 2026-02-15 15:44:04 +00:00
#import search rule: relative then core/
This commit is contained in:
18
build.bat
18
build.bat
@@ -31,32 +31,32 @@ set linker_flags= -incremental:no -opt:ref -subsystem:console
|
||||
|
||||
if %release_mode% EQU 0 ( rem Debug
|
||||
set linker_flags=%linker_flags% -debug
|
||||
set libs=%libs% ..\src\utf8proc\utf8proc_debug.lib
|
||||
set libs=%libs% src\utf8proc\utf8proc_debug.lib
|
||||
) else ( rem Release
|
||||
set linker_flags=%linker_flags%
|
||||
set libs=%libs% ..\src\utf8proc\utf8proc.lib
|
||||
set libs=%libs% src\utf8proc\utf8proc.lib
|
||||
)
|
||||
|
||||
set compiler_settings=%compiler_includes% %compiler_flags% %compiler_warnings%
|
||||
set linker_settings=%libs% %linker_flags%
|
||||
|
||||
|
||||
set build_dir= "bin\"
|
||||
if not exist %build_dir% mkdir %build_dir%
|
||||
pushd %build_dir%
|
||||
rem set build_dir= "\"
|
||||
rem if not exist %build_dir% mkdir %build_dir%
|
||||
rem pushd %build_dir%
|
||||
del *.pdb > NUL 2> NUL
|
||||
del *.ilk > NUL 2> NUL
|
||||
|
||||
del ..\misc\*.pdb > NUL 2> NUL
|
||||
del ..\misc\*.ilk > NUL 2> NUL
|
||||
|
||||
cl %compiler_settings% "..\src\main.cpp" ^
|
||||
cl %compiler_settings% "src\main.cpp" ^
|
||||
/link %linker_settings% -OUT:%exe_name% ^
|
||||
&& odin run ..\code/demo.odin
|
||||
rem odin run ..\code/demo.odin
|
||||
&& odin run code/demo.odin
|
||||
rem odin run code/demo.odin
|
||||
|
||||
|
||||
:do_not_compile_exe
|
||||
popd
|
||||
rem popd
|
||||
:end_of_build
|
||||
|
||||
|
||||
583
code/fmt.odin
583
code/fmt.odin
@@ -1,583 +0,0 @@
|
||||
#import "os.odin" as os
|
||||
|
||||
print_byte_buffer :: proc(buf: ^[]byte, b: []byte) {
|
||||
if buf.count < buf.capacity {
|
||||
n := min(buf.capacity-buf.count, b.count)
|
||||
if n > 0 {
|
||||
offset := ptr_offset(buf.data, buf.count)
|
||||
memory_copy(offset, ^b[0], n)
|
||||
buf.count += n
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print_string_to_buffer :: proc(buf: ^[]byte, s: string) {
|
||||
print_byte_buffer(buf, s as []byte)
|
||||
}
|
||||
|
||||
|
||||
byte_reverse :: proc(b: []byte) {
|
||||
n := b.count
|
||||
for i := 0; i < n/2; i++ {
|
||||
b[i], b[n-1-i] = b[n-1-i], b[i]
|
||||
}
|
||||
}
|
||||
|
||||
encode_rune :: proc(r: rune) -> ([4]byte, int) {
|
||||
buf: [4]byte
|
||||
i := r as u32
|
||||
mask: byte : 0x3f
|
||||
if i <= 1<<7-1 {
|
||||
buf[0] = r as byte
|
||||
return buf, 1
|
||||
}
|
||||
if i <= 1<<11-1 {
|
||||
buf[0] = 0xc0 | (r>>6) as byte
|
||||
buf[1] = 0x80 | (r) as byte & mask
|
||||
return buf, 2
|
||||
}
|
||||
|
||||
// Invalid or Surrogate range
|
||||
if i > 0x0010ffff ||
|
||||
(i >= 0xd800 && i <= 0xdfff) {
|
||||
r = 0xfffd
|
||||
}
|
||||
|
||||
if i <= 1<<16-1 {
|
||||
buf[0] = 0xe0 | (r>>12) as byte
|
||||
buf[1] = 0x80 | (r>>6) as byte & mask
|
||||
buf[2] = 0x80 | (r) as byte & mask
|
||||
return buf, 3
|
||||
}
|
||||
|
||||
buf[0] = 0xf0 | (r>>18) as byte
|
||||
buf[1] = 0x80 | (r>>12) as byte & mask
|
||||
buf[2] = 0x80 | (r>>6) as byte & mask
|
||||
buf[3] = 0x80 | (r) as byte & mask
|
||||
return buf, 4
|
||||
}
|
||||
|
||||
print_rune_to_buffer :: proc(buf: ^[]byte, r: rune) {
|
||||
b, n := encode_rune(r)
|
||||
print_string_to_buffer(buf, b[:n] as string)
|
||||
}
|
||||
|
||||
print_space_to_buffer :: proc(buf: ^[]byte) { print_rune_to_buffer(buf, #rune " ") }
|
||||
print_nl_to_buffer :: proc(buf: ^[]byte) { print_rune_to_buffer(buf, #rune "\n") }
|
||||
|
||||
print_int_to_buffer :: proc(buf: ^[]byte, i: int) {
|
||||
print_int_base_to_buffer(buf, i, 10);
|
||||
}
|
||||
PRINT__NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$"
|
||||
print_int_base_to_buffer :: proc(buffer: ^[]byte, i, base: int) {
|
||||
|
||||
buf: [65]byte
|
||||
len := 0
|
||||
negative := false
|
||||
if i < 0 {
|
||||
negative = true
|
||||
i = -i
|
||||
}
|
||||
if i == 0 {
|
||||
buf[len] = #rune "0"
|
||||
len++
|
||||
}
|
||||
for i > 0 {
|
||||
buf[len] = PRINT__NUM_TO_CHAR_TABLE[i % base]
|
||||
len++
|
||||
i /= base
|
||||
}
|
||||
|
||||
if negative {
|
||||
buf[len] = #rune "-"
|
||||
len++
|
||||
}
|
||||
|
||||
byte_reverse(buf[:len])
|
||||
print_string_to_buffer(buffer, buf[:len] as string)
|
||||
}
|
||||
|
||||
print_uint_to_buffer :: proc(buffer: ^[]byte, i: uint) {
|
||||
print_uint_base_to_buffer(buffer, i, 10, 0, #rune " ")
|
||||
}
|
||||
print_uint_base_to_buffer :: proc(buffer: ^[]byte, i, base: uint, min_width: int, pad_char: byte) {
|
||||
buf: [65]byte
|
||||
len := 0
|
||||
if i == 0 {
|
||||
buf[len] = #rune "0"
|
||||
len++
|
||||
}
|
||||
for i > 0 {
|
||||
buf[len] = PRINT__NUM_TO_CHAR_TABLE[i % base]
|
||||
len++
|
||||
i /= base
|
||||
}
|
||||
for len < min_width {
|
||||
buf[len] = pad_char
|
||||
len++
|
||||
}
|
||||
|
||||
byte_reverse(buf[:len])
|
||||
print_string_to_buffer(buffer, buf[:len] as string)
|
||||
}
|
||||
|
||||
print_bool_to_buffer :: proc(buffer: ^[]byte, b : bool) {
|
||||
if b { print_string_to_buffer(buffer, "true") }
|
||||
else { print_string_to_buffer(buffer, "false") }
|
||||
}
|
||||
|
||||
print_pointer_to_buffer :: proc(buffer: ^[]byte, p: rawptr) #inline { print_uint_base_to_buffer(buffer, p as uint, 16, 0, #rune " ") }
|
||||
|
||||
print_f32_to_buffer :: proc(buffer: ^[]byte, f: f32) #inline { print__f64(buffer, f as f64, 7) }
|
||||
print_f64_to_buffer :: proc(buffer: ^[]byte, f: f64) #inline { print__f64(buffer, f, 10) }
|
||||
|
||||
print__f64 :: proc(buffer: ^[]byte, f: f64, decimal_places: int) {
|
||||
if f == 0 {
|
||||
print_rune_to_buffer(buffer, #rune "0")
|
||||
return
|
||||
}
|
||||
if f < 0 {
|
||||
print_rune_to_buffer(buffer, #rune "-")
|
||||
f = -f
|
||||
}
|
||||
|
||||
print_u64_to_buffer :: proc(buffer: ^[]byte, i: u64) {
|
||||
buf: [22]byte
|
||||
len := 0
|
||||
if i == 0 {
|
||||
buf[len] = #rune "0"
|
||||
len++
|
||||
}
|
||||
for i > 0 {
|
||||
buf[len] = PRINT__NUM_TO_CHAR_TABLE[i % 10]
|
||||
len++
|
||||
i /= 10
|
||||
}
|
||||
byte_reverse(buf[:len])
|
||||
print_string_to_buffer(buffer, buf[:len] as string)
|
||||
}
|
||||
|
||||
i := f as u64
|
||||
print_u64_to_buffer(buffer, i)
|
||||
f -= i as f64
|
||||
|
||||
print_rune_to_buffer(buffer, #rune ".")
|
||||
|
||||
mult := 10.0
|
||||
for decimal_places := 6; decimal_places >= 0; decimal_places-- {
|
||||
i = (f * mult) as u64
|
||||
print_u64_to_buffer(buffer, i as u64)
|
||||
f -= i as f64 / mult
|
||||
mult *= 10
|
||||
}
|
||||
}
|
||||
|
||||
print_type_to_buffer :: proc(buf: ^[]byte, ti: ^Type_Info) {
|
||||
if ti == null { return }
|
||||
|
||||
using Type_Info
|
||||
match type info : ti {
|
||||
case Named:
|
||||
print_string_to_buffer(buf, info.name)
|
||||
case Integer:
|
||||
match {
|
||||
case ti == type_info(int):
|
||||
print_string_to_buffer(buf, "int")
|
||||
case ti == type_info(uint):
|
||||
print_string_to_buffer(buf, "uint")
|
||||
default:
|
||||
if info.signed {
|
||||
print_string_to_buffer(buf, "i")
|
||||
} else {
|
||||
print_string_to_buffer(buf, "u")
|
||||
}
|
||||
print_int_to_buffer(buf, 8*info.size)
|
||||
}
|
||||
|
||||
case Float:
|
||||
match info.size {
|
||||
case 4: print_string_to_buffer(buf, "f32")
|
||||
case 8: print_string_to_buffer(buf, "f64")
|
||||
}
|
||||
case String: print_string_to_buffer(buf, "string")
|
||||
case Boolean: print_string_to_buffer(buf, "bool")
|
||||
case Pointer:
|
||||
print_string_to_buffer(buf, "^")
|
||||
print_type_to_buffer(buf, info.elem)
|
||||
case Procedure:
|
||||
print_string_to_buffer(buf, "proc")
|
||||
if info.params == null {
|
||||
print_string_to_buffer(buf, "()")
|
||||
} else {
|
||||
count := (info.params as ^Tuple).fields.count
|
||||
if count == 1 { print_string_to_buffer(buf, "(") }
|
||||
print_type_to_buffer(buf, info.params)
|
||||
if count == 1 { print_string_to_buffer(buf, ")") }
|
||||
}
|
||||
if info.results != null {
|
||||
print_string_to_buffer(buf, " -> ")
|
||||
print_type_to_buffer(buf, info.results)
|
||||
}
|
||||
case Tuple:
|
||||
count := info.fields.count
|
||||
if count != 1 { print_string_to_buffer(buf, "(") }
|
||||
for i := 0; i < count; i++ {
|
||||
if i > 0 { print_string_to_buffer(buf, ", ") }
|
||||
|
||||
f := info.fields[i]
|
||||
|
||||
if f.name.count > 0 {
|
||||
print_string_to_buffer(buf, f.name)
|
||||
print_string_to_buffer(buf, ": ")
|
||||
}
|
||||
print_type_to_buffer(buf, f.type_info)
|
||||
}
|
||||
if count != 1 { print_string_to_buffer(buf, ")") }
|
||||
|
||||
case Array:
|
||||
print_string_to_buffer(buf, "[")
|
||||
print_int_to_buffer(buf, info.count)
|
||||
print_string_to_buffer(buf, "]")
|
||||
print_type_to_buffer(buf, info.elem)
|
||||
case Slice:
|
||||
print_string_to_buffer(buf, "[")
|
||||
print_string_to_buffer(buf, "]")
|
||||
print_type_to_buffer(buf, info.elem)
|
||||
case Vector:
|
||||
print_string_to_buffer(buf, "{")
|
||||
print_int_to_buffer(buf, info.count)
|
||||
print_string_to_buffer(buf, "}")
|
||||
print_type_to_buffer(buf, info.elem)
|
||||
|
||||
case Struct:
|
||||
print_string_to_buffer(buf, "struct ")
|
||||
if info.packed { print_string_to_buffer(buf, "#packed ") }
|
||||
if info.ordered { print_string_to_buffer(buf, "#ordered ") }
|
||||
print_string_to_buffer(buf, "{")
|
||||
for i := 0; i < info.fields.count; i++ {
|
||||
if i > 0 {
|
||||
print_string_to_buffer(buf, ", ")
|
||||
}
|
||||
print_any_to_buffer(buf, info.fields[i].name)
|
||||
print_string_to_buffer(buf, ": ")
|
||||
print_type_to_buffer(buf, info.fields[i].type_info)
|
||||
}
|
||||
print_string_to_buffer(buf, "}")
|
||||
|
||||
case Union:
|
||||
print_string_to_buffer(buf, "union {")
|
||||
for i := 0; i < info.fields.count; i++ {
|
||||
if i > 0 {
|
||||
print_string_to_buffer(buf, ", ")
|
||||
}
|
||||
print_any_to_buffer(buf, info.fields[i].name)
|
||||
print_string_to_buffer(buf, ": ")
|
||||
print_type_to_buffer(buf, info.fields[i].type_info)
|
||||
}
|
||||
print_string_to_buffer(buf, "}")
|
||||
|
||||
case Raw_Union:
|
||||
print_string_to_buffer(buf, "raw_union {")
|
||||
for i := 0; i < info.fields.count; i++ {
|
||||
if i > 0 {
|
||||
print_string_to_buffer(buf, ", ")
|
||||
}
|
||||
print_any_to_buffer(buf, info.fields[i].name)
|
||||
print_string_to_buffer(buf, ": ")
|
||||
print_type_to_buffer(buf, info.fields[i].type_info)
|
||||
}
|
||||
print_string_to_buffer(buf, "}")
|
||||
|
||||
case Enum:
|
||||
print_string_to_buffer(buf, "enum ")
|
||||
print_type_to_buffer(buf, info.base)
|
||||
print_string_to_buffer(buf, "{}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
print_any_to_buffer :: proc(buf: ^[]byte, arg: any) {
|
||||
using Type_Info
|
||||
match type info : arg.type_info {
|
||||
case Named:
|
||||
a: any
|
||||
a.type_info = info.base
|
||||
a.data = arg.data
|
||||
match type b : info.base {
|
||||
case Struct:
|
||||
print_string_to_buffer(buf, info.name)
|
||||
print_string_to_buffer(buf, "{")
|
||||
for i := 0; i < b.fields.count; i++ {
|
||||
f := b.fields[i];
|
||||
if i > 0 {
|
||||
print_string_to_buffer(buf, ", ")
|
||||
}
|
||||
print_any_to_buffer(buf, f.name)
|
||||
print_string_to_buffer(buf, " = ")
|
||||
v: any
|
||||
v.type_info = f.type_info
|
||||
v.data = ptr_offset(arg.data as ^byte, f.offset)
|
||||
print_any_to_buffer(buf, v)
|
||||
}
|
||||
print_string_to_buffer(buf, "}")
|
||||
|
||||
default:
|
||||
print_any_to_buffer(buf, a)
|
||||
}
|
||||
|
||||
case Integer:
|
||||
if info.signed {
|
||||
i: int = 0;
|
||||
if arg.data != null {
|
||||
match info.size {
|
||||
case 1: i = (arg.data as ^i8)^ as int
|
||||
case 2: i = (arg.data as ^i16)^ as int
|
||||
case 4: i = (arg.data as ^i32)^ as int
|
||||
case 8: i = (arg.data as ^i64)^ as int
|
||||
case 16: i = (arg.data as ^i128)^ as int
|
||||
}
|
||||
}
|
||||
print_int_to_buffer(buf, i)
|
||||
} else {
|
||||
i: uint = 0;
|
||||
if arg.data != null {
|
||||
match info.size {
|
||||
case 1: i = (arg.data as ^u8)^ as uint
|
||||
case 2: i = (arg.data as ^u16)^ as uint
|
||||
case 4: i = (arg.data as ^u32)^ as uint
|
||||
case 8: i = (arg.data as ^u64)^ as uint
|
||||
case 16: i = (arg.data as ^u128)^ as uint
|
||||
}
|
||||
}
|
||||
print_uint_to_buffer(buf, i)
|
||||
}
|
||||
|
||||
case Float:
|
||||
f: f64 = 0
|
||||
if arg.data != null {
|
||||
match info.size {
|
||||
case 4: f = (arg.data as ^f32)^ as f64
|
||||
case 8: f = (arg.data as ^f64)^ as f64
|
||||
}
|
||||
}
|
||||
print_f64_to_buffer(buf, f)
|
||||
|
||||
case String:
|
||||
s := ""
|
||||
if arg.data != null {
|
||||
s = (arg.data as ^string)^
|
||||
}
|
||||
print_string_to_buffer(buf, s)
|
||||
|
||||
case Boolean:
|
||||
v := false;
|
||||
if arg.data != null {
|
||||
v = (arg.data as ^bool)^
|
||||
}
|
||||
print_bool_to_buffer(buf, v)
|
||||
|
||||
case Pointer:
|
||||
v := null;
|
||||
if arg.data != null {
|
||||
v = (arg.data as ^rawptr)^
|
||||
}
|
||||
print_pointer_to_buffer(buf, v)
|
||||
|
||||
case Enum:
|
||||
v: any
|
||||
v.data = arg.data
|
||||
v.type_info = info.base
|
||||
print_any_to_buffer(buf, v)
|
||||
|
||||
|
||||
case Array:
|
||||
print_string_to_buffer(buf, "[")
|
||||
defer print_string_to_buffer(buf, "]")
|
||||
|
||||
for i := 0; i < info.count; i++ {
|
||||
if i > 0 {
|
||||
print_string_to_buffer(buf, ", ")
|
||||
}
|
||||
|
||||
elem: any
|
||||
elem.data = (arg.data as int + i*info.elem_size) as rawptr
|
||||
elem.type_info = info.elem
|
||||
print_any_to_buffer(buf, elem)
|
||||
}
|
||||
|
||||
case Slice:
|
||||
slice := arg.data as ^[]byte
|
||||
print_string_to_buffer(buf, "[")
|
||||
defer print_string_to_buffer(buf, "]")
|
||||
|
||||
for i := 0; i < slice.count; i++ {
|
||||
if i > 0 {
|
||||
print_string_to_buffer(buf, ", ")
|
||||
}
|
||||
|
||||
elem: any
|
||||
elem.data = ptr_offset(slice.data, i*info.elem_size)
|
||||
elem.type_info = info.elem
|
||||
print_any_to_buffer(buf, elem)
|
||||
}
|
||||
|
||||
case Vector:
|
||||
print_string_to_buffer(buf, "<")
|
||||
defer print_string_to_buffer(buf, ">")
|
||||
|
||||
for i := 0; i < info.count; i++ {
|
||||
if i > 0 {
|
||||
print_string_to_buffer(buf, ", ")
|
||||
}
|
||||
|
||||
elem: any
|
||||
elem.data = ptr_offset(arg.data as ^byte, i*info.elem_size)
|
||||
elem.type_info = info.elem
|
||||
print_any_to_buffer(buf, elem)
|
||||
}
|
||||
|
||||
|
||||
case Struct:
|
||||
print_string_to_buffer(buf, "struct")
|
||||
print_string_to_buffer(buf, "{")
|
||||
defer print_string_to_buffer(buf, "}")
|
||||
|
||||
for i := 0; i < info.fields.count; i++ {
|
||||
if i > 0 {
|
||||
print_string_to_buffer(buf, ", ")
|
||||
}
|
||||
print_any_to_buffer(buf, info.fields[i].name)
|
||||
print_string_to_buffer(buf, " = ")
|
||||
a: any
|
||||
a.data = ptr_offset(arg.data as ^byte, info.fields[i].offset)
|
||||
a.type_info = info.fields[i].type_info
|
||||
print_any_to_buffer(buf, a)
|
||||
}
|
||||
|
||||
case Union:
|
||||
print_string_to_buffer(buf, "(union)")
|
||||
case Raw_Union:
|
||||
print_string_to_buffer(buf, "(raw_union)")
|
||||
case Procedure:
|
||||
print_type_to_buffer(buf, arg.type_info)
|
||||
print_string_to_buffer(buf, " @ 0x")
|
||||
print_pointer_to_buffer(buf, (arg.data as ^rawptr)^)
|
||||
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
type_info_is_string :: proc(info: ^Type_Info) -> bool {
|
||||
using Type_Info
|
||||
if info == null {
|
||||
return false
|
||||
}
|
||||
|
||||
for {
|
||||
match type i : info {
|
||||
case Named:
|
||||
info = i.base
|
||||
continue
|
||||
case String:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
print_to_buffer :: proc(buf: ^[]byte, fmt: string, args: ..any) {
|
||||
is_digit :: proc(r: rune) -> bool #inline {
|
||||
return r >= #rune "0" && r <= #rune "9"
|
||||
}
|
||||
|
||||
parse_int :: proc(s: string, offset: int) -> (int, int) {
|
||||
result := 0
|
||||
|
||||
for ; offset < s.count; offset++ {
|
||||
c := s[offset] as rune
|
||||
if !is_digit(c) {
|
||||
break
|
||||
}
|
||||
|
||||
result *= 10
|
||||
result += (c - #rune "0") as int
|
||||
}
|
||||
|
||||
return result, offset
|
||||
}
|
||||
|
||||
prev := 0
|
||||
implicit_index := 0
|
||||
|
||||
for i := 0; i < fmt.count; i++ {
|
||||
r := fmt[i] as rune
|
||||
index := implicit_index
|
||||
|
||||
if r != #rune "%" {
|
||||
continue
|
||||
}
|
||||
|
||||
print_string_to_buffer(buf, fmt[prev:i])
|
||||
i++ // Skip %
|
||||
if i < fmt.count {
|
||||
next := fmt[i] as rune
|
||||
|
||||
if next == #rune "%" {
|
||||
print_string_to_buffer(buf, "%")
|
||||
i++
|
||||
prev = i
|
||||
continue
|
||||
}
|
||||
|
||||
if is_digit(next) {
|
||||
index, i = parse_int(fmt, i)
|
||||
}
|
||||
}
|
||||
|
||||
if 0 <= index && index < args.count {
|
||||
print_any_to_buffer(buf, args[index])
|
||||
implicit_index = index+1
|
||||
} else {
|
||||
// TODO(bill): Error check index out bounds
|
||||
print_string_to_buffer(buf, "<invalid>")
|
||||
}
|
||||
|
||||
prev = i
|
||||
}
|
||||
|
||||
print_string_to_buffer(buf, fmt[prev:])
|
||||
}
|
||||
|
||||
PRINT_BUF_SIZE :: 1<<12
|
||||
|
||||
print_to_file :: proc(f: ^os.File, fmt: string, args: ..any) {
|
||||
data: [PRINT_BUF_SIZE]byte
|
||||
buf := data[:0]
|
||||
print_to_buffer(^buf, fmt, ..args)
|
||||
os.write(f, buf)
|
||||
}
|
||||
|
||||
println_to_file :: proc(f: ^os.File, fmt: string, args: ..any) {
|
||||
data: [PRINT_BUF_SIZE]byte
|
||||
buf := data[:0]
|
||||
print_to_buffer(^buf, fmt, ..args)
|
||||
print_nl_to_buffer(^buf)
|
||||
os.write(f, buf)
|
||||
}
|
||||
|
||||
|
||||
print :: proc(fmt: string, args: ..any) {
|
||||
print_to_file(os.get_standard_file(os.File_Standard.OUTPUT), fmt, ..args)
|
||||
}
|
||||
print_err :: proc(fmt: string, args: ..any) {
|
||||
print_to_file(os.get_standard_file(os.File_Standard.ERROR), fmt, ..args)
|
||||
}
|
||||
println :: proc(fmt: string, args: ..any) {
|
||||
println_to_file(os.get_standard_file(os.File_Standard.OUTPUT), fmt, ..args)
|
||||
}
|
||||
println_err :: proc(fmt: string, args: ..any) {
|
||||
println_to_file(os.get_standard_file(os.File_Standard.ERROR), fmt, ..args)
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
#foreign_system_library "opengl32"
|
||||
|
||||
ZERO :: 0x0000
|
||||
ONE :: 0x0001
|
||||
TRIANGLES :: 0x0004
|
||||
BLEND :: 0x0be2
|
||||
SRC_ALPHA :: 0x0302
|
||||
ONE_MINUS_SRC_ALPHA :: 0x0303
|
||||
TEXTURE_2D :: 0x0de1
|
||||
RGBA8 :: 0x8058
|
||||
UNSIGNED_BYTE :: 0x1401
|
||||
BGRA_EXT :: 0x80e1
|
||||
TEXTURE_MAX_LEVEL :: 0x813d
|
||||
RGBA :: 0x1908
|
||||
|
||||
NEAREST :: 0x2600
|
||||
LINEAR :: 0x2601
|
||||
|
||||
DEPTH_BUFFER_BIT :: 0x00000100
|
||||
STENCIL_BUFFER_BIT :: 0x00000400
|
||||
COLOR_BUFFER_BIT :: 0x00004000
|
||||
|
||||
TEXTURE_MAX_ANISOTROPY_EXT :: 0x84fe
|
||||
|
||||
TEXTURE_MAG_FILTER :: 0x2800
|
||||
TEXTURE_MIN_FILTER :: 0x2801
|
||||
TEXTURE_WRAP_S :: 0x2802
|
||||
TEXTURE_WRAP_T :: 0x2803
|
||||
|
||||
Clear :: proc(mask: u32) #foreign "glClear"
|
||||
ClearColor :: proc(r, g, b, a: f32) #foreign "glClearColor"
|
||||
Begin :: proc(mode: i32) #foreign "glBegin"
|
||||
End :: proc() #foreign "glEnd"
|
||||
Color3f :: proc(r, g, b: f32) #foreign "glColor3f"
|
||||
Color4f :: proc(r, g, b, a: f32) #foreign "glColor4f"
|
||||
Vertex2f :: proc(x, y: f32) #foreign "glVertex2f"
|
||||
Vertex3f :: proc(x, y, z: f32) #foreign "glVertex3f"
|
||||
TexCoord2f :: proc(u, v: f32) #foreign "glTexCoord2f"
|
||||
LoadIdentity :: proc() #foreign "glLoadIdentity"
|
||||
Ortho :: proc(left, right, bottom, top, near, far: f64) #foreign "glOrtho"
|
||||
BlendFunc :: proc(sfactor, dfactor: i32) #foreign "glBlendFunc"
|
||||
Enable :: proc(cap: i32) #foreign "glEnable"
|
||||
Disable :: proc(cap: i32) #foreign "glDisable"
|
||||
GenTextures :: proc(count: i32, result: ^u32) #foreign "glGenTextures"
|
||||
TexParameteri :: proc(target, pname, param: i32) #foreign "glTexParameteri"
|
||||
TexParameterf :: proc(target: i32, pname: i32, param: f32) #foreign "glTexParameterf"
|
||||
BindTexture :: proc(target: i32, texture: u32) #foreign "glBindTexture"
|
||||
TexImage2D :: proc(target, level, internal_format, width, height, border, format, _type: i32, pixels: rawptr) #foreign "glTexImage2D"
|
||||
|
||||
107
code/os.odin
107
code/os.odin
@@ -1,107 +0,0 @@
|
||||
#import "runtime.odin" as _ // TODO(bill): make the compile import this automatically
|
||||
#import "win32.odin" as win32
|
||||
|
||||
File :: type struct {
|
||||
Handle :: type win32.HANDLE
|
||||
handle: Handle
|
||||
}
|
||||
|
||||
open :: proc(name: string) -> (File, bool) {
|
||||
using win32
|
||||
buf: [300]byte
|
||||
copy(buf[:], name as []byte)
|
||||
f := File{CreateFileA(^buf[0], FILE_GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, 0, null)}
|
||||
success := f.handle != INVALID_HANDLE_VALUE as File.Handle
|
||||
|
||||
return f, success
|
||||
}
|
||||
|
||||
create :: proc(name: string) -> (File, bool) {
|
||||
using win32
|
||||
buf: [300]byte
|
||||
copy(buf[:], name as []byte)
|
||||
f := File{
|
||||
handle = CreateFileA(^buf[0], FILE_GENERIC_WRITE, FILE_SHARE_READ, null, CREATE_ALWAYS, 0, null),
|
||||
}
|
||||
success := f.handle != INVALID_HANDLE_VALUE as File.Handle
|
||||
return f, success
|
||||
}
|
||||
|
||||
|
||||
close :: proc(using f: ^File) {
|
||||
win32.CloseHandle(handle)
|
||||
}
|
||||
|
||||
write :: proc(using f: ^File, buf: []byte) -> bool {
|
||||
bytes_written: i32
|
||||
return win32.WriteFile(handle, buf.data, buf.count as i32, ^bytes_written, null) != 0
|
||||
}
|
||||
|
||||
|
||||
File_Standard :: type enum {
|
||||
INPUT,
|
||||
OUTPUT,
|
||||
ERROR,
|
||||
COUNT,
|
||||
}
|
||||
|
||||
__std_files := __set_file_standards();
|
||||
|
||||
__set_file_standards :: proc() -> [File_Standard.COUNT as int]File {
|
||||
return [File_Standard.COUNT as int]File{
|
||||
File{handle = win32.GetStdHandle(win32.STD_INPUT_HANDLE)},
|
||||
File{handle = win32.GetStdHandle(win32.STD_OUTPUT_HANDLE)},
|
||||
File{handle = win32.GetStdHandle(win32.STD_ERROR_HANDLE)},
|
||||
}
|
||||
}
|
||||
|
||||
get_standard_file :: proc(std: File_Standard) -> ^File {
|
||||
return ^__std_files[std]
|
||||
}
|
||||
|
||||
|
||||
read_entire_file :: proc(name: string) -> (string, bool) {
|
||||
buf: [300]byte
|
||||
copy(buf[:], name as []byte)
|
||||
|
||||
f, file_ok := open(name)
|
||||
if !file_ok {
|
||||
return "", false
|
||||
}
|
||||
defer close(^f)
|
||||
|
||||
length: i64
|
||||
file_size_ok := win32.GetFileSizeEx(f.handle as win32.HANDLE, ^length) != 0
|
||||
if !file_size_ok {
|
||||
return "", false
|
||||
}
|
||||
|
||||
data := new_slice(u8, length)
|
||||
if data.data == null {
|
||||
return "", false
|
||||
}
|
||||
|
||||
single_read_length: i32
|
||||
total_read: i64
|
||||
|
||||
for total_read < length {
|
||||
remaining := length - total_read
|
||||
to_read: u32
|
||||
MAX :: 1<<32-1
|
||||
if remaining <= MAX {
|
||||
to_read = remaining as u32
|
||||
} else {
|
||||
to_read = MAX
|
||||
}
|
||||
|
||||
win32.ReadFile(f.handle as win32.HANDLE, ^data[total_read], to_read, ^single_read_length, null)
|
||||
if single_read_length <= 0 {
|
||||
free(data.data)
|
||||
return "", false
|
||||
}
|
||||
|
||||
total_read += single_read_length as i64
|
||||
}
|
||||
|
||||
return data as string, true
|
||||
}
|
||||
@@ -1,353 +0,0 @@
|
||||
#shared_global_scope
|
||||
|
||||
// IMPORTANT NOTE(bill): Do not change the order of any of this data
|
||||
// The compiler relies upon this _exact_ order
|
||||
Type_Info :: union {
|
||||
Member :: struct #ordered {
|
||||
name: string // can be empty if tuple
|
||||
type_info: ^Type_Info
|
||||
offset: int // offsets are not used in tuples
|
||||
}
|
||||
Record :: struct #ordered {
|
||||
fields: []Member
|
||||
packed: bool
|
||||
ordered: bool
|
||||
}
|
||||
|
||||
|
||||
Named: struct #ordered {
|
||||
name: string
|
||||
base: ^Type_Info
|
||||
}
|
||||
Integer: struct #ordered {
|
||||
size: int // in bytes
|
||||
signed: bool
|
||||
}
|
||||
Float: struct #ordered {
|
||||
size: int // in bytes
|
||||
}
|
||||
String: struct #ordered {}
|
||||
Boolean: struct #ordered {}
|
||||
Pointer: struct #ordered {
|
||||
elem: ^Type_Info
|
||||
}
|
||||
Procedure: struct #ordered {
|
||||
params: ^Type_Info // Type_Info.Tuple
|
||||
results: ^Type_Info // Type_Info.Tuple
|
||||
variadic: bool
|
||||
}
|
||||
Array: struct #ordered {
|
||||
elem: ^Type_Info
|
||||
elem_size: int
|
||||
count: int
|
||||
}
|
||||
Slice: struct #ordered {
|
||||
elem: ^Type_Info
|
||||
elem_size: int
|
||||
}
|
||||
Vector: struct #ordered {
|
||||
elem: ^Type_Info
|
||||
elem_size: int
|
||||
count: int
|
||||
}
|
||||
Tuple: Record
|
||||
Struct: Record
|
||||
Union: Record
|
||||
Raw_Union: Record
|
||||
Enum: struct #ordered {
|
||||
base: ^Type_Info
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assume :: proc(cond: bool) #foreign "llvm.assume"
|
||||
|
||||
__debug_trap :: proc() #foreign "llvm.debugtrap"
|
||||
__trap :: proc() #foreign "llvm.trap"
|
||||
read_cycle_counter :: proc() -> u64 #foreign "llvm.readcyclecounter"
|
||||
|
||||
bit_reverse16 :: proc(b: u16) -> u16 #foreign "llvm.bitreverse.i16"
|
||||
bit_reverse32 :: proc(b: u32) -> u32 #foreign "llvm.bitreverse.i32"
|
||||
bit_reverse64 :: proc(b: u64) -> u64 #foreign "llvm.bitreverse.i64"
|
||||
|
||||
byte_swap16 :: proc(b: u16) -> u16 #foreign "llvm.bswap.i16"
|
||||
byte_swap32 :: proc(b: u32) -> u32 #foreign "llvm.bswap.i32"
|
||||
byte_swap64 :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64"
|
||||
|
||||
fmuladd32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32"
|
||||
fmuladd64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
|
||||
|
||||
heap_alloc :: proc(len: int) -> rawptr {
|
||||
c_malloc :: proc(len: int) -> rawptr #foreign "malloc"
|
||||
return c_malloc(len)
|
||||
}
|
||||
|
||||
heap_free :: proc(ptr: rawptr) {
|
||||
c_free :: proc(ptr: rawptr) #foreign "free"
|
||||
c_free(ptr)
|
||||
}
|
||||
|
||||
current_thread_id :: proc() -> int {
|
||||
GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
|
||||
return GetCurrentThreadId() as int
|
||||
}
|
||||
|
||||
memory_zero :: proc(data: rawptr, len: int) {
|
||||
llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign "llvm.memset.p0i8.i64"
|
||||
llvm_memset_64bit(data, 0, len, 1, false)
|
||||
}
|
||||
|
||||
memory_compare :: proc(dst, src: rawptr, len: int) -> int {
|
||||
// TODO(bill): make a faster `memory_compare`
|
||||
a := slice_ptr(dst as ^byte, len)
|
||||
b := slice_ptr(src as ^byte, len)
|
||||
for i := 0; i < len; i++ {
|
||||
if a[i] != b[i] {
|
||||
return (a[i] - b[i]) as int
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
memory_copy :: proc(dst, src: rawptr, len: int) #inline {
|
||||
llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memmove.p0i8.p0i8.i64"
|
||||
llvm_memmove_64bit(dst, src, len, 1, false)
|
||||
}
|
||||
|
||||
__string_eq :: proc(a, b: string) -> bool {
|
||||
if a.count != b.count {
|
||||
return false
|
||||
}
|
||||
if ^a[0] == ^b[0] {
|
||||
return true
|
||||
}
|
||||
return memory_compare(^a[0], ^b[0], a.count) == 0
|
||||
}
|
||||
|
||||
__string_cmp :: proc(a, b : string) -> int {
|
||||
// Translation of http://mgronhol.github.io/fast-strcmp/
|
||||
n := min(a.count, b.count)
|
||||
|
||||
fast := n/size_of(int) + 1
|
||||
offset := (fast-1)*size_of(int)
|
||||
curr_block := 0
|
||||
if n <= size_of(int) {
|
||||
fast = 0
|
||||
}
|
||||
|
||||
la := slice_ptr(^a[0] as ^int, fast)
|
||||
lb := slice_ptr(^b[0] as ^int, fast)
|
||||
|
||||
for ; curr_block < fast; curr_block++ {
|
||||
if (la[curr_block] ~ lb[curr_block]) != 0 {
|
||||
for pos := curr_block*size_of(int); pos < n; pos++ {
|
||||
if (a[pos] ~ b[pos]) != 0 {
|
||||
return a[pos] as int - b[pos] as int
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for ; offset < n; offset++ {
|
||||
if (a[offset] ~ b[offset]) != 0 {
|
||||
return a[offset] as int - b[offset] as int
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
__string_ne :: proc(a, b : string) -> bool #inline { return !__string_eq(a, b) }
|
||||
__string_lt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) < 0 }
|
||||
__string_gt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) > 0 }
|
||||
__string_le :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) <= 0 }
|
||||
__string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >= 0 }
|
||||
|
||||
__print_err_str :: proc(s: string) {
|
||||
|
||||
}
|
||||
__print_err_int :: proc(i: int) {
|
||||
|
||||
}
|
||||
|
||||
__assert :: proc(msg: string) {
|
||||
// TODO(bill): Write message
|
||||
__print_err_str(msg)
|
||||
__debug_trap()
|
||||
}
|
||||
|
||||
__bounds_check_error :: proc(file: string, line, column: int,
|
||||
index, count: int) {
|
||||
if 0 <= index && index < count {
|
||||
return
|
||||
}
|
||||
// TODO(bill): Write message
|
||||
// TODO(bill): Probably reduce the need for `print` in the runtime if possible
|
||||
// fmt.println_err("%(%:%) Index % is out of bounds range [0, %)",
|
||||
// file, line, column, index, count)
|
||||
__debug_trap()
|
||||
}
|
||||
|
||||
__slice_expr_error :: proc(file: string, line, column: int,
|
||||
low, high, max: int) {
|
||||
if 0 <= low && low <= high && high <= max {
|
||||
return
|
||||
}
|
||||
// TODO(bill): Write message
|
||||
// fmt.println_err("%(%:%) Invalid slice indices: [%:%:%]",
|
||||
// file, line, column, low, high, max)
|
||||
__debug_trap()
|
||||
}
|
||||
__substring_expr_error :: proc(file: string, line, column: int,
|
||||
low, high: int) {
|
||||
if 0 <= low && low <= high {
|
||||
return
|
||||
}
|
||||
// TODO(bill): Write message
|
||||
// fmt.println_err("%(%:%) Invalid substring indices: [%:%:%]",
|
||||
// file, line, column, low, high)
|
||||
__debug_trap()
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Allocator :: struct {
|
||||
Mode :: enum {
|
||||
ALLOC,
|
||||
FREE,
|
||||
FREE_ALL,
|
||||
RESIZE,
|
||||
}
|
||||
Proc :: type proc(allocator_data: rawptr, mode: Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64) -> rawptr
|
||||
|
||||
|
||||
procedure: Proc;
|
||||
data: rawptr
|
||||
}
|
||||
|
||||
|
||||
Context :: struct {
|
||||
thread_id: int
|
||||
|
||||
allocator: Allocator
|
||||
|
||||
user_data: rawptr
|
||||
user_index: int
|
||||
}
|
||||
|
||||
#thread_local __context: Context
|
||||
|
||||
|
||||
DEFAULT_ALIGNMENT :: align_of({4}f32)
|
||||
|
||||
|
||||
current_context :: proc() -> ^Context {
|
||||
return ^__context
|
||||
}
|
||||
|
||||
__check_context :: proc() {
|
||||
c := current_context()
|
||||
assert(c != null)
|
||||
|
||||
if c.allocator.procedure == null {
|
||||
c.allocator = __default_allocator()
|
||||
}
|
||||
if c.thread_id == 0 {
|
||||
c.thread_id = current_thread_id()
|
||||
}
|
||||
}
|
||||
|
||||
alloc :: proc(size: int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT) }
|
||||
|
||||
alloc_align :: proc(size, alignment: int) -> rawptr #inline {
|
||||
__check_context()
|
||||
a := current_context().allocator
|
||||
return a.procedure(a.data, Allocator.Mode.ALLOC, size, alignment, null, 0, 0)
|
||||
}
|
||||
|
||||
free :: proc(ptr: rawptr) #inline {
|
||||
__check_context()
|
||||
a := current_context().allocator
|
||||
_ = a.procedure(a.data, Allocator.Mode.FREE, 0, 0, ptr, 0, 0)
|
||||
}
|
||||
free_all :: proc() #inline {
|
||||
__check_context()
|
||||
a := current_context().allocator
|
||||
_ = a.procedure(a.data, Allocator.Mode.FREE_ALL, 0, 0, null, 0, 0)
|
||||
}
|
||||
|
||||
|
||||
resize :: proc(ptr: rawptr, old_size, new_size: int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT) }
|
||||
resize_align :: proc(ptr: rawptr, old_size, new_size, alignment: int) -> rawptr #inline {
|
||||
a := current_context().allocator
|
||||
return a.procedure(a.data, Allocator.Mode.RESIZE, new_size, alignment, ptr, old_size, 0)
|
||||
}
|
||||
|
||||
|
||||
|
||||
default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int) -> rawptr {
|
||||
if old_memory == null {
|
||||
return alloc_align(new_size, alignment)
|
||||
}
|
||||
|
||||
if new_size == 0 {
|
||||
free(old_memory)
|
||||
return null
|
||||
}
|
||||
|
||||
if new_size == old_size {
|
||||
return old_memory
|
||||
}
|
||||
|
||||
new_memory := alloc_align(new_size, alignment)
|
||||
if new_memory == null {
|
||||
return null
|
||||
}
|
||||
|
||||
memory_copy(new_memory, old_memory, min(old_size, new_size));
|
||||
free(old_memory)
|
||||
return new_memory
|
||||
}
|
||||
|
||||
|
||||
__default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
|
||||
using Allocator.Mode
|
||||
match mode {
|
||||
case ALLOC:
|
||||
return heap_alloc(size)
|
||||
case RESIZE:
|
||||
return default_resize_align(old_memory, old_size, size, alignment)
|
||||
case FREE:
|
||||
heap_free(old_memory)
|
||||
return null
|
||||
case FREE_ALL:
|
||||
// NOTE(bill): Does nothing
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
__default_allocator :: proc() -> Allocator {
|
||||
return Allocator{
|
||||
procedure = __default_allocator_proc,
|
||||
data = null,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
451
code/win32.odin
451
code/win32.odin
@@ -1,451 +0,0 @@
|
||||
#foreign_system_library "user32"
|
||||
#foreign_system_library "gdi32"
|
||||
|
||||
HANDLE :: type rawptr
|
||||
HWND :: type HANDLE
|
||||
HDC :: type HANDLE
|
||||
HINSTANCE :: type HANDLE
|
||||
HICON :: type HANDLE
|
||||
HCURSOR :: type HANDLE
|
||||
HMENU :: type HANDLE
|
||||
HBRUSH :: type HANDLE
|
||||
HGDIOBJ :: type HANDLE
|
||||
WPARAM :: type uint
|
||||
LPARAM :: type int
|
||||
LRESULT :: type int
|
||||
ATOM :: type i16
|
||||
BOOL :: type i32
|
||||
WNDPROC :: type proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT
|
||||
|
||||
INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE
|
||||
|
||||
CS_VREDRAW :: 0x0001
|
||||
CS_HREDRAW :: 0x0002
|
||||
CS_OWNDC :: 0x0020
|
||||
CW_USEDEFAULT :: 0x80000000
|
||||
|
||||
WS_OVERLAPPED :: 0
|
||||
WS_MAXIMIZEBOX :: 0x00010000
|
||||
WS_MINIMIZEBOX :: 0x00020000
|
||||
WS_THICKFRAME :: 0x00040000
|
||||
WS_SYSMENU :: 0x00080000
|
||||
WS_CAPTION :: 0x00C00000
|
||||
WS_VISIBLE :: 0x10000000
|
||||
WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX
|
||||
|
||||
WM_DESTROY :: 0x0002
|
||||
WM_CLOSE :: 0x0010
|
||||
WM_QUIT :: 0x0012
|
||||
WM_KEYDOWN :: 0x0100
|
||||
WM_KEYUP :: 0x0101
|
||||
|
||||
PM_REMOVE :: 1
|
||||
|
||||
COLOR_BACKGROUND :: 1 as HBRUSH
|
||||
BLACK_BRUSH :: 4
|
||||
|
||||
SM_CXSCREEN :: 0
|
||||
SM_CYSCREEN :: 1
|
||||
|
||||
SW_SHOW :: 5
|
||||
|
||||
POINT :: struct #ordered {
|
||||
x, y: i32
|
||||
}
|
||||
|
||||
|
||||
WNDCLASSEXA :: struct #ordered {
|
||||
size, style: u32
|
||||
wnd_proc: WNDPROC
|
||||
cls_extra, wnd_extra: i32
|
||||
instance: HINSTANCE
|
||||
icon: HICON
|
||||
cursor: HCURSOR
|
||||
background: HBRUSH
|
||||
menu_name, class_name: ^u8
|
||||
sm: HICON
|
||||
}
|
||||
|
||||
MSG :: struct #ordered {
|
||||
hwnd: HWND
|
||||
message: u32
|
||||
wparam: WPARAM
|
||||
lparam: LPARAM
|
||||
time: u32
|
||||
pt: POINT
|
||||
}
|
||||
|
||||
RECT :: struct #ordered {
|
||||
left: i32
|
||||
top: i32
|
||||
right: i32
|
||||
bottom: i32
|
||||
}
|
||||
|
||||
|
||||
GetLastError :: proc() -> i32 #foreign #dll_import
|
||||
ExitProcess :: proc(exit_code: u32) #foreign #dll_import
|
||||
GetDesktopWindow :: proc() -> HWND #foreign #dll_import
|
||||
GetCursorPos :: proc(p: ^POINT) -> i32 #foreign #dll_import
|
||||
ScreenToClient :: proc(h: HWND, p: ^POINT) -> i32 #foreign #dll_import
|
||||
GetModuleHandleA :: proc(module_name: ^u8) -> HINSTANCE #foreign #dll_import
|
||||
GetStockObject :: proc(fn_object: i32) -> HGDIOBJ #foreign #dll_import
|
||||
PostQuitMessage :: proc(exit_code: i32) #foreign #dll_import
|
||||
SetWindowTextA :: proc(hwnd: HWND, c_string: ^u8) -> BOOL #foreign #dll_import
|
||||
|
||||
QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign #dll_import
|
||||
QueryPerformanceCounter :: proc(result: ^i64) -> i32 #foreign #dll_import
|
||||
|
||||
Sleep :: proc(ms: i32) -> i32 #foreign #dll_import
|
||||
|
||||
OutputDebugStringA :: proc(c_str: ^u8) #foreign #dll_import
|
||||
|
||||
|
||||
RegisterClassExA :: proc(wc: ^WNDCLASSEXA) -> ATOM #foreign #dll_import
|
||||
CreateWindowExA :: proc(ex_style: u32,
|
||||
class_name, title: ^u8,
|
||||
style: u32,
|
||||
x, y, w, h: i32,
|
||||
parent: HWND, menu: HMENU, instance: HINSTANCE,
|
||||
param: rawptr) -> HWND #foreign #dll_import
|
||||
|
||||
ShowWindow :: proc(hwnd: HWND, cmd_show: i32) -> BOOL #foreign #dll_import
|
||||
TranslateMessage :: proc(msg: ^MSG) -> BOOL #foreign #dll_import
|
||||
DispatchMessageA :: proc(msg: ^MSG) -> LRESULT #foreign #dll_import
|
||||
UpdateWindow :: proc(hwnd: HWND) -> BOOL #foreign #dll_import
|
||||
PeekMessageA :: proc(msg: ^MSG, hwnd: HWND,
|
||||
msg_filter_min, msg_filter_max, remove_msg: u32) -> BOOL #foreign #dll_import
|
||||
|
||||
DefWindowProcA :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #foreign #dll_import
|
||||
|
||||
AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign #dll_import
|
||||
|
||||
|
||||
GetQueryPerformanceFrequency :: proc() -> i64 {
|
||||
r: i64
|
||||
QueryPerformanceFrequency(^r)
|
||||
return r
|
||||
}
|
||||
|
||||
GetCommandLineA :: proc() -> ^u8 #foreign #dll_import
|
||||
GetSystemMetrics :: proc(index: i32) -> i32 #foreign #dll_import
|
||||
GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
|
||||
|
||||
// File Stuff
|
||||
|
||||
CloseHandle :: proc(h: HANDLE) -> i32 #foreign #dll_import
|
||||
GetStdHandle :: proc(h: i32) -> HANDLE #foreign #dll_import
|
||||
CreateFileA :: proc(filename: ^u8, desired_access, share_mode: u32,
|
||||
security: rawptr,
|
||||
creation, flags_and_attribs: u32, template_file: HANDLE) -> HANDLE #foreign #dll_import
|
||||
ReadFile :: proc(h: HANDLE, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> BOOL #foreign #dll_import
|
||||
WriteFile :: proc(h: HANDLE, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> i32 #foreign #dll_import
|
||||
|
||||
GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^i64) -> BOOL #foreign #dll_import
|
||||
|
||||
FILE_SHARE_READ :: 0x00000001
|
||||
FILE_SHARE_WRITE :: 0x00000002
|
||||
FILE_SHARE_DELETE :: 0x00000004
|
||||
FILE_GENERIC_ALL :: 0x10000000
|
||||
FILE_GENERIC_EXECUTE :: 0x20000000
|
||||
FILE_GENERIC_WRITE :: 0x40000000
|
||||
FILE_GENERIC_READ :: 0x80000000
|
||||
|
||||
STD_INPUT_HANDLE :: -10
|
||||
STD_OUTPUT_HANDLE :: -11
|
||||
STD_ERROR_HANDLE :: -12
|
||||
|
||||
CREATE_NEW :: 1
|
||||
CREATE_ALWAYS :: 2
|
||||
OPEN_EXISTING :: 3
|
||||
OPEN_ALWAYS :: 4
|
||||
TRUNCATE_EXISTING :: 5
|
||||
|
||||
|
||||
HeapAlloc :: proc(h: HANDLE, flags: u32, bytes: int) -> rawptr #foreign #dll_import
|
||||
HeapFree :: proc(h: HANDLE, flags: u32, memory: rawptr) -> BOOL #foreign #dll_import
|
||||
GetProcessHeap :: proc() -> HANDLE #foreign #dll_import
|
||||
|
||||
|
||||
HEAP_ZERO_MEMORY :: 0x00000008
|
||||
|
||||
|
||||
|
||||
// GDI
|
||||
|
||||
BITMAPINFO :: struct #ordered {
|
||||
HEADER :: struct #ordered {
|
||||
size: u32
|
||||
width, height: i32
|
||||
planes, bit_count: i16
|
||||
compression: u32
|
||||
size_image: u32
|
||||
x_pels_per_meter: i32
|
||||
y_pels_per_meter: i32
|
||||
clr_used: u32
|
||||
clr_important: u32
|
||||
}
|
||||
using header: HEADER
|
||||
colors: [1]RGBQUAD
|
||||
}
|
||||
|
||||
|
||||
RGBQUAD :: struct #ordered {
|
||||
blue, green, red, reserved: byte
|
||||
}
|
||||
|
||||
BI_RGB :: 0
|
||||
DIB_RGB_COLORS :: 0x00
|
||||
SRCCOPY : u32 : 0x00cc0020
|
||||
|
||||
StretchDIBits :: proc(hdc: HDC,
|
||||
x_dst, y_dst, width_dst, height_dst: i32,
|
||||
x_src, y_src, width_src, header_src: i32,
|
||||
bits: rawptr, bits_info: ^BITMAPINFO,
|
||||
usage: u32,
|
||||
rop: u32) -> i32 #foreign #dll_import
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Windows OpenGL
|
||||
|
||||
PFD_TYPE_RGBA :: 0
|
||||
PFD_TYPE_COLORINDEX :: 1
|
||||
PFD_MAIN_PLANE :: 0
|
||||
PFD_OVERLAY_PLANE :: 1
|
||||
PFD_UNDERLAY_PLANE :: -1
|
||||
PFD_DOUBLEBUFFER :: 1
|
||||
PFD_STEREO :: 2
|
||||
PFD_DRAW_TO_WINDOW :: 4
|
||||
PFD_DRAW_TO_BITMAP :: 8
|
||||
PFD_SUPPORT_GDI :: 16
|
||||
PFD_SUPPORT_OPENGL :: 32
|
||||
PFD_GENERIC_FORMAT :: 64
|
||||
PFD_NEED_PALETTE :: 128
|
||||
PFD_NEED_SYSTEM_PALETTE :: 0x00000100
|
||||
PFD_SWAP_EXCHANGE :: 0x00000200
|
||||
PFD_SWAP_COPY :: 0x00000400
|
||||
PFD_SWAP_LAYER_BUFFERS :: 0x00000800
|
||||
PFD_GENERIC_ACCELERATED :: 0x00001000
|
||||
PFD_DEPTH_DONTCARE :: 0x20000000
|
||||
PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000
|
||||
PFD_STEREO_DONTCARE :: 0x80000000
|
||||
|
||||
HGLRC :: type HANDLE
|
||||
PROC :: type proc()
|
||||
wglCreateContextAttribsARBType :: type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC
|
||||
|
||||
|
||||
PIXELFORMATDESCRIPTOR :: struct #ordered {
|
||||
size,
|
||||
version,
|
||||
flags: u32
|
||||
|
||||
pixel_type,
|
||||
color_bits,
|
||||
red_bits,
|
||||
red_shift,
|
||||
green_bits,
|
||||
green_shift,
|
||||
blue_bits,
|
||||
blue_shift,
|
||||
alpha_bits,
|
||||
alpha_shift,
|
||||
accum_bits,
|
||||
accum_red_bits,
|
||||
accum_green_bits,
|
||||
accum_blue_bits,
|
||||
accum_alpha_bits,
|
||||
depth_bits,
|
||||
stencil_bits,
|
||||
aux_buffers,
|
||||
layer_type,
|
||||
reserved: byte
|
||||
|
||||
layer_mask,
|
||||
visible_mask,
|
||||
damage_mask: u32
|
||||
}
|
||||
|
||||
GetDC :: proc(h: HANDLE) -> HDC #foreign
|
||||
SetPixelFormat :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign #dll_import
|
||||
ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign #dll_import
|
||||
SwapBuffers :: proc(hdc: HDC) -> BOOL #foreign #dll_import
|
||||
ReleaseDC :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign #dll_import
|
||||
|
||||
WGL_CONTEXT_MAJOR_VERSION_ARB :: 0x2091
|
||||
WGL_CONTEXT_MINOR_VERSION_ARB :: 0x2092
|
||||
WGL_CONTEXT_PROFILE_MASK_ARB :: 0x9126
|
||||
WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002
|
||||
|
||||
wglCreateContext :: proc(hdc: HDC) -> HGLRC #foreign #dll_import
|
||||
wglMakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign #dll_import
|
||||
wglGetProcAddress :: proc(c_str: ^u8) -> PROC #foreign #dll_import
|
||||
wglDeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign #dll_import
|
||||
|
||||
|
||||
|
||||
GetKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import
|
||||
GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import
|
||||
|
||||
is_key_down :: proc(key: Key_Code) -> bool {
|
||||
return GetAsyncKeyState(key as i32) < 0
|
||||
}
|
||||
|
||||
Key_Code :: enum i32 {
|
||||
LBUTTON = 0x01,
|
||||
RBUTTON = 0x02,
|
||||
CANCEL = 0x03,
|
||||
MBUTTON = 0x04,
|
||||
|
||||
BACK = 0x08,
|
||||
TAB = 0x09,
|
||||
|
||||
CLEAR = 0x0C,
|
||||
RETURN = 0x0D,
|
||||
|
||||
SHIFT = 0x10,
|
||||
CONTROL = 0x11,
|
||||
MENU = 0x12,
|
||||
PAUSE = 0x13,
|
||||
CAPITAL = 0x14,
|
||||
|
||||
KANA = 0x15,
|
||||
HANGEUL = 0x15,
|
||||
HANGUL = 0x15,
|
||||
JUNJA = 0x17,
|
||||
FINAL = 0x18,
|
||||
HANJA = 0x19,
|
||||
KANJI = 0x19,
|
||||
|
||||
ESCAPE = 0x1B,
|
||||
|
||||
CONVERT = 0x1C,
|
||||
NONCONVERT = 0x1D,
|
||||
ACCEPT = 0x1E,
|
||||
MODECHANGE = 0x1F,
|
||||
|
||||
SPACE = 0x20,
|
||||
PRIOR = 0x21,
|
||||
NEXT = 0x22,
|
||||
END = 0x23,
|
||||
HOME = 0x24,
|
||||
LEFT = 0x25,
|
||||
UP = 0x26,
|
||||
RIGHT = 0x27,
|
||||
DOWN = 0x28,
|
||||
SELECT = 0x29,
|
||||
PRINT = 0x2A,
|
||||
EXECUTE = 0x2B,
|
||||
SNAPSHOT = 0x2C,
|
||||
INSERT = 0x2D,
|
||||
DELETE = 0x2E,
|
||||
HELP = 0x2F,
|
||||
|
||||
NUM0 = #rune "0",
|
||||
NUM1 = #rune "1",
|
||||
NUM2 = #rune "2",
|
||||
NUM3 = #rune "3",
|
||||
NUM4 = #rune "4",
|
||||
NUM5 = #rune "5",
|
||||
NUM6 = #rune "6",
|
||||
NUM7 = #rune "7",
|
||||
NUM8 = #rune "8",
|
||||
NUM9 = #rune "9",
|
||||
|
||||
A = #rune "A",
|
||||
B = #rune "B",
|
||||
C = #rune "C",
|
||||
D = #rune "D",
|
||||
E = #rune "E",
|
||||
F = #rune "F",
|
||||
G = #rune "G",
|
||||
H = #rune "H",
|
||||
I = #rune "I",
|
||||
J = #rune "J",
|
||||
K = #rune "K",
|
||||
L = #rune "L",
|
||||
M = #rune "M",
|
||||
N = #rune "N",
|
||||
O = #rune "O",
|
||||
P = #rune "P",
|
||||
Q = #rune "Q",
|
||||
R = #rune "R",
|
||||
S = #rune "S",
|
||||
T = #rune "T",
|
||||
U = #rune "U",
|
||||
V = #rune "V",
|
||||
W = #rune "W",
|
||||
X = #rune "X",
|
||||
Y = #rune "Y",
|
||||
Z = #rune "Z",
|
||||
|
||||
LWIN = 0x5B,
|
||||
RWIN = 0x5C,
|
||||
APPS = 0x5D,
|
||||
|
||||
NUMPAD0 = 0x60,
|
||||
NUMPAD1 = 0x61,
|
||||
NUMPAD2 = 0x62,
|
||||
NUMPAD3 = 0x63,
|
||||
NUMPAD4 = 0x64,
|
||||
NUMPAD5 = 0x65,
|
||||
NUMPAD6 = 0x66,
|
||||
NUMPAD7 = 0x67,
|
||||
NUMPAD8 = 0x68,
|
||||
NUMPAD9 = 0x69,
|
||||
MULTIPLY = 0x6A,
|
||||
ADD = 0x6B,
|
||||
SEPARATOR = 0x6C,
|
||||
SUBTRACT = 0x6D,
|
||||
DECIMAL = 0x6E,
|
||||
DIVIDE = 0x6F,
|
||||
F1 = 0x70,
|
||||
F2 = 0x71,
|
||||
F3 = 0x72,
|
||||
F4 = 0x73,
|
||||
F5 = 0x74,
|
||||
F6 = 0x75,
|
||||
F7 = 0x76,
|
||||
F8 = 0x77,
|
||||
F9 = 0x78,
|
||||
F10 = 0x79,
|
||||
F11 = 0x7A,
|
||||
F12 = 0x7B,
|
||||
F13 = 0x7C,
|
||||
F14 = 0x7D,
|
||||
F15 = 0x7E,
|
||||
F16 = 0x7F,
|
||||
F17 = 0x80,
|
||||
F18 = 0x81,
|
||||
F19 = 0x82,
|
||||
F20 = 0x83,
|
||||
F21 = 0x84,
|
||||
F22 = 0x85,
|
||||
F23 = 0x86,
|
||||
F24 = 0x87,
|
||||
|
||||
NUMLOCK = 0x90,
|
||||
SCROLL = 0x91,
|
||||
|
||||
LSHIFT = 0xA0,
|
||||
RSHIFT = 0xA1,
|
||||
LCONTROL = 0xA2,
|
||||
RCONTROL = 0xA3,
|
||||
LMENU = 0xA4,
|
||||
RMENU = 0xA5,
|
||||
PROCESSKEY = 0xE5,
|
||||
ATTN = 0xF6,
|
||||
CRSEL = 0xF7,
|
||||
EXSEL = 0xF8,
|
||||
EREOF = 0xF9,
|
||||
PLAY = 0xFA,
|
||||
ZOOM = 0xFB,
|
||||
NONAME = 0xFC,
|
||||
PA1 = 0xFD,
|
||||
OEM_CLEAR = 0xFE,
|
||||
}
|
||||
|
||||
@@ -840,7 +840,11 @@ void init_type_info_types(Checker *c) {
|
||||
if (t_type_info == NULL) {
|
||||
String type_info_str = make_string("Type_Info");
|
||||
Entity *e = current_scope_lookup_entity(c->global_scope, type_info_str);
|
||||
GB_ASSERT_MSG(e != NULL, "Internal Compiler Error: Could not find type declaration for `Type_Info`");
|
||||
if (e == NULL) {
|
||||
gb_printf_err("Internal Compiler Error: Could not find type declaration for `Type_Info`\n");
|
||||
gb_printf_err("Is `runtime.odin` missing from the `core` directory?\n");
|
||||
gb_exit(1);
|
||||
}
|
||||
t_type_info = e->type;
|
||||
t_type_info_ptr = make_type_pointer(c->allocator, t_type_info);
|
||||
|
||||
@@ -849,7 +853,10 @@ void init_type_info_types(Checker *c) {
|
||||
t_type_info_member = record->other_fields[0]->type;
|
||||
t_type_info_member_ptr = make_type_pointer(c->allocator, t_type_info_member);
|
||||
|
||||
GB_ASSERT_MSG(record->field_count == 16, "Internal Compiler Error: Invalid `Type_Info` layout");
|
||||
if (record->field_count != 16) {
|
||||
gb_printf_err("Internal Compiler Error: Invalid `Type_Info` layout\n");
|
||||
gb_exit(1);
|
||||
}
|
||||
t_type_info_named = record->fields[ 1]->type;
|
||||
t_type_info_integer = record->fields[ 2]->type;
|
||||
t_type_info_float = record->fields[ 3]->type;
|
||||
|
||||
@@ -2741,6 +2741,45 @@ b32 try_add_import_path(Parser *p, String path, String rel_path, TokenPos pos) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
|
||||
isize str_len = base_dir.len+path.len;
|
||||
u8 *str = gb_alloc_array(gb_heap_allocator(), u8, str_len+1);
|
||||
defer (gb_free(gb_heap_allocator(), str));
|
||||
|
||||
gb_memcopy(str, base_dir.text, base_dir.len);
|
||||
gb_memcopy(str+base_dir.len, path.text, path.len);
|
||||
str[str_len] = '\0';
|
||||
// HACK(bill): memory leak
|
||||
char *path_str = gb_path_get_full_name(a, cast(char *)str);
|
||||
return make_string(path_str);
|
||||
}
|
||||
|
||||
String get_fullpath_core(gbAllocator a, String path) {
|
||||
char buf[300] = {};
|
||||
u32 buf_len = GetModuleFileNameA(GetModuleHandleA(NULL), buf, gb_size_of(buf));
|
||||
for (isize i = buf_len-1; i >= 0; i--) {
|
||||
if (buf[i] == '\\' ||
|
||||
buf[i] == '/') {
|
||||
break;
|
||||
}
|
||||
buf_len--;
|
||||
}
|
||||
|
||||
char core[] = "core/";
|
||||
isize core_len = gb_size_of(core)-1;
|
||||
|
||||
isize str_len = buf_len + core_len + path.len;
|
||||
u8 *str = gb_alloc_array(gb_heap_allocator(), u8, str_len+1);
|
||||
defer (gb_free(gb_heap_allocator(), str));
|
||||
|
||||
gb_memcopy(str, buf, buf_len);
|
||||
gb_memcopy(str+buf_len, core, core_len);
|
||||
gb_memcopy(str+buf_len+core_len, path.text, path.len);
|
||||
str[str_len] = '\0';
|
||||
// HACK(bill): memory leak
|
||||
char *path_str = gb_path_get_full_name(a, cast(char *)str);
|
||||
return make_string(path_str);}
|
||||
|
||||
// NOTE(bill): Returns true if it's added
|
||||
b32 try_add_foreign_system_library_path(Parser *p, String import_file) {
|
||||
gb_for_array(i, p->system_libraries) {
|
||||
@@ -2803,6 +2842,7 @@ void parse_file(Parser *p, AstFile *f) {
|
||||
}
|
||||
base_dir.len--;
|
||||
}
|
||||
gbAllocator allocator = gb_heap_allocator(); // TODO(bill): Change this allocator
|
||||
|
||||
f->decls = parse_stmt_list(f);
|
||||
|
||||
@@ -2819,25 +2859,27 @@ void parse_file(Parser *p, AstFile *f) {
|
||||
String file_str = id->relpath.string;
|
||||
|
||||
if (!is_import_path_valid(file_str)) {
|
||||
syntax_error(ast_node_token(node), "Invalid `load` path");
|
||||
if (id->is_load) {
|
||||
syntax_error(ast_node_token(node), "Invalid #load path");
|
||||
} else {
|
||||
syntax_error(ast_node_token(node), "Invalid #import path");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
isize str_len = base_dir.len+file_str.len;
|
||||
u8 *str = gb_alloc_array(gb_heap_allocator(), u8, str_len+1);
|
||||
defer (gb_free(gb_heap_allocator(), str));
|
||||
|
||||
gb_memcopy(str, base_dir.text, base_dir.len);
|
||||
gb_memcopy(str+base_dir.len, file_str.text, file_str.len);
|
||||
str[str_len] = '\0';
|
||||
// HACK(bill): memory leak
|
||||
char *path_str = gb_path_get_full_name(gb_heap_allocator(), cast(char *)str);
|
||||
String import_file = make_string(path_str);
|
||||
String import_file = {};
|
||||
String rel_path = get_fullpath_relative(allocator, base_dir, file_str);
|
||||
import_file = rel_path;
|
||||
if (!gb_file_exists(cast(char *)rel_path.text)) { // NOTE(bill): This should be null terminated
|
||||
String abs_path = get_fullpath_core(allocator, file_str);
|
||||
if (gb_file_exists(cast(char *)abs_path.text)) {
|
||||
import_file = abs_path;
|
||||
}
|
||||
}
|
||||
|
||||
id->fullpath = import_file;
|
||||
if (!try_add_import_path(p, import_file, file_str, ast_node_token(node).pos)) {
|
||||
// gb_free(gb_heap_allocator(), import_file.text);
|
||||
}
|
||||
try_add_import_path(p, import_file, file_str, ast_node_token(node).pos);
|
||||
|
||||
} else if (node->kind == AstNode_ForeignSystemLibrary) {
|
||||
auto *id = &node->ForeignSystemLibrary;
|
||||
String file_str = id->filepath.string;
|
||||
@@ -2862,13 +2904,11 @@ ParseFileError parse_files(Parser *p, char *init_filename) {
|
||||
gb_array_append(p->imports, init_imported_file);
|
||||
p->init_fullpath = init_fullpath;
|
||||
|
||||
// {
|
||||
// // IMPORTANT TODO(bill): Don't embed this, do it relative to the .exe
|
||||
// char *path = gb_path_get_full_name(gb_heap_allocator(), "W:/Odin/core/__runtime.odin");
|
||||
// String s = make_string(path);
|
||||
// ImportedFile runtime_file = {s, s, init_pos};
|
||||
// gb_array_append(p->imports, runtime_file);
|
||||
// }
|
||||
{
|
||||
String s = get_fullpath_core(gb_heap_allocator(), make_string("runtime.odin"));
|
||||
ImportedFile runtime_file = {s, s, init_pos};
|
||||
gb_array_append(p->imports, runtime_file);
|
||||
}
|
||||
|
||||
gb_for_array(i, p->imports) {
|
||||
String import_path = p->imports[i].path;
|
||||
|
||||
@@ -13,8 +13,9 @@ typedef struct String {
|
||||
gb_inline String make_string(u8 *text, isize len) {
|
||||
String s;
|
||||
s.text = text;
|
||||
if (len < 0)
|
||||
if (len < 0) {
|
||||
len = gb_strlen(cast(char *)text);
|
||||
}
|
||||
s.len = len;
|
||||
return s;
|
||||
}
|
||||
|
||||
45
syntax.odin
45
syntax.odin
@@ -1,45 +0,0 @@
|
||||
main :: proc(args: []string) -> i32 {
|
||||
if args.count < 2 {
|
||||
io.println("Please specify a .odin file");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for arg_index := 1; arg_index < args.count; arg_index++ {
|
||||
arg := args[arg_index];
|
||||
filename := arg;
|
||||
ext := filepath.path_extension(filename);
|
||||
if (ext != "odin") {
|
||||
io.println("File is not a .odin file");
|
||||
return 1;
|
||||
}
|
||||
output_name := filepath.change_extension(filename, "c");
|
||||
|
||||
parser: Parser;
|
||||
err: Error;
|
||||
parser, err = make_parser(filename);
|
||||
if err {
|
||||
handle_error();
|
||||
}
|
||||
defer destroy_parser(*parser);
|
||||
|
||||
root_node := parse_statement_list(*parser, null);
|
||||
|
||||
code_generator: CodeGenerator;
|
||||
code_generator, err = make_code_generator(*parser, root);
|
||||
if err {
|
||||
handle_error();
|
||||
}
|
||||
defer destroy_code_generator(*code_generator);
|
||||
|
||||
output: File;
|
||||
output, err = file_create(output_nameu);
|
||||
if err {
|
||||
handle_error();
|
||||
}
|
||||
defer file_close(*output);
|
||||
|
||||
convert_to_c_code(*code_generator, root, *output);
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
Reference in New Issue
Block a user