mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-15 18:32:22 -07:00
+60
-4
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user