Merge pull request #1 from odin-lang/master

update from master
This commit is contained in:
DanielGavin
2020-12-18 14:19:03 +01:00
committed by GitHub
26 changed files with 518 additions and 251 deletions
+60 -4
View File
@@ -8,6 +8,8 @@ MIN_READ :: 512;
@(private)
SMALL_BUFFER_SIZE :: 64;
// A Buffer is a variable-sized buffer of bytes with a io.Stream interface
// The zero value for Buffer is an empty buffer ready to use.
Buffer :: struct {
buf: [dynamic]byte,
off: int,
@@ -35,6 +37,11 @@ buffer_init_string :: proc(b: ^Buffer, s: string) {
copy(b.buf[:], s);
}
buffer_init_allocator :: proc(b: ^Buffer, len, cap: int, allocator := context.allocator) {
b.buf.allocator = allocator;
reserve(&b.buf, cap);
resize(&b.buf, len);
}
buffer_destroy :: proc(b: ^Buffer) {
delete(b.buf);
@@ -276,6 +283,51 @@ buffer_read_string :: proc(b: ^Buffer, delim: byte) -> (line: string, err: io.Er
return string(slice), err;
}
buffer_write_to :: proc(b: ^Buffer, w: io.Writer) -> (n: i64, err: io.Error) {
b.last_read = .Invalid;
if byte_count := buffer_length(b); byte_count > 0 {
m, e := io.write(w, b.buf[b.off:]);
if m > byte_count {
panic("bytes.buffer_write_to: invalid io.write count");
}
b.off += m;
n = i64(m);
if e != nil {
err = e;
return;
}
if m != byte_count {
err = .Short_Write;
return;
}
}
buffer_reset(b);
return;
}
buffer_read_from :: proc(b: ^Buffer, r: io.Reader) -> (n: i64, err: io.Error) #no_bounds_check {
b.last_read = .Invalid;
for {
i := _buffer_grow(b, MIN_READ);
resize(&b.buf, i);
m, e := io.read(r, b.buf[i:cap(b.buf)]);
if m < 0 {
err = .Negative_Read;
return;
}
resize(&b.buf, i+m);
n += i64(m);
if e == .EOF {
return;
}
if e != nil {
err = e;
return;
}
}
return;
}
buffer_to_stream :: proc(b: ^Buffer) -> (s: io.Stream) {
@@ -327,9 +379,13 @@ _buffer_vtable := &io.Stream_VTable{
buffer_destroy(b);
return nil;
},
// TODO(bill): write_to and read_from
// impl_write_to = nil,
// impl_read_from = nil,
impl_write_to = proc(s: io.Stream, w: io.Writer) -> (n: i64, err: io.Error) {
b := (^Buffer)(s.stream_data);
return buffer_write_to(b, w);
},
impl_read_from = proc(s: io.Stream, r: io.Reader) -> (n: i64, err: io.Error) {
b := (^Buffer)(s.stream_data);
return buffer_read_from(b, r);
},
};
@@ -743,13 +743,12 @@ split_multi :: proc(s: []byte, substrs: [][]byte, skip_empty := false, allocator
return buf;
}
/*
// scrub scruvs invalid utf-8 characters and replaces them with the replacement string
// Adjacent invalid bytes are only replaced once
scrub :: proc(s: []byte, replacement: []byte, allocator := context.allocator) -> []byte {
str := s;
b: Builder;
init_builder(&b, 0, len(s), allocator);
b: Buffer;
buffer_init_allocator(&b, 0, len(s), allocator);
has_error := false;
cursor := 0;
@@ -761,11 +760,11 @@ scrub :: proc(s: []byte, replacement: []byte, allocator := context.allocator) ->
if r == utf8.RUNE_ERROR {
if !has_error {
has_error = true;
write(&b, origin[:cursor]);
buffer_write(&b, origin[:cursor]);
}
} else if has_error {
has_error = false;
write(&b, replacement);
buffer_write(&b, replacement);
origin = origin[cursor:];
cursor = 0;
@@ -775,9 +774,8 @@ scrub :: proc(s: []byte, replacement: []byte, allocator := context.allocator) ->
str = str[w:];
}
return to_string(b);
return buffer_to_bytes(&b);
}
*/
reverse :: proc(s: []byte, allocator := context.allocator) -> []byte {
@@ -795,8 +793,7 @@ reverse :: proc(s: []byte, allocator := context.allocator) -> []byte {
return buf;
}
/*
expand_tabs :: proc(s: string, tab_size: int, allocator := context.allocator) -> string {
expand_tabs :: proc(s: []byte, tab_size: int, allocator := context.allocator) -> []byte {
if tab_size <= 0 {
panic("tab size must be positive");
}
@@ -806,20 +803,20 @@ expand_tabs :: proc(s: string, tab_size: int, allocator := context.allocator) ->
return nil;
}
b: Builder;
init_builder(&b, allocator);
writer := to_writer(&b);
b: Buffer;
buffer_init_allocator(&b, 0, len(s), allocator);
str := s;
column: int;
for len(str) > 0 {
r, w := utf8.decode_rune_in_string(str);
r, w := utf8.decode_rune(str);
if r == '\t' {
expand := tab_size - column%tab_size;
for i := 0; i < expand; i += 1 {
io.write_byte(writer, ' ');
buffer_write_byte(&b, ' ');
}
column += expand;
@@ -830,15 +827,14 @@ expand_tabs :: proc(s: string, tab_size: int, allocator := context.allocator) ->
column += w;
}
io.write_rune(writer, r);
buffer_write_rune(&b, r);
}
str = str[w:];
}
return to_string(b);
return buffer_to_bytes(&b);
}
*/
partition :: proc(str, sep: []byte) -> (head, match, tail: []byte) {
i := index(str, sep);
@@ -853,11 +849,10 @@ partition :: proc(str, sep: []byte) -> (head, match, tail: []byte) {
return;
}
/*
center_justify :: centre_justify; // NOTE(bill): Because Americans exist
// centre_justify returns a string with a pad string at boths sides if the str's rune length is smaller than length
centre_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator) -> string {
// centre_justify returns a byte slice with a pad byte slice at boths sides if the str's rune length is smaller than length
centre_justify :: proc(str: []byte, length: int, pad: []byte, allocator := context.allocator) -> []byte {
n := rune_count(str);
if n >= length || pad == nil {
return clone(str, allocator);
@@ -866,21 +861,18 @@ centre_justify :: proc(str: string, length: int, pad: string, allocator := conte
remains := length-1;
pad_len := rune_count(pad);
b: Builder;
init_builder(&b, allocator);
grow_builder(&b, len(str) + (remains/pad_len + 1)*len(pad));
b: Buffer;
buffer_init_allocator(&b, 0, len(str) + (remains/pad_len + 1)*len(pad), allocator);
w := to_writer(&b);
write_pad_string(&b, pad, pad_len, remains/2);
buffer_write(&b, str);
write_pad_string(&b, pad, pad_len, (remains+1)/2);
write_pad_string(w, pad, pad_len, remains/2);
io.write_string(w, str);
write_pad_string(w, pad, pad_len, (remains+1)/2);
return to_string(b);
return buffer_to_bytes(&b);
}
// left_justify returns a string with a pad string at left side if the str's rune length is smaller than length
left_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator) -> string {
// left_justify returns a byte slice with a pad byte slice at left side if the str's rune length is smaller than length
left_justify :: proc(str: []byte, length: int, pad: []byte, allocator := context.allocator) -> []byte {
n := rune_count(str);
if n >= length || pad == nil {
return clone(str, allocator);
@@ -889,20 +881,17 @@ left_justify :: proc(str: string, length: int, pad: string, allocator := context
remains := length-1;
pad_len := rune_count(pad);
b: Builder;
init_builder(&b, allocator);
grow_builder(&b, len(str) + (remains/pad_len + 1)*len(pad));
b: Buffer;
buffer_init_allocator(&b, 0, len(str) + (remains/pad_len + 1)*len(pad), allocator);
w := to_writer(&b);
buffer_write(&b, str);
write_pad_string(&b, pad, pad_len, remains);
io.write_string(w, str);
write_pad_string(w, pad, pad_len, remains);
return to_string(b);
return buffer_to_bytes(&b);
}
// right_justify returns a string with a pad string at right side if the str's rune length is smaller than length
right_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator) -> string {
// right_justify returns a byte slice with a pad byte slice at right side if the str's rune length is smaller than length
right_justify :: proc(str: []byte, length: int, pad: []byte, allocator := context.allocator) -> []byte {
n := rune_count(str);
if n >= length || pad == nil {
return clone(str, allocator);
@@ -911,39 +900,35 @@ right_justify :: proc(str: string, length: int, pad: string, allocator := contex
remains := length-1;
pad_len := rune_count(pad);
b: Builder;
init_builder(&b, allocator);
grow_builder(&b, len(str) + (remains/pad_len + 1)*len(pad));
b: Buffer;
buffer_init_allocator(&b, 0, len(str) + (remains/pad_len + 1)*len(pad), allocator);
w := to_writer(&b);
write_pad_string(&b, pad, pad_len, remains);
buffer_write(&b, str);
write_pad_string(w, pad, pad_len, remains);
io.write_string(w, str);
return to_string(b);
return buffer_to_bytes(&b);
}
@private
write_pad_string :: proc(w: io.Writer, pad: string, pad_len, remains: int) {
write_pad_string :: proc(b: ^Buffer, pad: []byte, pad_len, remains: int) {
repeats := remains / pad_len;
for i := 0; i < repeats; i += 1 {
io.write_string(w, pad);
buffer_write(b, pad);
}
n := remains % pad_len;
p := pad;
for i := 0; i < n; i += 1 {
r, width := utf8.decode_rune_in_string(p);
io.write_rune(w, r);
r, width := utf8.decode_rune(p);
buffer_write_rune(b, r);
p = p[width:];
}
}
*/
// fields splits the byte slice s around each instance of one or more consecutive white space character, defined by unicode.is_space
+49 -37
View File
@@ -1,14 +1,18 @@
package container
import "intrinsics"
_ :: intrinsics;
Map :: struct(Value: typeid) {
Map :: struct(Key, Value: typeid) where intrinsics.type_is_valid_map_key(Key) {
hash: Array(int),
entries: Array(Map_Entry(Value)),
entries: Array(Map_Entry(Key, Value)),
}
Map_Entry :: struct(Value: typeid) {
key: u64,
Map_Entry :: struct(Key, Value: typeid) where intrinsics.type_is_valid_map_key(Key) {
hash: uintptr,
next: int,
key: Key,
value: Value,
}
@@ -47,28 +51,28 @@ multi_map_remove_all
map_init :: proc{map_init_none, map_init_cap};
map_init_none :: proc(m: ^$M/Map($Value), allocator := context.allocator) {
map_init_none :: proc(m: ^$M/Map($Key, $Value), allocator := context.allocator) {
m.hash.allocator = allocator;
m.entries.allocator = allocator;
}
map_init_cap :: proc(m: ^$M/Map($Value), cap: int, allocator := context.allocator) {
map_init_cap :: proc(m: ^$M/Map($Key, $Value), cap: int, allocator := context.allocator) {
m.hash.allocator = allocator;
m.entries.allocator = allocator;
map_reserve(m, cap);
}
map_delete :: proc(m: $M/Map($Value)) {
map_delete :: proc(m: $M/Map($Key, $Value)) {
array_delete(m.hash);
array_delete(m.entries);
}
map_has :: proc(m: $M/Map($Value), key: u64) -> bool {
map_has :: proc(m: $M/Map($Key, $Value), key: Key) -> bool {
return _map_find_or_fail(m, key) >= 0;
}
map_get :: proc(m: $M/Map($Value), key: u64) -> (res: Value, ok: bool) #optional_ok {
map_get :: proc(m: $M/Map($Key, $Value), key: Key) -> (res: Value, ok: bool) #optional_ok {
i := _map_find_or_fail(m, key);
if i < 0 {
return {}, false;
@@ -76,7 +80,7 @@ map_get :: proc(m: $M/Map($Value), key: u64) -> (res: Value, ok: bool) #optional
return array_get(m.entries, i).value, true;
}
map_get_default :: proc(m: $M/Map($Value), key: u64, default: Value) -> (res: Value, ok: bool) #optional_ok {
map_get_default :: proc(m: $M/Map($Key, $Value), key: Key, default: Value) -> (res: Value, ok: bool) #optional_ok {
i := _map_find_or_fail(m, key);
if i < 0 {
return default, false;
@@ -84,7 +88,7 @@ map_get_default :: proc(m: $M/Map($Value), key: u64, default: Value) -> (res: Va
return array_get(m.entries, i).value, true;
}
map_get_ptr :: proc(m: $M/Map($Value), key: u64) -> ^Value {
map_get_ptr :: proc(m: $M/Map($Key, $Value), key: Key) -> ^Value {
i := _map_find_or_fail(m, key);
if i < 0 {
return nil;
@@ -92,7 +96,7 @@ map_get_ptr :: proc(m: $M/Map($Value), key: u64) -> ^Value {
return array_get_ptr(m.entries, i).value;
}
map_set :: proc(m: ^$M/Map($Value), key: u64, value: Value) {
map_set :: proc(m: ^$M/Map($Key, $Value), key: Key, value: Value) {
if array_len(m.hash) == 0 {
_map_grow(m);
}
@@ -104,7 +108,7 @@ map_set :: proc(m: ^$M/Map($Value), key: u64, value: Value) {
}
}
map_remove :: proc(m: ^$M/Map($Value), key: u64) {
map_remove :: proc(m: ^$M/Map($Key, $Value), key: Key) {
fr := _map_find_key(m^, key);
if fr.entry_index >= 0 {
_map_erase(m, fr);
@@ -112,7 +116,7 @@ map_remove :: proc(m: ^$M/Map($Value), key: u64) {
}
map_reserve :: proc(m: ^$M/Map($Value), new_size: int) {
map_reserve :: proc(m: ^$M/Map($Key, $Value), new_size: int) {
nm: M;
map_init(&nm, m.hash.allocator);
array_resize(&nm.hash, new_size);
@@ -130,14 +134,14 @@ map_reserve :: proc(m: ^$M/Map($Value), new_size: int) {
m^ = nm;
}
map_clear :: proc(m: ^$M/Map($Value)) {
map_clear :: proc(m: ^$M/Map($Key, $Value)) {
array_clear(&m.hash);
array_clear(&m.entries);
}
multi_map_find_first :: proc(m: $M/Map($Value), key: u64) -> ^Map_Entry(Value) {
multi_map_find_first :: proc(m: $M/Map($Key, $Value), key: Key) -> ^Map_Entry(Value) {
i := _map_find_or_fail(m, key);
if i < 0 {
return nil;
@@ -145,11 +149,11 @@ multi_map_find_first :: proc(m: $M/Map($Value), key: u64) -> ^Map_Entry(Value) {
return array_get_ptr(m.entries, i);
}
multi_map_find_next :: proc(m: $M/Map($Value), e: ^Map_Entry(Value)) -> ^Map_Entry(Value) {
multi_map_find_next :: proc(m: $M/Map($Key, $Value), e: ^Map_Entry(Value)) -> ^Map_Entry(Value) {
i := e.next;
for i >= 0 {
it := array_get_ptr(m.entries, i);
if it.key == e.key {
if it.hash == e.hash && it.key == e.key {
return it;
}
i = it.next;
@@ -157,7 +161,7 @@ multi_map_find_next :: proc(m: $M/Map($Value), e: ^Map_Entry(Value)) -> ^Map_Ent
return nil;
}
multi_map_count :: proc(m: $M/Map($Value), key: u64) -> int {
multi_map_count :: proc(m: $M/Map($Key, $Value), key: Key) -> int {
n := 0;
e := multi_map_find_first(m, key);
for e != nil {
@@ -169,7 +173,7 @@ multi_map_count :: proc(m: $M/Map($Value), key: u64) -> int {
multi_map_get :: proc{multi_map_get_array, multi_map_get_slice};
multi_map_get_array :: proc(m: $M/Map($Value), key: u64, items: ^Array(Value)) {
multi_map_get_array :: proc(m: $M/Map($Key, $Value), key: Key, items: ^Array(Value)) {
if items == nil {
return;
}
@@ -180,7 +184,7 @@ multi_map_get_array :: proc(m: $M/Map($Value), key: u64, items: ^Array(Value)) {
}
}
multi_map_get_slice :: proc(m: $M/Map($Value), key: u64, items: []Value) {
multi_map_get_slice :: proc(m: $M/Map($Key, $Value), key: Key, items: []Value) {
e := multi_map_find_first(m, key);
i := 0;
for e != nil && i < len(items) {
@@ -190,7 +194,7 @@ multi_map_get_slice :: proc(m: $M/Map($Value), key: u64, items: []Value) {
}
}
multi_map_get_as_slice :: proc(m: $M/Map($Value), key: u64) -> []Value {
multi_map_get_as_slice :: proc(m: $M/Map($Key, $Value), key: Key) -> []Value {
items: Array(Value);
array_init(&items, 0);
@@ -204,7 +208,7 @@ multi_map_get_as_slice :: proc(m: $M/Map($Value), key: u64) -> []Value {
}
multi_map_insert :: proc(m: ^$M/Map($Value), key: u64, value: Value) {
multi_map_insert :: proc(m: ^$M/Map($Key, $Value), key: Key, value: Value) {
if array_len(m.hash) == 0 {
_map_grow(m);
}
@@ -216,14 +220,14 @@ multi_map_insert :: proc(m: ^$M/Map($Value), key: u64, value: Value) {
}
}
multi_map_remove :: proc(m: ^$M/Map($Value), e: ^Map_Entry(Value)) {
multi_map_remove :: proc(m: ^$M/Map($Key, $Value), e: ^Map_Entry(Value)) {
fr := _map_find_entry(m, e);
if fr.entry_index >= 0 {
_map_erase(m, fr);
}
}
multi_map_remove_all :: proc(m: ^$M/Map($Value), key: u64) {
multi_map_remove_all :: proc(m: ^$M/Map($Key, $Value), key: Key) {
for map_exist(m^, key) {
map_remove(m, key);
}
@@ -239,9 +243,12 @@ Map_Find_Result :: struct {
entry_index: int,
}
_map_add_entry :: proc(m: ^$M/Map($Value), key: u64) -> int {
e: Map_Entry(Value);
_map_add_entry :: proc(m: ^$M/Map($Key, $Value), key: Key) -> int where intrinsics.type_is_valid_map_key(Key) {
hasher := intrinsics.type_hasher_proc(Key);
e: Map_Entry(Key, Value);
e.key = key;
e.hash = hasher(&e.key, 0);
e.next = -1;
idx := array_len(m.entries);
array_push(&m.entries, e);
@@ -271,7 +278,7 @@ _map_erase :: proc(m: ^$M/Map, fr: Map_Find_Result) {
}
_map_find_key :: proc(m: $M/Map($Value), key: u64) -> Map_Find_Result {
_map_find_key :: proc(m: $M/Map($Key, $Value), key: Key) -> Map_Find_Result where intrinsics.type_is_valid_map_key(Key) {
fr: Map_Find_Result;
fr.hash_index = -1;
fr.entry_prev = -1;
@@ -281,11 +288,16 @@ _map_find_key :: proc(m: $M/Map($Value), key: u64) -> Map_Find_Result {
return fr;
}
fr.hash_index = int(key % u64(array_len(m.hash)));
hasher := intrinsics.type_hasher_proc(Key);
key := key;
hash := hasher(&key, 0);
fr.hash_index = int(hash % uintptr(array_len(m.hash)));
fr.entry_index = array_get(m.hash, fr.hash_index);
for fr.entry_index >= 0 {
it := array_get_ptr(m.entries, fr.entry_index);
if it.key == key {
if it.hash == hash && it.key == key {
return fr;
}
fr.entry_prev = fr.entry_index;
@@ -294,7 +306,7 @@ _map_find_key :: proc(m: $M/Map($Value), key: u64) -> Map_Find_Result {
return fr;
}
_map_find_entry :: proc(m: ^$M/Map($Value), e: ^Map_Entry(Value)) -> Map_Find_Result {
_map_find_entry :: proc(m: ^$M/Map($Key, $Value), e: ^Map_Entry(Value)) -> Map_Find_Result {
fr: Map_Find_Result;
fr.hash_index = -1;
fr.entry_prev = -1;
@@ -304,7 +316,7 @@ _map_find_entry :: proc(m: ^$M/Map($Value), e: ^Map_Entry(Value)) -> Map_Find_Re
return fr;
}
fr.hash_index = int(e.key % u64(array_len(m.hash)));
fr.hash_index = int(e.hash % uintptr(array_len(m.hash)));
fr.entry_index = array_get(m.hash, fr.hash_index);
for fr.entry_index >= 0 {
it := array_get_ptr(m.entries, fr.entry_index);
@@ -317,10 +329,10 @@ _map_find_entry :: proc(m: ^$M/Map($Value), e: ^Map_Entry(Value)) -> Map_Find_Re
return fr;
}
_map_find_or_fail :: proc(m: $M/Map($Value), key: u64) -> int {
_map_find_or_fail :: proc(m: $M/Map($Key, $Value), key: Key) -> int {
return _map_find_key(m, key).entry_index;
}
_map_find_or_make :: proc(m: ^$M/Map($Value), key: u64) -> int {
_map_find_or_make :: proc(m: ^$M/Map($Key, $Value), key: Key) -> int {
fr := _map_find_key(m^, key);
if fr.entry_index >= 0 {
return fr.entry_index;
@@ -336,7 +348,7 @@ _map_find_or_make :: proc(m: ^$M/Map($Value), key: u64) -> int {
}
_map_make :: proc(m: ^$M/Map($Value), key: u64) -> int {
_map_make :: proc(m: ^$M/Map($Key, $Value), key: Key) -> int {
fr := _map_find_key(m^, key);
i := _map_add_entry(m, key);
@@ -352,12 +364,12 @@ _map_make :: proc(m: ^$M/Map($Value), key: u64) -> int {
}
_map_full :: proc(m: $M/Map($Value)) -> bool {
_map_full :: proc(m: $M/Map($Key, $Value)) -> bool {
// TODO(bill): Determine good max load factor
return array_len(m.entries) >= (array_len(m.hash) / 4)*3;
}
_map_grow :: proc(m: ^$M/Map($Value)) {
_map_grow :: proc(m: ^$M/Map($Key, $Value)) {
new_size := array_len(m.entries) * 4 + 7; // TODO(bill): Determine good grow rate
map_reserve(m, new_size);
}
+12 -24
View File
@@ -12,8 +12,6 @@ import "core:time"
import "core:unicode/utf8"
import "intrinsics"
DEFAULT_BUFFER_SIZE :: #config(FMT_DEFAULT_BUFFER_SIZE, 1<<10);
Info :: struct {
minus: bool,
plus: bool,
@@ -798,7 +796,7 @@ fmt_int :: proc(fi: ^Info, u: u64, is_signed: bool, bit_size: int, verb: rune) {
case 'v': _fmt_int(fi, u, 10, is_signed, bit_size, __DIGITS_LOWER);
case 'b': _fmt_int(fi, u, 2, is_signed, bit_size, __DIGITS_LOWER);
case 'o': _fmt_int(fi, u, 8, is_signed, bit_size, __DIGITS_LOWER);
case 'd': _fmt_int(fi, u, 10, is_signed, bit_size, __DIGITS_LOWER);
case 'i', 'd': _fmt_int(fi, u, 10, is_signed, bit_size, __DIGITS_LOWER);
case 'z': _fmt_int(fi, u, 12, is_signed, bit_size, __DIGITS_LOWER);
case 'x': _fmt_int(fi, u, 16, is_signed, bit_size, __DIGITS_LOWER);
case 'X': _fmt_int(fi, u, 16, is_signed, bit_size, __DIGITS_UPPER);
@@ -823,7 +821,7 @@ fmt_int_128 :: proc(fi: ^Info, u: u128, is_signed: bool, bit_size: int, verb: ru
case 'v': _fmt_int_128(fi, u, 10, is_signed, bit_size, __DIGITS_LOWER);
case 'b': _fmt_int_128(fi, u, 2, is_signed, bit_size, __DIGITS_LOWER);
case 'o': _fmt_int_128(fi, u, 8, is_signed, bit_size, __DIGITS_LOWER);
case 'd': _fmt_int_128(fi, u, 10, is_signed, bit_size, __DIGITS_LOWER);
case 'i', 'd': _fmt_int_128(fi, u, 10, is_signed, bit_size, __DIGITS_LOWER);
case 'z': _fmt_int_128(fi, u, 12, is_signed, bit_size, __DIGITS_LOWER);
case 'x': _fmt_int_128(fi, u, 16, is_signed, bit_size, __DIGITS_LOWER);
case 'X': _fmt_int_128(fi, u, 16, is_signed, bit_size, __DIGITS_UPPER);
@@ -1007,7 +1005,7 @@ fmt_pointer :: proc(fi: ^Info, p: rawptr, verb: rune) {
case 'b': _fmt_int(fi, u, 2, false, 8*size_of(rawptr), __DIGITS_UPPER);
case 'o': _fmt_int(fi, u, 8, false, 8*size_of(rawptr), __DIGITS_UPPER);
case 'd': _fmt_int(fi, u, 10, false, 8*size_of(rawptr), __DIGITS_UPPER);
case 'i', 'd': _fmt_int(fi, u, 10, false, 8*size_of(rawptr), __DIGITS_UPPER);
case 'x': _fmt_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER);
case 'X': _fmt_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER);
@@ -1072,7 +1070,7 @@ fmt_enum :: proc(fi: ^Info, v: any, verb: rune) {
case runtime.Type_Info_Enum:
switch verb {
case: fmt_bad_verb(fi, verb);
case 'd', 'f':
case 'i', 'd', 'f':
fmt_arg(fi, any{v.data, runtime.type_info_base(e.base).id}, verb);
case 's', 'v':
str, ok := enum_value_to_string(v);
@@ -1087,6 +1085,8 @@ fmt_enum :: proc(fi: ^Info, v: any, verb: rune) {
stored_enum_value_to_string :: proc(enum_type: ^runtime.Type_Info, ev: runtime.Type_Info_Enum_Value, offset: int = 0) -> (string, bool) {
et := runtime.type_info_base(enum_type);
ev := ev;
ev += runtime.Type_Info_Enum_Value(offset);
#partial switch e in et.variant {
case: return "", false;
case runtime.Type_Info_Enum:
@@ -1111,18 +1111,6 @@ stored_enum_value_to_string :: proc(enum_type: ^runtime.Type_Info, ev: runtime.T
return "", false;
}
fmt_write_i64 :: proc(w: io.Writer, i: i64, base: int = 10) {
buf: [32]byte;
s := strconv.append_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil);
io.write_string(w, s);
}
fmt_write_u64 :: proc(w: io.Writer, i: u64, base: int) {
buf: [32]byte;
s := strconv.append_bits(buf[:], u64(i), base, false, 64, strconv.digits, nil);
io.write_string(w, s);
}
fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") {
is_bit_set_different_endian_to_platform :: proc(ti: ^runtime.Type_Info) -> bool {
if ti == nil {
@@ -1211,7 +1199,7 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") {
}
}
v := i64(i) + info.lower;
fmt_write_i64(fi.writer, v, 10);
io.write_i64(fi.writer, v, 10);
commas += 1;
}
}
@@ -1253,7 +1241,7 @@ fmt_bit_field :: proc(fi: ^Info, v: any, bit_field_name: string = "") {
u <<= sa;
u >>= sa;
fmt_write_u64(fi.writer, u, 10);
io.write_u64(fi.writer, u, 10);
}
io.write_byte(fi.writer, '}');
@@ -1312,7 +1300,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
for in 0..<n {
io.write_byte(fi.writer, '0');
}
fmt_write_i64(fi.writer, i, 10);
io.write_i64(fi.writer, i, 10);
}
@@ -1654,7 +1642,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
io.write_byte(fi.writer, '.');
io.write_string(fi.writer, idx);
} else {
fmt_write_i64(fi.writer, i64(info.min_value)+i64(i));
io.write_i64(fi.writer, i64(info.min_value)+i64(i));
}
io.write_string(fi.writer, " = ");
@@ -2060,9 +2048,9 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
if fi.hash && verb == 'v' {
io.write_string(fi.writer, a.file_path);
io.write_byte(fi.writer, '(');
fmt_write_i64(fi.writer, i64(a.line), 10);
io.write_i64(fi.writer, i64(a.line), 10);
io.write_byte(fi.writer, ':');
fmt_write_i64(fi.writer, i64(a.column), 10);
io.write_i64(fi.writer, i64(a.column), 10);
io.write_byte(fi.writer, ')');
return;
}
+1 -1
View File
@@ -436,7 +436,7 @@ copy_buffer :: proc(dst: Writer, src: Reader, buf: []byte) -> (written: i64, err
// It returns the number of bytes copied and the first error that occurred whilst copying, if any.
// On return, written == n IFF err == nil
copy_n :: proc(dst: Writer, src: Reader, n: i64) -> (written: i64, err: Error) {
nsrc := inline_limited_reader(&Limited_Reader{}, src, n);
nsrc := limited_reader_init(&Limited_Reader{}, src, n);
written, err = copy(dst, nsrc);
if written == n {
return n, nil;
+11 -27
View File
@@ -1,6 +1,5 @@
package io
import "core:runtime"
import "core:strconv"
write_u64 :: proc(w: Writer, i: u64, base: int = 10) -> (n: int, err: Error) {
@@ -21,11 +20,9 @@ write_int :: proc(w: Writer, i: int, base: int = 10) -> (n: int, err: Error) {
return write_i64(w, i64(i), base);
}
@(private)
Tee_Reader :: struct {
r: Reader,
w: Writer,
allocator: runtime.Allocator,
}
@(private)
@@ -40,27 +37,22 @@ _tee_reader_vtable := &Stream_VTable{
}
return;
},
impl_destroy = proc(s: Stream) -> Error {
t := (^Tee_Reader)(s.stream_data);
allocator := t.allocator;
free(t, allocator);
return .None;
},
};
// tee_reader returns a Reader that writes to 'w' what it reads from 'r'
// tee_reader_init returns a Reader that writes to 'w' what it reads from 'r'
// All reads from 'r' performed through it are matched with a corresponding write to 'w'
// There is no internal buffering done
// The write must complete before th read completes
// Any error encountered whilst writing is reported as a 'read' error
// tee_reader must call io.destroy when done with
tee_reader :: proc(r: Reader, w: Writer, allocator := context.allocator) -> (out: Reader) {
t := new(Tee_Reader, allocator);
// tee_reader_init must call io.destroy when done with
tee_reader_init :: proc(t: ^Tee_Reader, r: Reader, w: Writer, allocator := context.allocator) -> Reader {
t.r, t.w = r, w;
t.allocator = allocator;
return tee_reader_to_reader(t);
}
out.stream_data = t;
out.stream_vtable = _tee_reader_vtable;
tee_reader_to_reader :: proc(t: ^Tee_Reader) -> (r: Reader) {
r.stream_data = t;
r.stream_vtable = _tee_reader_vtable;
return;
}
@@ -90,11 +82,10 @@ _limited_reader_vtable := &Stream_VTable{
},
};
new_limited_reader :: proc(r: Reader, n: i64) -> ^Limited_Reader {
l := new(Limited_Reader);
limited_reader_init :: proc(l: ^Limited_Reader, r: Reader, n: i64) -> Reader {
l.r = r;
l.n = n;
return l;
return limited_reader_to_reader(l);
}
limited_reader_to_reader :: proc(l: ^Limited_Reader) -> (r: Reader) {
@@ -103,13 +94,6 @@ limited_reader_to_reader :: proc(l: ^Limited_Reader) -> (r: Reader) {
return;
}
@(private="package")
inline_limited_reader :: proc(l: ^Limited_Reader, r: Reader, n: i64) -> Reader {
l.r = r;
l.n = n;
return limited_reader_to_reader(l);
}
// Section_Reader implements read, seek, and read_at on a section of an underlying Reader_At
Section_Reader :: struct {
r: Reader_At,
@@ -118,7 +102,7 @@ Section_Reader :: struct {
limit: i64,
}
init_section_reader :: proc(s: ^Section_Reader, r: Reader_At, off: i64, n: i64) {
section_reader_init :: proc(s: ^Section_Reader, r: Reader_At, off: i64, n: i64) {
s.r = r;
s.off = off;
s.limit = off + n;
+1 -1
View File
@@ -508,7 +508,7 @@ factorial :: proc(n: int) -> int {
assert(n >= 0, "parameter must not be negative");
assert(n < len(table), "parameter is too large to lookup in the table");
return 0;
return table[n];
}
classify_f32 :: proc(x: f32) -> Float_Class {
+48 -5
View File
@@ -35,11 +35,6 @@ Node_State_Flag :: enum {
}
Node_State_Flags :: distinct bit_set[Node_State_Flag];
Comment_Group :: struct {
list: []tokenizer.Token,
}
Node :: struct {
pos: tokenizer.Pos,
end: tokenizer.Pos,
@@ -47,6 +42,54 @@ Node :: struct {
derived: any,
}
Comment_Group :: struct {
using node: Node,
list: []tokenizer.Token,
}
Package_Kind :: enum {
Normal,
Runtime,
Init,
}
Package :: struct {
using node: Node,
kind: Package_Kind,
id: int,
name: string,
fullpath: string,
files: map[string]^File,
user_data: rawptr,
}
File :: struct {
using node: Node,
id: int,
pkg: ^Package,
fullpath: string,
src: []byte,
docs: ^Comment_Group,
pkg_decl: ^Package_Decl,
pkg_token: tokenizer.Token,
pkg_name: string,
decls: [dynamic]^Stmt,
imports: [dynamic]^Import_Decl,
directive_count: int,
comments: [dynamic]^Comment_Group,
syntax_warning_count: int,
syntax_error_count: int,
}
// Base Types
Expr :: struct {
using expr_base: Node,
+5
View File
@@ -67,6 +67,11 @@ clone_node :: proc(node: ^Node) -> ^Node {
align = ti.align;
}
switch in node.derived {
case Package, File:
panic("Cannot clone this node type");
}
res := cast(^Node)mem.alloc(size, align);
src: rawptr = node;
if node.derived != nil {
-40
View File
@@ -1,40 +0,0 @@
package odin_ast
import "core:odin/tokenizer"
Package_Kind :: enum {
Normal,
Runtime,
Init,
}
Package :: struct {
kind: Package_Kind,
id: int,
name: string,
fullpath: string,
files: []^File,
user_data: rawptr,
}
File :: struct {
id: int,
pkg: ^Package,
fullpath: string,
src: []byte,
pkg_decl: ^Package_Decl,
pkg_token: tokenizer.Token,
pkg_name: string,
decls: [dynamic]^Stmt,
imports: [dynamic]^Import_Decl,
directive_count: int,
comments: [dynamic]^Comment_Group,
syntax_warning_count: int,
syntax_error_count: int,
}
+45
View File
@@ -59,6 +59,18 @@ walk :: proc(v: ^Visitor, node: ^Node) {
}
switch n in &node.derived {
case File:
if n.docs != nil {
walk(v, n.docs);
}
walk_stmt_list(v, n.decls[:]);
case Package:
for _, f in n.files {
walk(v, f);
}
case Comment_Group:
// empty
case Bad_Expr:
case Ident:
case Implicit:
@@ -252,29 +264,59 @@ walk :: proc(v: ^Visitor, node: ^Node) {
case Bad_Decl:
case Value_Decl:
if n.docs != nil {
walk(v, n.docs);
}
walk_attribute_list(v, n.attributes[:]);
walk_expr_list(v, n.names);
if n.type != nil {
walk(v, n.type);
}
walk_expr_list(v, n.values);
if n.comment != nil {
walk(v, n.comment);
}
case Package_Decl:
if n.docs != nil {
walk(v, n.docs);
}
if n.comment != nil {
walk(v, n.comment);
}
case Import_Decl:
if n.docs != nil {
walk(v, n.docs);
}
if n.comment != nil {
walk(v, n.comment);
}
case Foreign_Block_Decl:
if n.docs != nil {
walk(v, n.docs);
}
walk_attribute_list(v, n.attributes[:]);
if n.foreign_library != nil {
walk(v, n.foreign_library);
}
walk(v, n.body);
case Foreign_Import_Decl:
if n.docs != nil {
walk(v, n.docs);
}
walk_attribute_list(v, n.attributes[:]);
walk(v, n.name);
if n.comment != nil {
walk(v, n.comment);
}
case Proc_Group:
walk_expr_list(v, n.args);
case Attribute:
walk_expr_list(v, n.elems);
case Field:
if n.docs != nil {
walk(v, n.docs);
}
walk_expr_list(v, n.names);
if n.type != nil {
walk(v, n.type);
@@ -282,6 +324,9 @@ walk :: proc(v: ^Visitor, node: ^Node) {
if n.default_value != nil {
walk(v, n.default_value);
}
if n.comment != nil {
walk(v, n.comment);
}
case Field_List:
for x in n.list {
walk(v, x);
+89
View File
@@ -0,0 +1,89 @@
package odin_parser
import "core:odin/tokenizer"
import "core:odin/ast"
import "core:path/filepath"
import "core:fmt"
import "core:os"
import "core:slice"
collect_package :: proc(path: string) -> (pkg: ^ast.Package, success: bool) {
NO_POS :: tokenizer.Pos{};
pkg_path, pkg_path_ok := filepath.abs(path);
if !pkg_path_ok {
return;
}
path_pattern := fmt.tprintf("%s/*.odin", pkg_path);
matches, err := filepath.glob(path_pattern);
defer delete(matches);
if err != nil {
return;
}
pkg = ast.new(ast.Package, NO_POS, NO_POS);
pkg.fullpath = pkg_path;
for match in matches {
src: []byte;
fullpath, ok := filepath.abs(match);
if !ok {
return;
}
src, ok = os.read_entire_file(fullpath);
if !ok {
delete(fullpath);
return;
}
file := ast.new(ast.File, NO_POS, NO_POS);
file.pkg = pkg;
file.src = src;
file.fullpath = fullpath;
pkg.files[fullpath] = file;
}
success = true;
return;
}
parse_package :: proc(pkg: ^ast.Package, p: ^Parser = nil) -> bool {
p := p;
if p == nil {
p = &Parser{};
p^ = default_parser();
}
ok := true;
files := make([]^ast.File, len(pkg.files), context.temp_allocator);
i := 0;
for _, file in pkg.files {
files[i] = file;
i += 1;
}
slice.sort(files);
for file in files {
if !parse_file(p, file) {
ok = false;
}
if pkg.name == "" {
pkg.name = file.pkg_decl.name;
} else if pkg.name != file.pkg_decl.name {
error(p, file.pkg_decl.pos, "different package name, expected '%s', got '%s'", pkg.name, file.pkg_decl.name);
}
}
return ok;
}
parse_package_from_path :: proc(path: string, p: ^Parser = nil) -> (pkg: ^ast.Package, ok: bool) {
pkg, ok = collect_package(path);
if !ok {
return;
}
ok = parse_package(pkg, p);
return;
}
+16 -7
View File
@@ -107,6 +107,14 @@ default_parser :: proc() -> Parser {
};
}
is_package_name_reserved :: proc(name: string) -> bool {
switch name {
case "builtin", "intrinsics":
return true;
}
return false;
}
parse_file :: proc(p: ^Parser, file: ^ast.File) -> bool {
zero_parser: {
p.prev_tok = {};
@@ -139,8 +147,11 @@ parse_file :: proc(p: ^Parser, file: ^ast.File) -> bool {
pkg_name := expect_token_after(p, .Ident, "package");
if pkg_name.kind == .Ident {
if is_blank_ident(pkg_name) {
switch name := pkg_name.text; {
case is_blank_ident(name):
error(p, pkg_name.pos, "invalid package name '_'");
case is_package_name_reserved(name), file.pkg.kind != .Runtime && name == "runtime":
error(p, pkg_name.pos, "use of reserved package name '%s'", name);
}
}
p.file.pkg_name = pkg_name.text;
@@ -276,7 +287,7 @@ consume_comment_group :: proc(p: ^Parser, n: int) -> (comments: ^ast.Comment_Gro
}
if len(list) > 0 {
comments = new(ast.Comment_Group);
comments = ast.new(ast.Comment_Group, list[0].pos, end_pos(list[len(list)-1]));
comments.list = list[:];
append(&p.file.comments, comments);
}
@@ -521,6 +532,7 @@ parse_stmt_list :: proc(p: ^Parser) -> []^ast.Stmt {
}
parse_block_stmt :: proc(p: ^Parser, is_when: bool) -> ^ast.Stmt {
skip_possible_newline_for_literal(p);
if !is_when && p.curr_proc == nil {
error(p, p.curr_tok.pos, "you cannot use a block statement in the file scope");
}
@@ -546,9 +558,9 @@ parse_when_stmt :: proc(p: ^Parser) -> ^ast.When_Stmt {
body = convert_stmt_to_body(p, parse_stmt(p));
} else {
body = parse_block_stmt(p, true);
skip_possible_newline_for_literal(p);
}
skip_possible_newline_for_literal(p);
if allow_token(p, .Else) {
#partial switch p.curr_tok.kind {
case .When:
@@ -622,11 +634,11 @@ parse_if_stmt :: proc(p: ^Parser) -> ^ast.If_Stmt {
body = convert_stmt_to_body(p, parse_stmt(p));
} else {
body = parse_block_stmt(p, false);
skip_possible_newline_for_literal(p);
}
else_tok := p.curr_tok.pos;
skip_possible_newline_for_literal(p);
if allow_token(p, .Else) {
#partial switch p.curr_tok.kind {
case .If:
@@ -687,7 +699,6 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
body = convert_stmt_to_body(p, parse_stmt(p));
} else {
body = parse_body(p);
skip_possible_newline_for_literal(p);
}
range_stmt := ast.new(ast.Range_Stmt, tok.pos, body.end);
@@ -722,7 +733,6 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
body = convert_stmt_to_body(p, parse_stmt(p));
} else {
body = parse_body(p);
skip_possible_newline_for_literal(p);
}
@@ -1094,7 +1104,6 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
body = convert_stmt_to_body(p, parse_stmt(p));
} else {
body = parse_block_stmt(p, false);
skip_possible_newline_for_literal(p);
}
if bad_stmt {
+4 -4
View File
@@ -272,13 +272,13 @@ _glob :: proc(dir, pattern: string, matches: ^[dynamic]string) -> (m: [dynamic]s
}
defer os.close(d);
fi, ferr := os.fstat(d);
file_info, ferr := os.fstat(d);
if ferr != 0 {
os.file_info_delete(fi);
os.file_info_delete(file_info);
return;
}
if !fi.is_dir {
os.file_info_delete(fi);
if !file_info.is_dir {
os.file_info_delete(file_info);
return;
}
+1 -2
View File
@@ -2,7 +2,6 @@
// To process paths usch as URLs that depend on forward slashes regardless of the OS, use the path package
package filepath
import "core:os"
import "core:strings"
// is_separator checks whether the byte is a valid separator character
@@ -265,7 +264,7 @@ rel :: proc(base_path, target_path: string, allocator := context.allocator) -> (
}
buf := make([]byte, size);
n := copy(buf, "..");
for i in 0..<seps {
for in 0..<seps {
buf[n] = SEPARATOR;
copy(buf[n+1:], "..");
n += 3;
+4 -3
View File
@@ -41,7 +41,8 @@ is_abs :: proc(path: string) -> bool {
return false;
}
path := path[l:];
path := path;
path = path[l:];
if path == "" {
return false;
}
@@ -123,8 +124,8 @@ split_list :: proc(path: string, allocator := context.allocator) -> []string {
}
assert(index == count);
for s, i in list {
s, new := strings.replace_all(s, `"`, ``, allocator);
for s0, i in list {
s, new := strings.replace_all(s0, `"`, ``, allocator);
if !new {
s = strings.clone(s, allocator);
}
+54
View File
@@ -0,0 +1,54 @@
package strings
import "core:mem"
Intern_Entry :: struct {
len: int,
str: [1]byte, // string is allocated inline with the entry to keep allocations simple
}
Intern :: struct {
allocator: mem.Allocator,
entries: map[string]^Intern_Entry,
}
intern_init :: proc(m: ^Intern, allocator := context.allocator, map_allocator := context.allocator) {
m.allocator = allocator;
m.entries = make(map[string]^Intern_Entry, 16, map_allocator);
}
intern_destroy :: proc(m: ^Intern) {
for _, value in m.entries {
free(value, m.allocator);
}
delete(m.entries);
}
intern_get :: proc(m: ^Intern, text: string) -> string {
entry := _intern_get_entry(m, text);
return #no_bounds_check string(entry.str[:entry.len]);
}
intern_get_cstring :: proc(m: ^Intern, text: string) -> cstring {
entry := _intern_get_entry(m, text);
return cstring(&entry.str[0]);
}
_intern_get_entry :: proc(m: ^Intern, text: string) -> ^Intern_Entry #no_bounds_check {
if prev, ok := m.entries[text]; ok {
return prev;
}
if m.allocator.procedure == nil {
m.allocator = context.allocator;
}
entry_size := int(offset_of(Intern_Entry, str)) + len(text) + 1;
new_entry := (^Intern_Entry)(mem.alloc(entry_size, align_of(Intern_Entry), m.allocator));
new_entry.len = len(text);
copy(new_entry.str[:new_entry.len], text);
new_entry.str[new_entry.len] = 0;
key := string(new_entry.str[:new_entry.len]);
m.entries[key] = new_entry;
return new_entry;
}
+8 -5
View File
@@ -61,14 +61,17 @@ Scan_Flag :: enum u32 {
Scan_Comments,
Skip_Comments, // if set with .Scan_Comments, comments become white space
}
Scan_Flags :: bit_set[Scan_Flag; u32];
Scan_Flags :: distinct bit_set[Scan_Flag; u32];
Odin_Like_Tokens :: Scan_Flags{.Scan_Idents, .Scan_Ints, .Scan_Floats, .Scan_Chars, .Scan_Strings, .Scan_Raw_Strings, .Scan_Comments, .Skip_Comments};
C_Like_Tokens :: Scan_Flags{.Scan_Idents, .Scan_Ints, .Scan_C_Int_Prefixes, .Scan_Floats, .Scan_Chars, .Scan_Strings, .Scan_Raw_Strings, .Scan_Comments, .Skip_Comments};
// Only allows for ASCII whitespace
Whitespace :: distinct bit_set['\x00'..<utf8.RUNE_SELF; u128];
// Odin_Whitespace is the default value for the Scanner's whitespace field
Odin_Whitespace :: 1<<'\t' | 1<<'\n' | 1<<'\r' | 1<<' ';
C_Whitespace :: 1<<'\t' | 1<<'\n' | 1<<'\r' | 1<<'\v' | 1<<'\f' | 1<<' ';
Odin_Whitespace :: Whitespace{'\t', '\n', '\r', ' '};
C_Whitespace :: Whitespace{'\t', '\n', '\r', '\v', '\f', ' '};
// Scanner allows for the reading of Unicode characters and tokens from a string
@@ -102,7 +105,7 @@ Scanner :: struct {
// The whitespace field controls which characters are recognized as white space
// This field may be changed by the user at any time during scanning
whitespace: u64,
whitespace: Whitespace,
// is_ident_rune is a predicate controlling the characters accepted as the ith rune in an identifier
// The valid characters must not conflict with the set of white space characters
@@ -523,7 +526,7 @@ scan :: proc(s: ^Scanner) -> (tok: rune) {
s.pos.line = 0;
redo: for {
for s.whitespace & (1<<uint(ch)) != 0 {
for (ch < utf8.RUNE_SELF && ch in s.whitespace) {
ch = advance(s);
}
+27
View File
@@ -0,0 +1,27 @@
{ pkgs ? import <nixpkgs> { } }:
let
odin-unwrapped = pkgs.llvmPackages_11.stdenv.mkDerivation (rec {
name = "odin-unwrapped";
src = ./.;
dontConfigure = true;
nativeBuildInputs = [ pkgs.git ];
buildPhase = ''
make debug SHELL=${pkgs.llvmPackages_11.stdenv.shell}
'';
installPhase = ''
mkdir -p $out/bin
cp odin $out/bin/odin
cp -r core $out/bin/core
'';
});
path = builtins.map (path: path + "/bin") (with pkgs.llvmPackages_11; [
bintools
llvm
clang
lld
]);
in
pkgs.writeScriptBin "odin" ''
#!${pkgs.llvmPackages_11.stdenv.shell}
PATH="${(builtins.concatStringsSep ":" path)}" exec ${odin-unwrapped}/bin/odin $@
''
+1 -21
View File
@@ -168,18 +168,6 @@ void check_init_constant(CheckerContext *ctx, Entity *e, Operand *operand) {
return;
}
#if 0
if (!is_type_constant_type(operand->type)) {
gbString type_str = type_to_string(operand->type);
error(operand->expr, "Invalid constant type: '%s'", type_str);
gb_string_free(type_str);
if (e->type == nullptr) {
e->type = t_invalid;
}
return;
}
#endif
if (e->type == nullptr) { // NOTE(bill): type inference
e->type = operand->type;
}
@@ -388,15 +376,7 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init,
e->flags |= EntityFlag_Visited;
if (type_expr) {
Type *t = check_type(ctx, type_expr);
if (!is_type_constant_type(t) && !is_type_proc(t)) {
gbString str = type_to_string(t);
error(type_expr, "Invalid constant type '%s'", str);
gb_string_free(str);
e->type = t_invalid;
return;
}
e->type = t;
e->type = check_type(ctx, type_expr);
}
Operand operand = {};
+6 -2
View File
@@ -7910,7 +7910,9 @@ void check_expr_with_type_hint(CheckerContext *c, Operand *o, Ast *e, Type *t) {
err_str = "used as a value";
break;
case Addressing_Type:
err_str = "is not an expression but a type";
if (t == nullptr || !is_type_typeid(t)) {
err_str = "is not an expression but a type";
}
break;
case Addressing_Builtin:
err_str = "must be called";
@@ -8760,8 +8762,10 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
i64 lo = exact_value_to_i64(x.value);
i64 hi = exact_value_to_i64(y.value);
i64 max_index = hi;
if (op.kind == Token_RangeHalf) {
if (op.kind == Token_RangeHalf) { // ..< (exclusive)
hi -= 1;
} else { // .. (inclusive)
max_index += 1;
}
bool new_range = range_cache_add_range(&rc, lo, hi);
+12 -2
View File
@@ -1803,9 +1803,19 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
if (val0 == nullptr) {
gbString s = expr_to_string(operand.expr);
gbString t = type_to_string(operand.type);
defer (gb_string_free(s));
defer (gb_string_free(t));
error(operand.expr, "Cannot iterate over '%s' of type '%s'", s, t);
gb_string_free(t);
gb_string_free(s);
if (rs->val0 != nullptr && rs->val1 == nullptr) {
if (is_type_map(operand.type) || is_type_bit_set(operand.type)) {
gbString v = expr_to_string(rs->val0);
defer (gb_string_free(v));
error_line("\tSuggestion: place parentheses around the expression\n");
error_line("\t for (%s in %s) {\n", v, s);
}
}
}
}
+10 -2
View File
@@ -1638,6 +1638,7 @@ irValue *ir_check_compound_lit_constant(irModule *m, Ast *expr) {
if (expr == nullptr) {
return nullptr;
}
if (expr->kind == Ast_CompoundLit) {
ast_node(cl, CompoundLit, expr);
for_array(i, cl->elems) {
@@ -1661,6 +1662,7 @@ irValue *ir_check_compound_lit_constant(irModule *m, Ast *expr) {
}
}
return nullptr;
}
@@ -6743,7 +6745,10 @@ irValue *ir_type_info(irProcedure *proc, Type *type) {
return ir_emit_array_ep(proc, ir_global_type_info_data, ir_const_i32(id));
}
irValue *ir_typeid(irModule *m, Type *type) {
u64 ir_typeid_as_integer(irModule *m, Type *type) {
if (type == nullptr) {
return 0;
}
type = default_type(type);
u64 id = cast(u64)ir_type_info_index(m->info, type);
@@ -6808,8 +6813,11 @@ irValue *ir_typeid(irModule *m, Type *type) {
data |= (reserved &~ (1ull<<1)) << 63ull; // kind
}
return id;
}
return ir_value_constant(t_typeid, exact_value_u64(data));
irValue *ir_typeid(irModule *m, Type *type) {
return ir_value_constant(t_typeid, exact_value_u64(ir_typeid_as_integer(m, type)));
}
+5
View File
@@ -787,6 +787,11 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
}
switch (value.kind) {
case ExactValue_Typeid:
GB_ASSERT(is_type_typeid(type));
ir_write_u64(f, ir_typeid_as_integer(m, value.value_typeid));
break;
case ExactValue_Bool:
if (value.value_bool) {
ir_write_string(f, are_types_identical(type, t_llvm_bool) ? str_lit("true") : str_lit("1"));
+7 -10
View File
@@ -1284,8 +1284,7 @@ bool skip_possible_newline(AstFile *f) {
if ((f->tokenizer.flags & TokenizerFlag_InsertSemicolon) == 0) {
return false;
}
Token *prev = &f->curr_token;
if (prev->kind == Token_Semicolon && prev->string == "\n") {
if (token_is_newline(f->curr_token)) {
advance_token(f);
return true;
}
@@ -1296,10 +1295,10 @@ bool skip_possible_newline_for_literal(AstFile *f) {
if ((f->tokenizer.flags & TokenizerFlag_InsertSemicolon) == 0) {
return false;
}
TokenPos curr_pos = f->curr_token.pos;
if (token_is_newline(f->curr_token)) {
Token curr = f->curr_token;
if (token_is_newline(curr)) {
Token next = peek_token(f);
if (curr_pos.line+1 >= next.pos.line) {
if (curr.pos.line+1 >= next.pos.line) {
switch (next.kind) {
case Token_OpenBrace:
case Token_else:
@@ -3182,6 +3181,7 @@ Ast *parse_simple_stmt(AstFile *f, u32 flags) {
Ast *parse_block_stmt(AstFile *f, b32 is_when) {
skip_possible_newline_for_literal(f);
if (!is_when && f->curr_proc == nullptr) {
syntax_error(f->curr_token, "You cannot use a block statement in the file scope");
return ast_bad_stmt(f, f->curr_token, f->curr_token);
@@ -3796,9 +3796,9 @@ Ast *parse_if_stmt(AstFile *f) {
}
} else {
body = parse_block_stmt(f, false);
skip_possible_newline_for_literal(f);
}
skip_possible_newline_for_literal(f);
if (allow_token(f, Token_else)) {
switch (f->curr_token.kind) {
case Token_if:
@@ -3852,9 +3852,9 @@ Ast *parse_when_stmt(AstFile *f) {
}
} else {
body = parse_block_stmt(f, true);
skip_possible_newline_for_literal(f);
}
skip_possible_newline_for_literal(f);
if (allow_token(f, Token_else)) {
switch (f->curr_token.kind) {
case Token_when:
@@ -3958,7 +3958,6 @@ Ast *parse_for_stmt(AstFile *f) {
}
} else {
body = parse_block_stmt(f, false);
skip_possible_newline_for_literal(f);
}
return ast_range_stmt(f, token, nullptr, nullptr, in_token, rhs, body);
}
@@ -3994,7 +3993,6 @@ Ast *parse_for_stmt(AstFile *f) {
}
} else {
body = parse_block_stmt(f, false);
skip_possible_newline_for_literal(f);
}
if (is_range) {
@@ -4346,7 +4344,6 @@ Ast *parse_stmt(AstFile *f) {
}
} else {
body = parse_block_stmt(f, false);
skip_possible_newline_for_literal(f);
}
if (bad_stmt) {
return ast_bad_stmt(f, inline_token, f->curr_token);
+3
View File
@@ -1720,6 +1720,9 @@ TypeTuple *get_record_polymorphic_params(Type *t) {
bool is_type_polymorphic(Type *t, bool or_specialized=false) {
if (t == nullptr) {
return false;
}
if (t->flags & TypeFlag_InProcessOfCheckingPolymorphic) {
return false;
}