mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-13 01:21:38 -07:00
Remove len(), cap() and replace with selectors; fix defer in match
This commit is contained in:
+6
-2
@@ -1,6 +1,10 @@
|
||||
#load "basic.odin"
|
||||
|
||||
main :: proc() {
|
||||
println("% % % %", "Hellope", true, 6.28, [4]int{1, 2, 3, 4})
|
||||
println("%0 %1 %0", "Hellope", 34)
|
||||
println("% % % %", "Hellope", true, 6.28, {4}int{1, 2, 3, 4})
|
||||
x: struct #ordered {
|
||||
x, y: int
|
||||
z: f32
|
||||
}
|
||||
println("%", x)
|
||||
}
|
||||
|
||||
+2
-2
@@ -31,7 +31,7 @@ file_close :: proc(f: ^File) {
|
||||
|
||||
file_write :: proc(f: ^File, buf: []byte) -> bool {
|
||||
bytes_written: i32
|
||||
return WriteFile(f.handle, ^buf[0], len(buf) as i32, ^bytes_written, null) != 0
|
||||
return WriteFile(f.handle, ^buf[0], buf.count as i32, ^bytes_written, null) != 0
|
||||
}
|
||||
|
||||
File_Standard :: type enum {
|
||||
@@ -95,7 +95,7 @@ read_entire_file :: proc(name: string) -> (string, bool) {
|
||||
|
||||
ReadFile(f.handle as HANDLE, ^data[total_read], to_read, ^single_read_length, null)
|
||||
if single_read_length <= 0 {
|
||||
delete(data)
|
||||
free(^data[0])
|
||||
return "", false
|
||||
}
|
||||
|
||||
|
||||
+175
-53
@@ -3,22 +3,12 @@
|
||||
#load "file.odin"
|
||||
|
||||
print_byte_buffer :: proc(buf: ^[]byte, b: []byte) {
|
||||
// NOTE(bill): This is quite a hack
|
||||
// TODO(bill): Should I allow the raw editing of a slice by exposing its
|
||||
// internal members?
|
||||
Raw_Bytes :: struct #ordered {
|
||||
data: ^byte
|
||||
len: int
|
||||
cap: int
|
||||
}
|
||||
|
||||
slice := buf as ^Raw_Bytes
|
||||
if slice.len < slice.cap {
|
||||
n := min(slice.cap-slice.len, len(b))
|
||||
if buf.count < buf.capacity {
|
||||
n := min(buf.capacity-buf.count, b.count)
|
||||
if n > 0 {
|
||||
offset := ptr_offset(slice.data, slice.len)
|
||||
offset := ptr_offset(buf.data, buf.count)
|
||||
memory_copy(offset, ^b[0], n)
|
||||
slice.len += n
|
||||
buf.count += n
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,7 +19,7 @@ print_string_to_buffer :: proc(buf: ^[]byte, s: string) {
|
||||
|
||||
|
||||
byte_reverse :: proc(b: []byte) {
|
||||
n := len(b)
|
||||
n := b.count
|
||||
for i := 0; i < n/2; i++ {
|
||||
b[i], b[n-1-i] = b[n-1-i], b[i]
|
||||
}
|
||||
@@ -184,6 +174,128 @@ print__f64 :: proc(buffer: ^[]byte, f: f64, decimal_places: int) {
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -197,7 +309,7 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) {
|
||||
case Struct:
|
||||
print_string_to_buffer(buf, info.name)
|
||||
print_string_to_buffer(buf, "{")
|
||||
for i := 0; i < len(b.fields); i++ {
|
||||
for i := 0; i < b.fields.count; i++ {
|
||||
f := b.fields[i];
|
||||
if i > 0 {
|
||||
print_string_to_buffer(buf, ", ")
|
||||
@@ -282,7 +394,9 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) {
|
||||
|
||||
case Array:
|
||||
print_string_to_buffer(buf, "[")
|
||||
for i := 0; i < info.len; i++ {
|
||||
defer print_string_to_buffer(buf, "]")
|
||||
|
||||
for i := 0; i < info.count; i++ {
|
||||
if i > 0 {
|
||||
print_string_to_buffer(buf, ", ")
|
||||
}
|
||||
@@ -292,55 +406,66 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) {
|
||||
elem.type_info = info.elem
|
||||
print_any_to_buffer(buf, elem)
|
||||
}
|
||||
print_string_to_buffer(buf, "]")
|
||||
|
||||
case Slice:
|
||||
slice := arg.data as ^struct { data: rawptr; len, cap: int }
|
||||
slice := arg.data as ^[]byte
|
||||
print_string_to_buffer(buf, "[")
|
||||
for i := 0; i < slice.len; i++ {
|
||||
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 = (slice.data as int + i*info.elem_size) as rawptr
|
||||
elem.data = ptr_offset(slice.data, i*info.elem_size)
|
||||
elem.type_info = info.elem
|
||||
print_any_to_buffer(buf, elem)
|
||||
}
|
||||
print_string_to_buffer(buf, "]")
|
||||
|
||||
case Vector:
|
||||
print_string_to_buffer(buf, "<")
|
||||
for i := 0; i < info.len; i++ {
|
||||
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.data = ptr_offset(arg.data as ^byte, i*info.elem_size)
|
||||
elem.type_info = info.elem
|
||||
print_any_to_buffer(buf, elem)
|
||||
}
|
||||
print_string_to_buffer(buf, ">")
|
||||
|
||||
|
||||
case Struct:
|
||||
print_string_to_buffer(buf, "(struct ")
|
||||
for i := 0; i < len(info.fields); i++ {
|
||||
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)
|
||||
}
|
||||
print_string_to_buffer(buf, ")")
|
||||
case Union: print_string_to_buffer(buf, "(union)")
|
||||
case Raw_Union: print_string_to_buffer(buf, "(raw_union)")
|
||||
|
||||
case Union:
|
||||
print_string_to_buffer(buf, "(union)")
|
||||
case Raw_Union:
|
||||
print_string_to_buffer(buf, "(raw_union)")
|
||||
case Procedure:
|
||||
print_string_to_buffer(buf, "(procedure 0x")
|
||||
print_type_to_buffer(buf, arg.type_info)
|
||||
print_string_to_buffer(buf, " @ 0x")
|
||||
print_pointer_to_buffer(buf, (arg.data as ^rawptr)^)
|
||||
print_string_to_buffer(buf, ")")
|
||||
|
||||
default:
|
||||
print_string_to_buffer(buf, "")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,7 +498,7 @@ print_to_buffer :: proc(buf: ^[]byte, fmt: string, args: ..any) {
|
||||
parse_int :: proc(s: string, offset: int) -> (int, int) {
|
||||
result := 0
|
||||
|
||||
for ; offset < len(s); offset++ {
|
||||
for ; offset < s.count; offset++ {
|
||||
c := s[offset] as rune
|
||||
if !is_digit(c) {
|
||||
break
|
||||
@@ -389,8 +514,9 @@ print_to_buffer :: proc(buf: ^[]byte, fmt: string, args: ..any) {
|
||||
prev := 0
|
||||
implicit_index := 0
|
||||
|
||||
for i := 0; i < len(fmt); i++ {
|
||||
for i := 0; i < fmt.count; i++ {
|
||||
r := fmt[i] as rune
|
||||
index := implicit_index
|
||||
|
||||
if r != #rune "%" {
|
||||
continue
|
||||
@@ -398,26 +524,22 @@ print_to_buffer :: proc(buf: ^[]byte, fmt: string, args: ..any) {
|
||||
|
||||
print_string_to_buffer(buf, fmt[prev:i])
|
||||
i++ // Skip %
|
||||
if i >= len(fmt) {
|
||||
return
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
next := fmt[i] as rune
|
||||
if next == #rune "%" {
|
||||
print_string_to_buffer(buf, "%")
|
||||
i++
|
||||
prev = i
|
||||
continue
|
||||
}
|
||||
|
||||
index := implicit_index
|
||||
set_prev := true
|
||||
|
||||
if is_digit(next) {
|
||||
index, i = parse_int(fmt, i)
|
||||
}
|
||||
|
||||
if 0 <= index && index < len(args) {
|
||||
if 0 <= index && index < args.count {
|
||||
print_any_to_buffer(buf, args[index])
|
||||
implicit_index = index+1
|
||||
} else {
|
||||
|
||||
+95
-76
@@ -11,6 +11,8 @@ Type_Info :: union {
|
||||
}
|
||||
Record :: struct #ordered {
|
||||
fields: []Member
|
||||
packed: bool
|
||||
ordered: bool
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +40,7 @@ Type_Info :: union {
|
||||
Array: struct #ordered {
|
||||
elem: ^Type_Info
|
||||
elem_size: int
|
||||
len: int
|
||||
count: int
|
||||
}
|
||||
Slice: struct #ordered {
|
||||
elem: ^Type_Info
|
||||
@@ -47,7 +49,7 @@ Type_Info :: union {
|
||||
Vector: struct #ordered {
|
||||
elem: ^Type_Info
|
||||
elem_size: int
|
||||
len: int
|
||||
count: int
|
||||
}
|
||||
Tuple: Record
|
||||
Struct: Record
|
||||
@@ -81,7 +83,7 @@ heap_alloc :: proc(len: int) -> rawptr {
|
||||
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len)
|
||||
}
|
||||
|
||||
heap_dealloc :: proc(ptr: rawptr) {
|
||||
heap_free :: proc(ptr: rawptr) {
|
||||
_ = HeapFree(GetProcessHeap(), 0, ptr)
|
||||
}
|
||||
|
||||
@@ -108,18 +110,18 @@ memory_copy :: proc(dst, src: rawptr, len: int) #inline {
|
||||
}
|
||||
|
||||
__string_eq :: proc(a, b: string) -> bool {
|
||||
if len(a) != len(b) {
|
||||
if a.count != b.count {
|
||||
return false
|
||||
}
|
||||
if ^a[0] == ^b[0] {
|
||||
return true
|
||||
}
|
||||
return memory_compare(^a[0], ^b[0], len(a)) == 0
|
||||
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(len(a), len(b))
|
||||
n := min(a.count, b.count)
|
||||
|
||||
fast := n/size_of(int) + 1
|
||||
offset := (fast-1)*size_of(int)
|
||||
@@ -159,20 +161,64 @@ __string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >
|
||||
|
||||
|
||||
|
||||
|
||||
Allocation_Mode :: enum {
|
||||
ALLOC,
|
||||
DEALLOC,
|
||||
DEALLOC_ALL,
|
||||
RESIZE,
|
||||
__assert :: proc(msg: string) {
|
||||
file_write(file_get_standard(File_Standard.ERROR), msg as []byte)
|
||||
__debug_trap()
|
||||
}
|
||||
|
||||
Allocator_Proc :: type proc(allocator_data: rawptr, mode: Allocation_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64) -> rawptr
|
||||
__bounds_check_error :: proc(file: string, line, column: int,
|
||||
index, count: int) {
|
||||
if 0 <= index && index < count {
|
||||
return
|
||||
}
|
||||
// TODO(bill): Probably reduce the need for `print` in the runtime if possible
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
println_err("%(%:%) Invalid substring indices: [%:%:%]",
|
||||
file, line, column, low, high)
|
||||
__debug_trap()
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Allocator :: struct {
|
||||
procedure: Allocator_Proc;
|
||||
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
|
||||
}
|
||||
|
||||
@@ -180,24 +226,26 @@ Allocator :: struct {
|
||||
Context :: struct {
|
||||
thread_ptr: rawptr
|
||||
|
||||
allocator: Allocator
|
||||
|
||||
user_data: rawptr
|
||||
user_index: int
|
||||
|
||||
allocator: Allocator
|
||||
}
|
||||
|
||||
#thread_local context: Context
|
||||
#thread_local __context: Context
|
||||
|
||||
|
||||
DEFAULT_ALIGNMENT :: 2*size_of(int)
|
||||
|
||||
|
||||
__check_context :: proc() {
|
||||
if context.allocator.procedure == null {
|
||||
context.allocator = __default_allocator()
|
||||
__check_context :: proc(c: ^Context) {
|
||||
assert(c != null)
|
||||
if c.allocator.procedure == null {
|
||||
c.allocator = __default_allocator()
|
||||
}
|
||||
if context.thread_ptr == null {
|
||||
if c.thread_ptr == null {
|
||||
// TODO(bill):
|
||||
// context.thread_ptr = current_thread_pointer()
|
||||
// c.thread_ptr = current_thread_pointer()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,28 +253,28 @@ __check_context :: proc() {
|
||||
alloc :: proc(size: int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT) }
|
||||
|
||||
alloc_align :: proc(size, alignment: int) -> rawptr #inline {
|
||||
__check_context()
|
||||
a := context.allocator
|
||||
return a.procedure(a.data, Allocation_Mode.ALLOC, size, alignment, null, 0, 0)
|
||||
__check_context(^__context)
|
||||
a := __context.allocator
|
||||
return a.procedure(a.data, Allocator.Mode.ALLOC, size, alignment, null, 0, 0)
|
||||
}
|
||||
|
||||
dealloc :: proc(ptr: rawptr) #inline {
|
||||
__check_context()
|
||||
a := context.allocator
|
||||
_ = a.procedure(a.data, Allocation_Mode.DEALLOC, 0, 0, ptr, 0, 0)
|
||||
free :: proc(ptr: rawptr) #inline {
|
||||
__check_context(^__context)
|
||||
a := __context.allocator
|
||||
_ = a.procedure(a.data, Allocator.Mode.FREE, 0, 0, ptr, 0, 0)
|
||||
}
|
||||
dealloc_all :: proc(ptr: rawptr) #inline {
|
||||
__check_context()
|
||||
a := context.allocator
|
||||
_ = a.procedure(a.data, Allocation_Mode.DEALLOC_ALL, 0, 0, ptr, 0, 0)
|
||||
free_all :: proc() #inline {
|
||||
__check_context(^__context)
|
||||
a := __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 {
|
||||
__check_context()
|
||||
a := context.allocator
|
||||
return a.procedure(a.data, Allocation_Mode.RESIZE, new_size, alignment, ptr, old_size, 0)
|
||||
__check_context(^__context)
|
||||
a := __context.allocator
|
||||
return a.procedure(a.data, Allocator.Mode.RESIZE, new_size, alignment, ptr, old_size, 0)
|
||||
}
|
||||
|
||||
|
||||
@@ -237,7 +285,7 @@ default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment:
|
||||
}
|
||||
|
||||
if new_size == 0 {
|
||||
dealloc(old_memory)
|
||||
free(old_memory)
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -251,24 +299,24 @@ default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment:
|
||||
}
|
||||
|
||||
memory_copy(new_memory, old_memory, min(old_size, new_size));
|
||||
dealloc(old_memory)
|
||||
free(old_memory)
|
||||
return new_memory
|
||||
}
|
||||
|
||||
|
||||
__default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocation_Mode,
|
||||
__default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
|
||||
using Allocation_Mode
|
||||
using Allocator.Mode
|
||||
match mode {
|
||||
case ALLOC:
|
||||
return heap_alloc(size)
|
||||
case RESIZE:
|
||||
return default_resize_align(old_memory, old_size, size, alignment)
|
||||
case DEALLOC:
|
||||
heap_dealloc(old_memory)
|
||||
case FREE:
|
||||
heap_free(old_memory)
|
||||
return null
|
||||
case DEALLOC_ALL:
|
||||
case FREE_ALL:
|
||||
// NOTE(bill): Does nothing
|
||||
}
|
||||
|
||||
@@ -277,40 +325,11 @@ __default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocation_Mode,
|
||||
|
||||
__default_allocator :: proc() -> Allocator {
|
||||
return Allocator{
|
||||
__default_allocator_proc,
|
||||
null,
|
||||
procedure = __default_allocator_proc,
|
||||
data = null,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
__assert :: proc(msg: string) {
|
||||
file_write(file_get_standard(File_Standard.ERROR), msg as []byte)
|
||||
__debug_trap()
|
||||
}
|
||||
|
||||
__bounds_check_error :: proc(file: string, line, column: int,
|
||||
index, count: int) {
|
||||
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) {
|
||||
print_err("%(%:%) Invalid slice indices: [%:%:%]\n",
|
||||
file, line, column, low, high, max)
|
||||
__debug_trap()
|
||||
}
|
||||
__substring_expr_error :: proc(file: string, line, column: int,
|
||||
low, high: int) {
|
||||
print_err("%(%:%) Invalid substring indices: [%:%:%]\n",
|
||||
file, line, column, low, high)
|
||||
__debug_trap()
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -124,7 +124,6 @@ enum BuiltinProcId {
|
||||
|
||||
BuiltinProc_new,
|
||||
BuiltinProc_new_slice,
|
||||
BuiltinProc_delete,
|
||||
|
||||
BuiltinProc_size_of,
|
||||
BuiltinProc_size_of_val,
|
||||
@@ -139,8 +138,6 @@ enum BuiltinProcId {
|
||||
BuiltinProc_compile_assert,
|
||||
BuiltinProc_assert,
|
||||
|
||||
BuiltinProc_len,
|
||||
BuiltinProc_cap,
|
||||
BuiltinProc_copy,
|
||||
BuiltinProc_append,
|
||||
|
||||
@@ -168,7 +165,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
|
||||
|
||||
{STR_LIT("new"), 1, false, Expr_Expr},
|
||||
{STR_LIT("new_slice"), 2, true, Expr_Expr},
|
||||
{STR_LIT("delete"), 1, false, Expr_Stmt},
|
||||
|
||||
{STR_LIT("size_of"), 1, false, Expr_Expr},
|
||||
{STR_LIT("size_of_val"), 1, false, Expr_Expr},
|
||||
@@ -183,8 +179,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
|
||||
{STR_LIT("compile_assert"), 1, false, Expr_Stmt},
|
||||
{STR_LIT("assert"), 1, false, Expr_Stmt},
|
||||
|
||||
{STR_LIT("len"), 1, false, Expr_Expr},
|
||||
{STR_LIT("cap"), 1, false, Expr_Expr},
|
||||
{STR_LIT("copy"), 2, false, Expr_Expr},
|
||||
{STR_LIT("append"), 2, false, Expr_Expr},
|
||||
|
||||
|
||||
@@ -2095,21 +2095,6 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
operand->mode = Addressing_Value;
|
||||
operand->type = make_type_slice(c->allocator, type);
|
||||
} break;
|
||||
case BuiltinProc_delete: {
|
||||
// delete :: proc(ptr: ^T)
|
||||
Type *type = get_base_type(operand->type);
|
||||
if (!is_type_pointer(type) && !is_type_slice(type)) {
|
||||
gbString type_str = type_to_string(operand->type);
|
||||
defer (gb_string_free(type_str));
|
||||
error(&c->error_collector, ast_node_token(call),
|
||||
"Expected a pointer or slice to `delete`, got `%s`",
|
||||
type_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
operand->mode = Addressing_NoValue;
|
||||
operand->type = NULL;
|
||||
} break;
|
||||
|
||||
case BuiltinProc_size_of: {
|
||||
// size_of :: proc(Type) -> int
|
||||
@@ -2289,58 +2274,6 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
}
|
||||
break;
|
||||
|
||||
// TODO(bill): Should these be procedures and are their names appropriate?
|
||||
case BuiltinProc_len:
|
||||
case BuiltinProc_cap: {
|
||||
Type *t = get_base_type(operand->type);
|
||||
|
||||
AddressingMode mode = Addressing_Invalid;
|
||||
ExactValue value = {};
|
||||
|
||||
switch (t->kind) {
|
||||
case Type_Basic:
|
||||
if (id == BuiltinProc_len) {
|
||||
if (is_type_string(t)) {
|
||||
if (operand->mode == Addressing_Constant) {
|
||||
mode = Addressing_Constant;
|
||||
value = make_exact_value_integer(operand->value.value_string);
|
||||
} else {
|
||||
mode = Addressing_Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_Array:
|
||||
mode = Addressing_Constant;
|
||||
value = make_exact_value_integer(t->Array.count);
|
||||
break;
|
||||
|
||||
case Type_Vector:
|
||||
mode = Addressing_Constant;
|
||||
value = make_exact_value_integer(t->Vector.count);
|
||||
break;
|
||||
|
||||
case Type_Slice:
|
||||
mode = Addressing_Value;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mode == Addressing_Invalid) {
|
||||
gbString str = expr_to_string(operand->expr);
|
||||
error(&c->error_collector, ast_node_token(operand->expr),
|
||||
"Invalid expression `%s` for `%.*s`",
|
||||
str, LIT(bp->name));
|
||||
gb_string_free(str);
|
||||
return false;
|
||||
}
|
||||
|
||||
operand->mode = mode;
|
||||
operand->type = t_int;
|
||||
operand->value = value;
|
||||
|
||||
} break;
|
||||
|
||||
case BuiltinProc_copy: {
|
||||
// copy :: proc(x, y: []Type) -> int
|
||||
Type *dest_type = NULL, *src_type = NULL;
|
||||
|
||||
+81
-3
@@ -350,6 +350,7 @@ gb_global Type *t_untyped_rune = &basic_types[Basic_UntypedRune];
|
||||
gb_global Type *t_byte = &basic_type_aliases[Basic_byte];
|
||||
gb_global Type *t_rune = &basic_type_aliases[Basic_rune];
|
||||
|
||||
|
||||
gb_global Type *t_type_info = NULL;
|
||||
gb_global Type *t_type_info_ptr = NULL;
|
||||
gb_global Type *t_type_info_member = NULL;
|
||||
@@ -588,7 +589,9 @@ b32 are_types_identical(Type *x, Type *y) {
|
||||
case TypeRecord_Struct:
|
||||
case TypeRecord_RawUnion:
|
||||
case TypeRecord_Union:
|
||||
if (x->Record.field_count == y->Record.field_count) {
|
||||
if (x->Record.field_count == y->Record.field_count &&
|
||||
x->Record.struct_is_packed == y->Record.struct_is_packed &&
|
||||
x->Record.struct_is_ordered == y->Record.struct_is_ordered) {
|
||||
for (isize i = 0; i < x->Record.field_count; i++) {
|
||||
if (!are_types_identical(x->Record.fields[i]->type, y->Record.fields[i]->type)) {
|
||||
return false;
|
||||
@@ -709,6 +712,8 @@ void selection_add_index(Selection *s, isize index) {
|
||||
|
||||
gb_global Entity *entity__any_type_info = NULL;
|
||||
gb_global Entity *entity__any_data = NULL;
|
||||
gb_global Entity *entity__string_data = NULL;
|
||||
gb_global Entity *entity__string_count = NULL;
|
||||
|
||||
Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection sel = empty_selection) {
|
||||
GB_ASSERT(type_ != NULL);
|
||||
@@ -717,6 +722,7 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se
|
||||
return empty_selection;
|
||||
}
|
||||
|
||||
gbAllocator a = gb_heap_allocator();
|
||||
Type *type = type_deref(type_);
|
||||
b32 is_ptr = type != type_;
|
||||
type = get_base_type(type);
|
||||
@@ -729,12 +735,12 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se
|
||||
if (entity__any_type_info == NULL) {
|
||||
Token token = {Token_Identifier};
|
||||
token.string = type_info_str;
|
||||
entity__any_type_info = make_entity_field(gb_heap_allocator(), NULL, token, t_type_info_ptr, false, 0);
|
||||
entity__any_type_info = make_entity_field(a, NULL, token, t_type_info_ptr, false, 0);
|
||||
}
|
||||
if (entity__any_data == NULL) {
|
||||
Token token = {Token_Identifier};
|
||||
token.string = data_str;
|
||||
entity__any_data = make_entity_field(gb_heap_allocator(), NULL, token, t_rawptr, false, 1);
|
||||
entity__any_data = make_entity_field(a, NULL, token, t_rawptr, false, 1);
|
||||
}
|
||||
|
||||
if (are_strings_equal(field_name, type_info_str)) {
|
||||
@@ -747,9 +753,81 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se
|
||||
return sel;
|
||||
}
|
||||
} break;
|
||||
case Basic_string: {
|
||||
String data_str = make_string("data");
|
||||
String count_str = make_string("count");
|
||||
if (entity__string_data == NULL) {
|
||||
Token token = {Token_Identifier};
|
||||
token.string = data_str;
|
||||
entity__string_data = make_entity_field(a, NULL, token, make_type_pointer(a, t_byte), false, 0);
|
||||
}
|
||||
|
||||
if (entity__string_count == NULL) {
|
||||
Token token = {Token_Identifier};
|
||||
token.string = count_str;
|
||||
entity__string_count = make_entity_field(a, NULL, token, t_int, false, 1);
|
||||
}
|
||||
|
||||
if (are_strings_equal(field_name, data_str)) {
|
||||
selection_add_index(&sel, 0);
|
||||
sel.entity = entity__string_data;
|
||||
return sel;
|
||||
} else if (are_strings_equal(field_name, count_str)) {
|
||||
selection_add_index(&sel, 1);
|
||||
sel.entity = entity__string_count;
|
||||
return sel;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
return sel;
|
||||
} else if (type->kind == Type_Array) {
|
||||
String count_str = make_string("count");
|
||||
// NOTE(bill):U nderlying memory address cannot be changed
|
||||
if (are_strings_equal(field_name, count_str)) {
|
||||
Token token = {Token_Identifier};
|
||||
token.string = count_str;
|
||||
// HACK(bill): Memory leak
|
||||
sel.entity = make_entity_constant(a, NULL, token, t_int, make_exact_value_integer(type->Array.count));
|
||||
return sel;
|
||||
}
|
||||
} else if (type->kind == Type_Vector) {
|
||||
String count_str = make_string("count");
|
||||
// NOTE(bill): Vectors are not addressable
|
||||
if (are_strings_equal(field_name, count_str)) {
|
||||
Token token = {Token_Identifier};
|
||||
token.string = count_str;
|
||||
// HACK(bill): Memory leak
|
||||
sel.entity = make_entity_constant(a, NULL, token, t_int, make_exact_value_integer(type->Vector.count));
|
||||
return sel;
|
||||
}
|
||||
} else if (type->kind == Type_Slice) {
|
||||
String data_str = make_string("data");
|
||||
String count_str = make_string("count");
|
||||
String capacity_str = make_string("capacity");
|
||||
|
||||
if (are_strings_equal(field_name, data_str)) {
|
||||
selection_add_index(&sel, 0);
|
||||
Token token = {Token_Identifier};
|
||||
token.string = data_str;
|
||||
// HACK(bill): Memory leak
|
||||
sel.entity = make_entity_field(a, NULL, token, make_type_pointer(a, type->Slice.elem), false, 0);
|
||||
return sel;
|
||||
} else if (are_strings_equal(field_name, count_str)) {
|
||||
selection_add_index(&sel, 1);
|
||||
Token token = {Token_Identifier};
|
||||
token.string = count_str;
|
||||
// HACK(bill): Memory leak
|
||||
sel.entity = make_entity_field(a, NULL, token, t_int, false, 1);
|
||||
return sel;
|
||||
} else if (are_strings_equal(field_name, capacity_str)) {
|
||||
selection_add_index(&sel, 2);
|
||||
Token token = {Token_Identifier};
|
||||
token.string = capacity_str;
|
||||
// HACK(bill): Memory leak
|
||||
sel.entity = make_entity_field(a, NULL, token, t_int, false, 2);
|
||||
return sel;
|
||||
}
|
||||
}
|
||||
|
||||
if (type->kind != Type_Record) {
|
||||
|
||||
+13
-3
@@ -330,6 +330,13 @@ void ssa_gen_tree(ssaGen *s) {
|
||||
case TypeRecord_Struct: {
|
||||
tag = ssa_add_local_generated(proc, t_type_info_struct);
|
||||
|
||||
{
|
||||
ssaValue *packed = ssa_make_const_bool(a, t->Record.struct_is_packed);
|
||||
ssaValue *ordered = ssa_make_const_bool(a, t->Record.struct_is_ordered);
|
||||
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, v_one32, t_bool_ptr), packed);
|
||||
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, v_two32, t_bool_ptr), ordered);
|
||||
}
|
||||
|
||||
ssaValue *memory = type_info_member_offset(proc, type_info_member_data, t->Record.field_count, &type_info_member_index);
|
||||
|
||||
type_set_offsets(m->sizes, a, t); // NOTE(bill): Just incase the offsets have not been set yet
|
||||
@@ -456,9 +463,12 @@ void ssa_gen_tree(ssaGen *s) {
|
||||
ssaValue *results = ssa_emit_struct_gep(proc, tag, v_one32, t_type_info_ptr_ptr);
|
||||
ssaValue *variadic = ssa_emit_struct_gep(proc, tag, v_two32, t_bool_ptr);
|
||||
|
||||
|
||||
ssa_emit_store(proc, params, get_type_info_ptr(proc, type_info_data, t->Proc.params));
|
||||
ssa_emit_store(proc, results, get_type_info_ptr(proc, type_info_data, t->Proc.results));
|
||||
if (t->Proc.params) {
|
||||
ssa_emit_store(proc, params, get_type_info_ptr(proc, type_info_data, t->Proc.params));
|
||||
}
|
||||
if (t->Proc.results) {
|
||||
ssa_emit_store(proc, results, get_type_info_ptr(proc, type_info_data, t->Proc.results));
|
||||
}
|
||||
ssa_emit_store(proc, variadic, ssa_make_const_bool(a, t->Proc.variadic));
|
||||
|
||||
// TODO(bill): Type_Info for procedures
|
||||
|
||||
@@ -121,7 +121,7 @@ void ssa_print_encoded_local(ssaFileBuffer *f, String name) {
|
||||
|
||||
void ssa_print_encoded_global(ssaFileBuffer *f, String name, b32 global_scope = false) {
|
||||
ssa_fprintf(f, "@");
|
||||
if (!global_scope) {
|
||||
if (!global_scope && !are_strings_equal(name, make_string("main"))) {
|
||||
ssa_fprintf(f, ".");
|
||||
}
|
||||
ssa_print_escape_string(f, name, true);
|
||||
|
||||
+51
-105
@@ -1116,10 +1116,16 @@ ssaValue *ssa_emit_deep_field_gep(ssaProcedure *proc, Type *type, ssaValue *e, S
|
||||
e = ssa_emit_struct_gep(proc, e, index, make_type_pointer(proc->module->allocator, type));
|
||||
} break;
|
||||
|
||||
case Basic_string:
|
||||
e = ssa_emit_struct_gep(proc, e, index, make_type_pointer(proc->module->allocator, sel.entity->type));
|
||||
break;
|
||||
|
||||
default:
|
||||
GB_PANIC("un-gep-able type");
|
||||
break;
|
||||
}
|
||||
} else if (type->kind == Type_Slice) {
|
||||
e = ssa_emit_struct_gep(proc, e, index, make_type_pointer(proc->module->allocator, sel.entity->type));
|
||||
} else {
|
||||
GB_PANIC("un-gep-able type");
|
||||
}
|
||||
@@ -1159,10 +1165,16 @@ ssaValue *ssa_emit_deep_field_ev(ssaProcedure *proc, Type *type, ssaValue *e, Se
|
||||
e = ssa_emit_struct_ev(proc, e, index, type);
|
||||
} break;
|
||||
|
||||
case Basic_string:
|
||||
e = ssa_emit_struct_ev(proc, e, index, sel.entity->type);
|
||||
break;
|
||||
|
||||
default:
|
||||
GB_PANIC("un-ev-able type");
|
||||
break;
|
||||
}
|
||||
} else if (type->kind == Type_Slice) {
|
||||
e = ssa_emit_struct_gep(proc, e, index, make_type_pointer(proc->module->allocator, sel.entity->type));
|
||||
} else {
|
||||
GB_PANIC("un-ev-able type");
|
||||
}
|
||||
@@ -1194,6 +1206,9 @@ isize ssa_type_info_index(CheckerInfo *info, Type *type) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (entry_index < 0) {
|
||||
gb_printf_err("%s\n", type_to_string(type));
|
||||
}
|
||||
GB_ASSERT(entry_index >= 0);
|
||||
return entry_index;
|
||||
}
|
||||
@@ -1599,7 +1614,7 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg
|
||||
ssaValue *result = ssa_add_local_generated(proc, t_any);
|
||||
|
||||
ssaValue *data = NULL;
|
||||
if (false && value->kind == ssaValue_Instr &&
|
||||
if (value->kind == ssaValue_Instr &&
|
||||
value->Instr.kind == ssaInstr_Load) {
|
||||
// NOTE(bill): Addressable value
|
||||
data = value->Instr.Load.address;
|
||||
@@ -1704,37 +1719,16 @@ void ssa_array_bounds_check(ssaProcedure *proc, Token token, ssaValue *index, ss
|
||||
if ((proc->module->stmt_state_flags & StmtStateFlag_no_bounds_check) != 0) {
|
||||
return;
|
||||
}
|
||||
ssa_emit_comment(proc, make_string("ArrayBoundsCheck"));
|
||||
index = ssa_emit_conv(proc, index, t_int);
|
||||
len = ssa_emit_conv(proc, len, t_int);
|
||||
|
||||
Token le = {Token_LtEq};
|
||||
Token lt = {Token_Lt};
|
||||
Token cmp_and = {Token_And}; // NOTE(bill): Doesn't need to be logical
|
||||
ssaValue *c0 = ssa_emit_comp(proc, le, v_zero, index);
|
||||
ssaValue *c1 = ssa_emit_comp(proc, lt, index, len);
|
||||
ssaValue *cond = ssa_emit_comp(proc, cmp_and, c0, c1);
|
||||
|
||||
ssaBlock *then = ssa_add_block(proc, NULL, make_string("abc.then"));
|
||||
ssaBlock *done = ssa__make_block(proc, NULL, make_string("abc.done"));
|
||||
|
||||
ssa_emit_if(proc, cond, done, then);
|
||||
proc->curr_block = then;
|
||||
|
||||
|
||||
gbAllocator a = proc->module->allocator;
|
||||
ssaValue **args = gb_alloc_array(a, ssaValue *, 5);
|
||||
args[0] = ssa_emit_global_string(proc, token.pos.file);
|
||||
args[1] = ssa_make_const_int(a, token.pos.line);
|
||||
args[2] = ssa_make_const_int(a, token.pos.column);
|
||||
args[3] = index;
|
||||
args[4] = len;
|
||||
args[3] = ssa_emit_conv(proc, index, t_int);
|
||||
args[4] = ssa_emit_conv(proc, len, t_int);
|
||||
|
||||
ssa_emit_global_call(proc, "__bounds_check_error", args, 5);
|
||||
|
||||
ssa_emit_jump(proc, done);
|
||||
gb_array_append(proc->blocks, done);
|
||||
proc->curr_block = done;
|
||||
}
|
||||
|
||||
void ssa_slice_bounds_check(ssaProcedure *proc, Token token, ssaValue *low, ssaValue *high, ssaValue *max, b32 is_substring) {
|
||||
@@ -1742,43 +1736,20 @@ void ssa_slice_bounds_check(ssaProcedure *proc, Token token, ssaValue *low, ssaV
|
||||
return;
|
||||
}
|
||||
|
||||
low = ssa_emit_conv(proc, low, t_int);
|
||||
high = ssa_emit_conv(proc, high, t_int);
|
||||
max = ssa_emit_conv(proc, max, t_int);
|
||||
|
||||
Token le = {Token_LtEq};
|
||||
Token cmp_and = {Token_And}; // NOTE(bill): Doesn't need to be logical
|
||||
ssaValue *c0 = ssa_emit_comp(proc, le, v_zero, low);
|
||||
ssaValue *c1 = ssa_emit_comp(proc, le, low, high);
|
||||
ssaValue *c2 = ssa_emit_comp(proc, le, high, max);
|
||||
ssaValue *cond = NULL;
|
||||
cond = ssa_emit_comp(proc, cmp_and, c0, c1);
|
||||
cond = ssa_emit_comp(proc, cmp_and, cond, c2);
|
||||
|
||||
ssaBlock *then = ssa_add_block(proc, NULL, make_string("seb.then"));
|
||||
ssaBlock *done = ssa__make_block(proc, NULL, make_string("seb.done"));
|
||||
|
||||
ssa_emit_if(proc, cond, done, then);
|
||||
proc->curr_block = then;
|
||||
|
||||
gbAllocator a = proc->module->allocator;
|
||||
ssaValue **args = gb_alloc_array(a, ssaValue *, 6);
|
||||
args[0] = ssa_emit_global_string(proc, token.pos.file);
|
||||
args[1] = ssa_make_const_int(a, token.pos.line);
|
||||
args[2] = ssa_make_const_int(a, token.pos.column);
|
||||
args[3] = low;
|
||||
args[4] = high;
|
||||
args[5] = max;
|
||||
args[3] = ssa_emit_conv(proc, low, t_int);
|
||||
args[4] = ssa_emit_conv(proc, high, t_int);
|
||||
args[5] = ssa_emit_conv(proc, max, t_int);
|
||||
|
||||
if (!is_substring) {
|
||||
ssa_emit_global_call(proc, "__slice_expr_error", args, 6);
|
||||
} else {
|
||||
ssa_emit_global_call(proc, "__substring_expr_error", args, 5);
|
||||
}
|
||||
|
||||
ssa_emit_jump(proc, done);
|
||||
gb_array_append(proc->blocks, done);
|
||||
proc->curr_block = done;
|
||||
}
|
||||
|
||||
|
||||
@@ -2109,26 +2080,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
return ssa_emit_load(proc, slice);
|
||||
} break;
|
||||
|
||||
case BuiltinProc_delete: {
|
||||
ssa_emit_comment(proc, make_string("delete"));
|
||||
// delete :: proc(ptr: ^Type)
|
||||
// delete :: proc(slice: []Type)
|
||||
gbAllocator allocator = proc->module->allocator;
|
||||
|
||||
ssaValue *value = ssa_build_expr(proc, ce->args[0]);
|
||||
|
||||
if (is_type_slice(ssa_type(value))) {
|
||||
Type *etp = get_base_type(ssa_type(value));
|
||||
etp = make_type_pointer(allocator, etp->Slice.elem);
|
||||
value = ssa_emit(proc, ssa_make_instr_extract_value(proc, value, 0, etp));
|
||||
}
|
||||
|
||||
ssaValue **args = gb_alloc_array(allocator, ssaValue *, 1);
|
||||
args[0] = ssa_emit_conv(proc, value, t_rawptr, true);
|
||||
return ssa_emit_global_call(proc, "dealloc", args, 1);
|
||||
} break;
|
||||
|
||||
|
||||
case BuiltinProc_assert: {
|
||||
ssa_emit_comment(proc, make_string("assert"));
|
||||
ssaValue *cond = ssa_build_expr(proc, ce->args[0]);
|
||||
@@ -2174,25 +2125,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
return NULL;
|
||||
} break;
|
||||
|
||||
case BuiltinProc_len: {
|
||||
ssa_emit_comment(proc, make_string("len"));
|
||||
// len :: proc(v: Type) -> int
|
||||
// NOTE(bill): len of an array is a constant expression
|
||||
ssaValue *v = ssa_build_expr(proc, ce->args[0]);
|
||||
Type *t = get_base_type(ssa_type(v));
|
||||
if (t == t_string)
|
||||
return ssa_string_len(proc, v);
|
||||
else if (t->kind == Type_Slice)
|
||||
return ssa_slice_len(proc, v);
|
||||
} break;
|
||||
case BuiltinProc_cap: {
|
||||
ssa_emit_comment(proc, make_string("cap"));
|
||||
// cap :: proc(v: Type) -> int
|
||||
// NOTE(bill): cap of an array is a constant expression
|
||||
ssaValue *v = ssa_build_expr(proc, ce->args[0]);
|
||||
Type *t = get_base_type(ssa_type(v));
|
||||
return ssa_slice_cap(proc, v);
|
||||
} break;
|
||||
case BuiltinProc_copy: {
|
||||
ssa_emit_comment(proc, make_string("copy"));
|
||||
// copy :: proc(dst, src: []Type) -> int
|
||||
@@ -3393,9 +3325,15 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
|
||||
gb_array_append(proc->blocks, body);
|
||||
}
|
||||
proc->curr_block = body;
|
||||
|
||||
// TODO(bill): Handle fallthrough scope exit correctly
|
||||
proc->scope_index++;
|
||||
ssa_push_target_list(proc, done, NULL, fall);
|
||||
ssa_build_stmt_list(proc, cc->stmts);
|
||||
ssa_emit_defer_stmts(proc, ssaDefer_Default, body);
|
||||
ssa_pop_target_list(proc);
|
||||
proc->scope_index--;
|
||||
|
||||
ssa_emit_jump(proc, done);
|
||||
proc->curr_block = next_cond;
|
||||
}
|
||||
@@ -3404,9 +3342,14 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
|
||||
ssa_emit_jump(proc, default_block);
|
||||
gb_array_append(proc->blocks, default_block);
|
||||
proc->curr_block = default_block;
|
||||
|
||||
// TODO(bill): Handle fallthrough scope exit correctly
|
||||
proc->scope_index++;
|
||||
ssa_push_target_list(proc, done, NULL, default_fall);
|
||||
ssa_build_stmt_list(proc, default_stmts);
|
||||
ssa_emit_defer_stmts(proc, ssaDefer_Default, default_block);
|
||||
ssa_pop_target_list(proc);
|
||||
proc->scope_index--;
|
||||
}
|
||||
|
||||
ssa_emit_jump(proc, done);
|
||||
@@ -3490,9 +3433,14 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
|
||||
|
||||
gb_array_append(proc->blocks, body);
|
||||
proc->curr_block = body;
|
||||
|
||||
proc->scope_index++;
|
||||
ssa_push_target_list(proc, done, NULL, NULL);
|
||||
ssa_build_stmt_list(proc, cc->stmts);
|
||||
ssa_emit_defer_stmts(proc, ssaDefer_Default, body);
|
||||
ssa_pop_target_list(proc);
|
||||
proc->scope_index--;
|
||||
|
||||
ssa_emit_jump(proc, done);
|
||||
proc->curr_block = next_cond;
|
||||
}
|
||||
@@ -3501,9 +3449,13 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
|
||||
ssa_emit_jump(proc, default_block);
|
||||
gb_array_append(proc->blocks, default_block);
|
||||
proc->curr_block = default_block;
|
||||
|
||||
proc->scope_index++;
|
||||
ssa_push_target_list(proc, done, NULL, NULL);
|
||||
ssa_build_stmt_list(proc, default_stmts);
|
||||
ssa_emit_defer_stmts(proc, ssaDefer_Default, default_block);
|
||||
ssa_pop_target_list(proc);
|
||||
proc->scope_index--;
|
||||
}
|
||||
|
||||
ssa_emit_jump(proc, done);
|
||||
@@ -3513,24 +3465,18 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
|
||||
|
||||
case_ast_node(bs, BranchStmt, node);
|
||||
ssaBlock *block = NULL;
|
||||
#define branch_case(x) case GB_JOIN2(Token_, x): \
|
||||
for (ssaTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) { \
|
||||
block = GB_JOIN3(t->, x, _); \
|
||||
} break
|
||||
switch (bs->token.kind) {
|
||||
case Token_break: {
|
||||
for (ssaTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) {
|
||||
block = t->break_;
|
||||
}
|
||||
} break;
|
||||
case Token_continue: {
|
||||
for (ssaTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) {
|
||||
block = t->continue_;
|
||||
}
|
||||
} break;
|
||||
case Token_fallthrough: {
|
||||
for (ssaTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) {
|
||||
block = t->fallthrough_;
|
||||
}
|
||||
} break;
|
||||
branch_case(break);
|
||||
branch_case(continue);
|
||||
branch_case(fallthrough);
|
||||
}
|
||||
if (block != NULL && bs->token.kind != Token_fallthrough) {
|
||||
// TODO(bill): Handle fallthrough scope exit correctly
|
||||
// if (block != NULL && bs->token.kind != Token_fallthrough) {
|
||||
if (block != NULL) {
|
||||
ssa_emit_defer_stmts(proc, ssaDefer_Branch, block);
|
||||
}
|
||||
switch (bs->token.kind) {
|
||||
|
||||
+30
-15
@@ -64,6 +64,7 @@ enum ProcTag {
|
||||
ProcTag_foreign = GB_BIT(2),
|
||||
ProcTag_inline = GB_BIT(3),
|
||||
ProcTag_no_inline = GB_BIT(4),
|
||||
ProcTag_no_context = GB_BIT(5),
|
||||
};
|
||||
|
||||
enum VarDeclTag {
|
||||
@@ -1173,14 +1174,16 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name) {
|
||||
|
||||
next_token(f);
|
||||
}
|
||||
} else if (are_strings_equal(tag_name, make_string("inline"))) {
|
||||
check_proc_add_tag(f, tag_expr, tags, ProcTag_inline, tag_name);
|
||||
} else if (are_strings_equal(tag_name, make_string("no_inline"))) {
|
||||
check_proc_add_tag(f, tag_expr, tags, ProcTag_no_inline, tag_name);
|
||||
} else if (are_strings_equal(tag_name, make_string("bounds_check"))) {
|
||||
check_proc_add_tag(f, tag_expr, tags, ProcTag_bounds_check, tag_name);
|
||||
} else if (are_strings_equal(tag_name, make_string("no_bounds_check"))) {
|
||||
check_proc_add_tag(f, tag_expr, tags, ProcTag_no_bounds_check, tag_name);
|
||||
} else if (are_strings_equal(tag_name, make_string("inline"))) {
|
||||
check_proc_add_tag(f, tag_expr, tags, ProcTag_inline, tag_name);
|
||||
} else if (are_strings_equal(tag_name, make_string("no_inline"))) {
|
||||
check_proc_add_tag(f, tag_expr, tags, ProcTag_no_inline, tag_name);
|
||||
} else if (are_strings_equal(tag_name, make_string("no_context"))) {
|
||||
check_proc_add_tag(f, tag_expr, tags, ProcTag_no_context, tag_name);
|
||||
} else {
|
||||
ast_file_err(f, ast_node_token(tag_expr), "Unknown procedure tag");
|
||||
}
|
||||
@@ -1490,17 +1493,16 @@ AstNode *parse_binary_expr(AstFile *f, b32 lhs, i32 prec_in) {
|
||||
}
|
||||
|
||||
switch (op.kind) {
|
||||
// case Token_DoublePrime: {
|
||||
// AstNode *proc = parse_identifier(f);
|
||||
// AstNode *right = parse_binary_expr(f, false, prec+1);
|
||||
// expression->next = right;
|
||||
// gbArray(AstNode *) args;
|
||||
// gb_array_init_reserve(args, gb_arena_allocator(&f->arena), 2);
|
||||
// gb_array_append(args, expression);
|
||||
// gb_array_append(args, right);
|
||||
// expression = make_call_expr(f, proc, args, op, ast_node_token(right), empty_token);
|
||||
// continue;
|
||||
// } break;
|
||||
case Token_DoublePrime: {
|
||||
AstNode *proc = parse_identifier(f);
|
||||
AstNode *right = parse_binary_expr(f, false, prec+1);
|
||||
gbArray(AstNode *) args;
|
||||
gb_array_init_reserve(args, gb_arena_allocator(&f->arena), 2);
|
||||
gb_array_append(args, expression);
|
||||
gb_array_append(args, right);
|
||||
expression = make_call_expr(f, proc, args, op, ast_node_token(right), empty_token);
|
||||
continue;
|
||||
} break;
|
||||
|
||||
case Token_as:
|
||||
case Token_transmute:
|
||||
@@ -2074,6 +2076,18 @@ AstNode *parse_decl(AstFile *f, AstNodeArray names) {
|
||||
AstNodeArray values = NULL;
|
||||
AstNode *type = NULL;
|
||||
|
||||
gb_for_array(i, names) {
|
||||
AstNode *name = names[i];
|
||||
if (name->kind == AstNode_Ident) {
|
||||
String n = name->Ident.string;
|
||||
// NOTE(bill): Check for reserved identifiers
|
||||
if (are_strings_equal(n, make_string("context"))) {
|
||||
ast_file_err(f, ast_node_token(name), "`context` is a reserved identifier");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allow_token(f, Token_Colon)) {
|
||||
if (!allow_token(f, Token_type)) {
|
||||
type = parse_identifier_or_type(f);
|
||||
@@ -2449,6 +2463,7 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
case Token_Rune:
|
||||
case Token_String:
|
||||
case Token_OpenParen:
|
||||
case Token_proc:
|
||||
// Unary Operators
|
||||
case Token_Add:
|
||||
case Token_Sub:
|
||||
|
||||
Reference in New Issue
Block a user