mirror of
https://github.com/odin-lang/Odin.git
synced 2026-04-20 21:35:19 +00:00
Merge branch 'master' into master
This commit is contained in:
@@ -42,8 +42,8 @@ del *.ilk > NUL 2> NUL
|
|||||||
|
|
||||||
cl %compiler_settings% "src\main.cpp" ^
|
cl %compiler_settings% "src\main.cpp" ^
|
||||||
/link %linker_settings% -OUT:%exe_name% ^
|
/link %linker_settings% -OUT:%exe_name% ^
|
||||||
&& odin run examples/demo/demo.odin
|
&& odin run examples/demo/demo.odin -keep-temp-files
|
||||||
|
|
||||||
del *.obj > NUL 2> NUL
|
del *.obj > NUL 2> NUL
|
||||||
|
|
||||||
:end_of_build
|
:end_of_build
|
||||||
|
|||||||
3
core/dynlib/lib.odin
Normal file
3
core/dynlib/lib.odin
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
package dynlib
|
||||||
|
|
||||||
|
Library :: opaque rawptr;
|
||||||
24
core/dynlib/lib_windows.odin
Normal file
24
core/dynlib/lib_windows.odin
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package dynlib
|
||||||
|
|
||||||
|
import "core:sys/win32"
|
||||||
|
import "core:strings"
|
||||||
|
|
||||||
|
load_library :: proc(path: string, global_symbols := false) -> (Library, bool) {
|
||||||
|
// NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL
|
||||||
|
|
||||||
|
wide_path := win32.utf8_to_wstring(path, context.temp_allocator);
|
||||||
|
handle := cast(Library)win32.load_library_w(wide_path);
|
||||||
|
return handle, handle != nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
unload_library :: proc(library: Library) -> bool {
|
||||||
|
ok := win32.free_library(cast(win32.Hmodule)library);
|
||||||
|
return bool(ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) {
|
||||||
|
c_str := strings.new_cstring(symbol, context.temp_allocator);
|
||||||
|
ptr = win32.get_proc_address(cast(win32.Hmodule)library, c_str);
|
||||||
|
found == ptr != nil;
|
||||||
|
return;
|
||||||
|
}
|
||||||
@@ -78,7 +78,7 @@ Token :: struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Tokenizer :: struct {
|
Tokenizer :: struct {
|
||||||
src: []byte,
|
src: []byte,
|
||||||
|
|
||||||
file: string, // May not be used
|
file: string, // May not be used
|
||||||
|
|
||||||
@@ -281,7 +281,7 @@ digit_value :: proc(r: rune) -> int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Kind, string) {
|
scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Kind, string) {
|
||||||
scan_manitissa :: proc(t: ^Tokenizer, base: int) {
|
scan_mantissa :: proc(t: ^Tokenizer, base: int) {
|
||||||
for digit_value(t.curr_rune) < base || t.curr_rune == '_' {
|
for digit_value(t.curr_rune) < base || t.curr_rune == '_' {
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
}
|
}
|
||||||
@@ -294,7 +294,7 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Kind, string) {
|
|||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
}
|
}
|
||||||
if digit_value(t.curr_rune) < 10 {
|
if digit_value(t.curr_rune) < 10 {
|
||||||
scan_manitissa(t, 10);
|
scan_mantissa(t, 10);
|
||||||
} else {
|
} else {
|
||||||
token_error(t, "Illegal floating point exponent");
|
token_error(t, "Illegal floating point exponent");
|
||||||
}
|
}
|
||||||
@@ -305,7 +305,7 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Kind, string) {
|
|||||||
if t.curr_rune == '.' {
|
if t.curr_rune == '.' {
|
||||||
tok = Float;
|
tok = Float;
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
scan_manitissa(t, 10);
|
scan_mantissa(t, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
return scan_exponent(t, tok, offset);
|
return scan_exponent(t, tok, offset);
|
||||||
@@ -317,7 +317,7 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Kind, string) {
|
|||||||
if seen_decimal_point {
|
if seen_decimal_point {
|
||||||
offset -= 1;
|
offset -= 1;
|
||||||
tok = Float;
|
tok = Float;
|
||||||
scan_manitissa(t, 10);
|
scan_mantissa(t, 10);
|
||||||
return scan_exponent(t, tok, offset);
|
return scan_exponent(t, tok, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,24 +327,24 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Kind, string) {
|
|||||||
switch t.curr_rune {
|
switch t.curr_rune {
|
||||||
case 'b', 'B':
|
case 'b', 'B':
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
scan_manitissa(t, 2);
|
scan_mantissa(t, 2);
|
||||||
if t.offset - offset <= 2 {
|
if t.offset - offset <= 2 {
|
||||||
token_error(t, "Illegal binary number");
|
token_error(t, "Illegal binary number");
|
||||||
}
|
}
|
||||||
case 'o', 'O':
|
case 'o', 'O':
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
scan_manitissa(t, 8);
|
scan_mantissa(t, 8);
|
||||||
if t.offset - offset <= 2 {
|
if t.offset - offset <= 2 {
|
||||||
token_error(t, "Illegal octal number");
|
token_error(t, "Illegal octal number");
|
||||||
}
|
}
|
||||||
case 'x', 'X':
|
case 'x', 'X':
|
||||||
advance_to_next_rune(t);
|
advance_to_next_rune(t);
|
||||||
scan_manitissa(t, 16);
|
scan_mantissa(t, 16);
|
||||||
if t.offset - offset <= 2 {
|
if t.offset - offset <= 2 {
|
||||||
token_error(t, "Illegal hexadecimal number");
|
token_error(t, "Illegal hexadecimal number");
|
||||||
}
|
}
|
||||||
case:
|
case:
|
||||||
scan_manitissa(t, 10);
|
scan_mantissa(t, 10);
|
||||||
switch t.curr_rune {
|
switch t.curr_rune {
|
||||||
case '.', 'e', 'E':
|
case '.', 'e', 'E':
|
||||||
return scan_fraction(t, tok, offset);
|
return scan_fraction(t, tok, offset);
|
||||||
@@ -354,7 +354,7 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Kind, string) {
|
|||||||
return tok, string(t.src[offset:t.offset]);
|
return tok, string(t.src[offset:t.offset]);
|
||||||
}
|
}
|
||||||
|
|
||||||
scan_manitissa(t, 10);
|
scan_mantissa(t, 10);
|
||||||
|
|
||||||
return scan_fraction(t, tok, offset);
|
return scan_fraction(t, tok, offset);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -468,11 +468,10 @@ _fmt_int :: proc(fi: ^Info, u: u64, base: int, is_signed: bool, bit_size: int, d
|
|||||||
buf: [256]byte;
|
buf: [256]byte;
|
||||||
start := 0;
|
start := 0;
|
||||||
|
|
||||||
using strconv.Int_Flag;
|
|
||||||
flags: strconv.Int_Flags;
|
flags: strconv.Int_Flags;
|
||||||
if fi.hash && !fi.zero do flags |= {Prefix};
|
if fi.hash && !fi.zero do flags |= {.Prefix};
|
||||||
if fi.plus do flags |= {Plus};
|
if fi.plus do flags |= {.Plus};
|
||||||
if fi.space do flags |= {Space};
|
if fi.space do flags |= {.Space};
|
||||||
s := strconv.append_bits(buf[start:], u, base, is_signed, bit_size, digits, flags);
|
s := strconv.append_bits(buf[start:], u, base, is_signed, bit_size, digits, flags);
|
||||||
|
|
||||||
if fi.hash && fi.zero {
|
if fi.hash && fi.zero {
|
||||||
@@ -746,11 +745,10 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") {
|
|||||||
ti = runtime.type_info_base(ti);
|
ti = runtime.type_info_base(ti);
|
||||||
switch info in ti.variant {
|
switch info in ti.variant {
|
||||||
case runtime.Type_Info_Integer:
|
case runtime.Type_Info_Integer:
|
||||||
using runtime.Type_Info_Endianness;
|
|
||||||
switch info.endianness {
|
switch info.endianness {
|
||||||
case Platform: return false;
|
case .Platform: return false;
|
||||||
case Little: return ODIN_ENDIAN != "little";
|
case .Little: return ODIN_ENDIAN != "little";
|
||||||
case Big: return ODIN_ENDIAN != "big";
|
case .Big: return ODIN_ENDIAN != "big";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -1008,6 +1006,20 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
|
|||||||
fmt_arg(fi, any{rawptr(data), info.elem.id}, verb);
|
fmt_arg(fi, any{rawptr(data), info.elem.id}, verb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case runtime.Type_Info_Simd_Vector:
|
||||||
|
if info.is_x86_mmx {
|
||||||
|
strings.write_string(fi.buf, "intrinsics.x86_mmx<>");
|
||||||
|
}
|
||||||
|
strings.write_byte(fi.buf, '<');
|
||||||
|
defer strings.write_byte(fi.buf, '>');
|
||||||
|
for i in 0..info.count-1 {
|
||||||
|
if i > 0 do strings.write_string(fi.buf, ", ");
|
||||||
|
|
||||||
|
data := uintptr(v.data) + uintptr(i*info.elem_size);
|
||||||
|
fmt_arg(fi, any{rawptr(data), info.elem.id}, verb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
case runtime.Type_Info_Slice:
|
case runtime.Type_Info_Slice:
|
||||||
strings.write_byte(fi.buf, '[');
|
strings.write_byte(fi.buf, '[');
|
||||||
defer strings.write_byte(fi.buf, ']');
|
defer strings.write_byte(fi.buf, ']');
|
||||||
@@ -1448,5 +1460,15 @@ write_type :: proc(buf: ^strings.Builder, ti: ^runtime.Type_Info) {
|
|||||||
write_string(buf, "opaque ");
|
write_string(buf, "opaque ");
|
||||||
write_type(buf, info.elem);
|
write_type(buf, info.elem);
|
||||||
|
|
||||||
|
case runtime.Type_Info_Simd_Vector:
|
||||||
|
if info.is_x86_mmx {
|
||||||
|
write_string(buf, "intrinsics.x86_mmx");
|
||||||
|
} else {
|
||||||
|
write_string(buf, "intrinsics.vector(");
|
||||||
|
write_i64(buf, i64(info.count));
|
||||||
|
write_string(buf, ", ");
|
||||||
|
write_type(buf, info.elem);
|
||||||
|
write_byte(buf, ')');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,12 +47,10 @@ arena_allocator :: proc(arena: ^Arena) -> Allocator {
|
|||||||
arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||||
size, alignment: int,
|
size, alignment: int,
|
||||||
old_memory: rawptr, old_size: int, flags: u64, location := #caller_location) -> rawptr {
|
old_memory: rawptr, old_size: int, flags: u64, location := #caller_location) -> rawptr {
|
||||||
using Allocator_Mode;
|
|
||||||
arena := cast(^Arena)allocator_data;
|
arena := cast(^Arena)allocator_data;
|
||||||
|
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case Alloc:
|
case .Alloc:
|
||||||
total_size := size + alignment;
|
total_size := size + alignment;
|
||||||
|
|
||||||
if arena.offset + total_size > len(arena.data) {
|
if arena.offset + total_size > len(arena.data) {
|
||||||
@@ -66,14 +64,14 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
arena.peak_used = max(arena.peak_used, arena.offset);
|
arena.peak_used = max(arena.peak_used, arena.offset);
|
||||||
return zero(ptr, size);
|
return zero(ptr, size);
|
||||||
|
|
||||||
case Free:
|
case .Free:
|
||||||
// NOTE(bill): Free all at once
|
// NOTE(bill): Free all at once
|
||||||
// Use Arena_Temp_Memory if you want to free a block
|
// Use Arena_Temp_Memory if you want to free a block
|
||||||
|
|
||||||
case Free_All:
|
case .Free_All:
|
||||||
arena.offset = 0;
|
arena.offset = 0;
|
||||||
|
|
||||||
case Resize:
|
case .Resize:
|
||||||
return default_resize_align(old_memory, old_size, size, alignment, arena_allocator(arena));
|
return default_resize_align(old_memory, old_size, size, alignment, arena_allocator(arena));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,7 +225,6 @@ stack_allocator :: proc(stack: ^Stack) -> Allocator {
|
|||||||
stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||||
size, alignment: int,
|
size, alignment: int,
|
||||||
old_memory: rawptr, old_size: int, flags: u64, location := #caller_location) -> rawptr {
|
old_memory: rawptr, old_size: int, flags: u64, location := #caller_location) -> rawptr {
|
||||||
using Allocator_Mode;
|
|
||||||
s := cast(^Stack)allocator_data;
|
s := cast(^Stack)allocator_data;
|
||||||
|
|
||||||
if s.data == nil {
|
if s.data == nil {
|
||||||
@@ -256,9 +253,9 @@ stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case Alloc:
|
case .Alloc:
|
||||||
return raw_alloc(s, size, alignment);
|
return raw_alloc(s, size, alignment);
|
||||||
case Free:
|
case .Free:
|
||||||
if old_memory == nil {
|
if old_memory == nil {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
@@ -288,11 +285,11 @@ stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
s.prev_offset = int(header.prev_offset);
|
s.prev_offset = int(header.prev_offset);
|
||||||
|
|
||||||
|
|
||||||
case Free_All:
|
case .Free_All:
|
||||||
s.prev_offset = 0;
|
s.prev_offset = 0;
|
||||||
s.curr_offset = 0;
|
s.curr_offset = 0;
|
||||||
|
|
||||||
case Resize:
|
case .Resize:
|
||||||
if old_memory == nil {
|
if old_memory == nil {
|
||||||
return raw_alloc(s, size, alignment);
|
return raw_alloc(s, size, alignment);
|
||||||
}
|
}
|
||||||
@@ -374,13 +371,14 @@ small_stack_allocator :: proc(stack: ^Small_Stack) -> Allocator {
|
|||||||
small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||||
size, alignment: int,
|
size, alignment: int,
|
||||||
old_memory: rawptr, old_size: int, flags: u64, location := #caller_location) -> rawptr {
|
old_memory: rawptr, old_size: int, flags: u64, location := #caller_location) -> rawptr {
|
||||||
using Allocator_Mode;
|
|
||||||
s := cast(^Small_Stack)allocator_data;
|
s := cast(^Small_Stack)allocator_data;
|
||||||
|
|
||||||
if s.data == nil {
|
if s.data == nil {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
alignment = clamp(alignment, 1, 8*size_of(Stack_Allocation_Header{}.padding)/2);
|
||||||
|
|
||||||
raw_alloc :: proc(s: ^Small_Stack, size, alignment: int) -> rawptr {
|
raw_alloc :: proc(s: ^Small_Stack, size, alignment: int) -> rawptr {
|
||||||
curr_addr := uintptr(&s.data[0]) + uintptr(s.offset);
|
curr_addr := uintptr(&s.data[0]) + uintptr(s.offset);
|
||||||
padding := calc_padding_with_header(curr_addr, uintptr(alignment), size_of(Small_Stack_Allocation_Header));
|
padding := calc_padding_with_header(curr_addr, uintptr(alignment), size_of(Small_Stack_Allocation_Header));
|
||||||
@@ -401,9 +399,9 @@ small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case Alloc:
|
case .Alloc:
|
||||||
return raw_alloc(s, size, alignment);
|
return raw_alloc(s, size, alignment);
|
||||||
case Free:
|
case .Free:
|
||||||
if old_memory == nil {
|
if old_memory == nil {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
@@ -426,10 +424,10 @@ small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
|
|
||||||
s.offset = int(old_offset);
|
s.offset = int(old_offset);
|
||||||
|
|
||||||
case Free_All:
|
case .Free_All:
|
||||||
s.offset = 0;
|
s.offset = 0;
|
||||||
|
|
||||||
case Resize:
|
case .Resize:
|
||||||
if old_memory == nil {
|
if old_memory == nil {
|
||||||
return raw_alloc(s, size, alignment);
|
return raw_alloc(s, size, alignment);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -183,6 +183,14 @@ align_forward_uintptr :: proc(ptr, align: uintptr) -> uintptr {
|
|||||||
return uintptr(p);
|
return uintptr(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
align_forward_int :: inline proc(ptr, align: int) -> int {
|
||||||
|
return int(align_forward_uintptr(uintptr(ptr), uintptr(align)));
|
||||||
|
}
|
||||||
|
align_forward_uint :: inline proc(ptr, align: uint) -> uint {
|
||||||
|
return uint(align_forward_uintptr(uintptr(ptr), uintptr(align)));
|
||||||
|
}
|
||||||
|
|
||||||
context_from_allocator :: proc(a: Allocator) -> type_of(context) {
|
context_from_allocator :: proc(a: Allocator) -> type_of(context) {
|
||||||
context.allocator = a;
|
context.allocator = a;
|
||||||
return context;
|
return context;
|
||||||
|
|||||||
@@ -144,6 +144,10 @@ Selector_Expr :: struct {
|
|||||||
field: ^Ident,
|
field: ^Ident,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Implicit_Selector_Expr :: struct {
|
||||||
|
using node: Expr,
|
||||||
|
field: ^Ident,
|
||||||
|
}
|
||||||
|
|
||||||
Index_Expr :: struct {
|
Index_Expr :: struct {
|
||||||
using node: Expr,
|
using node: Expr,
|
||||||
@@ -365,7 +369,6 @@ Value_Decl :: struct {
|
|||||||
type: ^Expr,
|
type: ^Expr,
|
||||||
values: []^Expr,
|
values: []^Expr,
|
||||||
comment: ^Comment_Group,
|
comment: ^Comment_Group,
|
||||||
is_static: bool,
|
|
||||||
is_using: bool,
|
is_using: bool,
|
||||||
is_mutable: bool,
|
is_mutable: bool,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -857,10 +857,6 @@ parse_foreign_block :: proc(p: ^Parser, tok: token.Token) -> ^ast.Foreign_Block_
|
|||||||
|
|
||||||
foreign_library: ^ast.Expr;
|
foreign_library: ^ast.Expr;
|
||||||
switch p.curr_tok.kind {
|
switch p.curr_tok.kind {
|
||||||
case token.Export:
|
|
||||||
i := ast.new(ast.Implicit, tok.pos, end_pos(tok));
|
|
||||||
i.tok = expect_token(p, token.Export);
|
|
||||||
foreign_library = i;
|
|
||||||
case token.Open_Brace:
|
case token.Open_Brace:
|
||||||
i := ast.new(ast.Ident, tok.pos, end_pos(tok));
|
i := ast.new(ast.Ident, tok.pos, end_pos(tok));
|
||||||
i.name = "_";
|
i.name = "_";
|
||||||
@@ -903,7 +899,7 @@ parse_foreign_decl :: proc(p: ^Parser) -> ^ast.Decl {
|
|||||||
tok := expect_token(p, token.Foreign);
|
tok := expect_token(p, token.Foreign);
|
||||||
|
|
||||||
switch p.curr_tok.kind {
|
switch p.curr_tok.kind {
|
||||||
case token.Export, token.Ident, token.Open_Brace:
|
case token.Ident, token.Open_Brace:
|
||||||
return parse_foreign_block(p, tok);
|
return parse_foreign_block(p, tok);
|
||||||
|
|
||||||
case token.Import:
|
case token.Import:
|
||||||
@@ -1033,37 +1029,6 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
|||||||
expect_semicolon(p, s);
|
expect_semicolon(p, s);
|
||||||
return s;
|
return s;
|
||||||
|
|
||||||
case token.Static:
|
|
||||||
docs := p.lead_comment;
|
|
||||||
tok := expect_token(p, token.Static);
|
|
||||||
|
|
||||||
list := parse_lhs_expr_list(p);
|
|
||||||
if len(list) == 0 {
|
|
||||||
error(p, tok.pos, "illegal use of 'static' statement");
|
|
||||||
expect_semicolon(p, nil);
|
|
||||||
return ast.new(ast.Bad_Stmt, tok.pos, end_pos(p.prev_tok));
|
|
||||||
}
|
|
||||||
|
|
||||||
expect_token_after(p, token.Colon, "identifier list");
|
|
||||||
decl := parse_value_decl(p, list, docs);
|
|
||||||
if decl != nil do switch d in &decl.derived {
|
|
||||||
case ast.Value_Decl:
|
|
||||||
if d.is_mutable {
|
|
||||||
d.is_static = true;
|
|
||||||
} else {
|
|
||||||
error(p, tok.pos, "'static' may only be currently used with variable declarations");
|
|
||||||
}
|
|
||||||
case:
|
|
||||||
error(p, tok.pos, "illegal use of 'static' statement");
|
|
||||||
}
|
|
||||||
|
|
||||||
error(p, tok.pos, "illegal use of 'static' statement");
|
|
||||||
if decl != nil {
|
|
||||||
return decl;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ast.new(ast.Bad_Stmt, tok.pos, end_pos(p.prev_tok));
|
|
||||||
|
|
||||||
case token.Using:
|
case token.Using:
|
||||||
docs := p.lead_comment;
|
docs := p.lead_comment;
|
||||||
tok := expect_token(p, token.Using);
|
tok := expect_token(p, token.Using);
|
||||||
@@ -1112,9 +1077,9 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
|||||||
stmt := parse_stmt(p);
|
stmt := parse_stmt(p);
|
||||||
switch name {
|
switch name {
|
||||||
case "bounds_check":
|
case "bounds_check":
|
||||||
stmt.state_flags |= {ast.Node_State_Flag.Bounds_Check};
|
stmt.state_flags |= {.Bounds_Check};
|
||||||
case "no_bounds_check":
|
case "no_bounds_check":
|
||||||
stmt.state_flags |= {ast.Node_State_Flag.No_Bounds_Check};
|
stmt.state_flags |= {.No_Bounds_Check};
|
||||||
}
|
}
|
||||||
return stmt;
|
return stmt;
|
||||||
case "complete":
|
case "complete":
|
||||||
@@ -1758,6 +1723,29 @@ string_to_calling_convention :: proc(s: string) -> ast.Proc_Calling_Convention {
|
|||||||
return Invalid;
|
return Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parse_proc_tags :: proc(p: ^Parser) -> (tags: Proc_Tags) {
|
||||||
|
for p.curr_tok.kind == token.Hash {
|
||||||
|
tok := expect_token(p, token.Hash);
|
||||||
|
ident := expect_token(p, token.Ident);
|
||||||
|
|
||||||
|
switch ident.text {
|
||||||
|
case "require_results":
|
||||||
|
tags |= {.Require_Results};
|
||||||
|
case "bounds_check":
|
||||||
|
tags |= {.Bounds_Check};
|
||||||
|
case "no_bounds_check":
|
||||||
|
tags |= {.No_Bounds_Check};
|
||||||
|
case:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if .Bounds_Check in tags && .No_Bounds_Check in tags {
|
||||||
|
p.err(p.curr_tok.pos, "#bounds_check and #no_bounds_check applied to the same procedure type");
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
parse_proc_type :: proc(p: ^Parser, tok: token.Token) -> ^ast.Proc_Type {
|
parse_proc_type :: proc(p: ^Parser, tok: token.Token) -> ^ast.Proc_Type {
|
||||||
cc := ast.Proc_Calling_Convention.Invalid;
|
cc := ast.Proc_Calling_Convention.Invalid;
|
||||||
if p.curr_tok.kind == token.String {
|
if p.curr_tok.kind == token.String {
|
||||||
@@ -2616,6 +2604,13 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
|||||||
ue.expr = expr;
|
ue.expr = expr;
|
||||||
return ue;
|
return ue;
|
||||||
|
|
||||||
|
case token.Period:
|
||||||
|
op := advance_token(p);
|
||||||
|
field := parse_ident(p);
|
||||||
|
ise := ast.new(ast.Implicit_Selector_Expr, op.pos, field.end);
|
||||||
|
ise.field = field;
|
||||||
|
return ise;
|
||||||
|
|
||||||
}
|
}
|
||||||
return parse_atom_expr(p, parse_operand(p, lhs), lhs);
|
return parse_atom_expr(p, parse_operand(p, lhs), lhs);
|
||||||
}
|
}
|
||||||
@@ -2707,7 +2702,7 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt {
|
|||||||
return stmt;
|
return stmt;
|
||||||
|
|
||||||
case op.kind == token.In:
|
case op.kind == token.In:
|
||||||
if Stmt_Allow_Flag.In in flags {
|
if .In in flags {
|
||||||
allow_token(p, token.In);
|
allow_token(p, token.In);
|
||||||
prev_allow_range := p.allow_range;
|
prev_allow_range := p.allow_range;
|
||||||
p.allow_range = true;
|
p.allow_range = true;
|
||||||
@@ -2725,7 +2720,7 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt {
|
|||||||
}
|
}
|
||||||
case op.kind == token.Colon:
|
case op.kind == token.Colon:
|
||||||
expect_token_after(p, token.Colon, "identifier list");
|
expect_token_after(p, token.Colon, "identifier list");
|
||||||
if Stmt_Allow_Flag.Label in flags && len(lhs) == 1 {
|
if .Label in flags && len(lhs) == 1 {
|
||||||
switch p.curr_tok.kind {
|
switch p.curr_tok.kind {
|
||||||
case token.Open_Brace, token.If, token.For, token.Switch:
|
case token.Open_Brace, token.If, token.For, token.Switch:
|
||||||
label := lhs[0];
|
label := lhs[0];
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ pos_compare :: proc(lhs, rhs: Pos) -> int {
|
|||||||
return strings.compare(lhs.file, rhs.file);
|
return strings.compare(lhs.file, rhs.file);
|
||||||
}
|
}
|
||||||
|
|
||||||
using Kind :: enum u16 {
|
using Kind :: enum u32 {
|
||||||
Invalid,
|
Invalid,
|
||||||
EOF,
|
EOF,
|
||||||
Comment,
|
Comment,
|
||||||
@@ -113,7 +113,6 @@ using Kind :: enum u16 {
|
|||||||
|
|
||||||
B_Keyword_Begin,
|
B_Keyword_Begin,
|
||||||
Import,
|
Import,
|
||||||
Export,
|
|
||||||
Foreign,
|
Foreign,
|
||||||
Package,
|
Package,
|
||||||
Typeid,
|
Typeid,
|
||||||
@@ -139,7 +138,6 @@ using Kind :: enum u16 {
|
|||||||
Bit_Field,
|
Bit_Field,
|
||||||
Bit_Set,
|
Bit_Set,
|
||||||
Map,
|
Map,
|
||||||
Static,
|
|
||||||
Dynamic,
|
Dynamic,
|
||||||
Auto_Cast,
|
Auto_Cast,
|
||||||
Cast,
|
Cast,
|
||||||
@@ -161,6 +159,9 @@ using Kind :: enum u16 {
|
|||||||
B_Keyword_End,
|
B_Keyword_End,
|
||||||
|
|
||||||
COUNT,
|
COUNT,
|
||||||
|
|
||||||
|
B_Custom_Keyword_Begin = COUNT+1,
|
||||||
|
// ... Custom keywords
|
||||||
};
|
};
|
||||||
|
|
||||||
tokens := [Kind.COUNT]string {
|
tokens := [Kind.COUNT]string {
|
||||||
@@ -248,7 +249,6 @@ tokens := [Kind.COUNT]string {
|
|||||||
|
|
||||||
"",
|
"",
|
||||||
"import",
|
"import",
|
||||||
"export",
|
|
||||||
"foreign",
|
"foreign",
|
||||||
"package",
|
"package",
|
||||||
"typeid",
|
"typeid",
|
||||||
@@ -274,7 +274,6 @@ tokens := [Kind.COUNT]string {
|
|||||||
"bit_field",
|
"bit_field",
|
||||||
"bit_set",
|
"bit_set",
|
||||||
"map",
|
"map",
|
||||||
"static",
|
|
||||||
"dynamic",
|
"dynamic",
|
||||||
"auto_cast",
|
"auto_cast",
|
||||||
"cast",
|
"cast",
|
||||||
@@ -296,10 +295,19 @@ tokens := [Kind.COUNT]string {
|
|||||||
"",
|
"",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
custom_keyword_tokens: []string;
|
||||||
|
|
||||||
to_string :: proc(kind: Kind) -> string {
|
to_string :: proc(kind: Kind) -> string {
|
||||||
if min(Kind) <= kind && kind <= max(Kind) {
|
if Invalid <= kind && kind < COUNT {
|
||||||
return tokens[kind];
|
return tokens[kind];
|
||||||
}
|
}
|
||||||
|
if B_Custom_Keyword_Begin < kind {
|
||||||
|
n := int(u16(kind)-u16(B_Custom_Keyword_Begin));
|
||||||
|
if n < len(custom_keyword_tokens) {
|
||||||
|
return custom_keyword_tokens[n];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return "Invalid";
|
return "Invalid";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,4 +324,12 @@ is_operator :: proc(kind: Kind) -> bool {
|
|||||||
is_assignment_operator :: proc(kind: Kind) -> bool {
|
is_assignment_operator :: proc(kind: Kind) -> bool {
|
||||||
return B_Assign_Op_Begin < kind && kind < B_Assign_Op_End || kind == Eq;
|
return B_Assign_Op_Begin < kind && kind < B_Assign_Op_End || kind == Eq;
|
||||||
}
|
}
|
||||||
is_keyword :: proc(kind: Kind) -> bool { return B_Keyword_Begin < kind && kind < B_Keyword_End; }
|
is_keyword :: proc(kind: Kind) -> bool {
|
||||||
|
switch {
|
||||||
|
case B_Keyword_Begin < kind && kind < B_Keyword_End:
|
||||||
|
return true;
|
||||||
|
case B_Custom_Keyword_Begin < kind:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -486,12 +486,18 @@ scan :: proc(t: ^Tokenizer) -> token.Token {
|
|||||||
case is_letter(ch):
|
case is_letter(ch):
|
||||||
lit = scan_identifier(t);
|
lit = scan_identifier(t);
|
||||||
kind = token.Ident;
|
kind = token.Ident;
|
||||||
if len(lit) > 1 {
|
check_keyword: if len(lit) > 1 {
|
||||||
// TODO(bill): Maybe have a hash table lookup rather than this linear search
|
// TODO(bill): Maybe have a hash table lookup rather than this linear search
|
||||||
for i in token.B_Keyword_Begin .. token.B_Keyword_End {
|
for i in token.B_Keyword_Begin .. token.B_Keyword_End {
|
||||||
if lit == token.tokens[i] {
|
if lit == token.tokens[i] {
|
||||||
kind = token.Kind(i);
|
kind = token.Kind(i);
|
||||||
break;
|
break check_keyword;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for keyword, i in token.custom_keyword_tokens {
|
||||||
|
if lit == keyword {
|
||||||
|
kind = token.Kind(i+1)+token.B_Custom_Keyword_Begin;
|
||||||
|
break check_keyword;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,20 @@ write_encoded_rune :: proc(fd: Handle, r: rune) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
file_size_from_path :: proc(path: string) -> i64 {
|
||||||
|
fd, err := open(path, O_RDONLY, 0);
|
||||||
|
if err != 0 {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
defer close(fd);
|
||||||
|
|
||||||
|
length: i64;
|
||||||
|
if length, err = file_size(fd); err != 0 {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
read_entire_file :: proc(name: string) -> (data: []byte, success: bool) {
|
read_entire_file :: proc(name: string) -> (data: []byte, success: bool) {
|
||||||
fd, err := open(name, O_RDONLY, 0);
|
fd, err := open(name, O_RDONLY, 0);
|
||||||
if err != 0 {
|
if err != 0 {
|
||||||
@@ -109,20 +123,18 @@ read_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) {
|
|||||||
heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
||||||
size, alignment: int,
|
size, alignment: int,
|
||||||
old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr {
|
old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr {
|
||||||
using mem.Allocator_Mode;
|
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case Alloc:
|
case .Alloc:
|
||||||
return heap_alloc(size);
|
return heap_alloc(size);
|
||||||
|
|
||||||
case Free:
|
case .Free:
|
||||||
heap_free(old_memory);
|
heap_free(old_memory);
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
case Free_All:
|
case .Free_All:
|
||||||
// NOTE(bill): Does nothing
|
// NOTE(bill): Does nothing
|
||||||
|
|
||||||
case Resize:
|
case .Resize:
|
||||||
if old_memory == nil {
|
if old_memory == nil {
|
||||||
return heap_alloc(size);
|
return heap_alloc(size);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,9 +112,14 @@ Type_Info_Bit_Set :: struct {
|
|||||||
lower: i64,
|
lower: i64,
|
||||||
upper: i64,
|
upper: i64,
|
||||||
};
|
};
|
||||||
|
|
||||||
Type_Info_Opaque :: struct {
|
Type_Info_Opaque :: struct {
|
||||||
elem: ^Type_Info,
|
elem: ^Type_Info,
|
||||||
|
};
|
||||||
|
Type_Info_Simd_Vector :: struct {
|
||||||
|
elem: ^Type_Info,
|
||||||
|
elem_size: int,
|
||||||
|
count: int,
|
||||||
|
is_x86_mmx: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
Type_Info :: struct {
|
Type_Info :: struct {
|
||||||
@@ -145,6 +150,7 @@ Type_Info :: struct {
|
|||||||
Type_Info_Bit_Field,
|
Type_Info_Bit_Field,
|
||||||
Type_Info_Bit_Set,
|
Type_Info_Bit_Set,
|
||||||
Type_Info_Opaque,
|
Type_Info_Opaque,
|
||||||
|
Type_Info_Simd_Vector,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,8 +251,10 @@ Map_Entry_Header :: struct {
|
|||||||
Map_Header :: struct {
|
Map_Header :: struct {
|
||||||
m: ^mem.Raw_Map,
|
m: ^mem.Raw_Map,
|
||||||
is_key_string: bool,
|
is_key_string: bool,
|
||||||
|
|
||||||
entry_size: int,
|
entry_size: int,
|
||||||
entry_align: int,
|
entry_align: int,
|
||||||
|
|
||||||
value_offset: uintptr,
|
value_offset: uintptr,
|
||||||
value_size: int,
|
value_size: int,
|
||||||
}
|
}
|
||||||
@@ -827,29 +835,23 @@ __get_map_key :: proc "contextless" (key: $K) -> Map_Key {
|
|||||||
return map_key;
|
return map_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_fnv64a :: proc(data: []byte, seed: u64 = 0xcbf29ce484222325) -> u64 {
|
||||||
|
h: u64 = seed;
|
||||||
|
for b in data {
|
||||||
|
h = (h ~ u64(b)) * 0x100000001b3;
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
default_hash :: proc(data: []byte) -> u64 {
|
default_hash :: proc(data: []byte) -> u64 {
|
||||||
fnv64a :: proc(data: []byte) -> u64 {
|
return _fnv64a(data);
|
||||||
h: u64 = 0xcbf29ce484222325;
|
|
||||||
for b in data {
|
|
||||||
h = (h ~ u64(b)) * 0x100000001b3;
|
|
||||||
}
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
return fnv64a(data);
|
|
||||||
}
|
}
|
||||||
default_hash_string :: proc(s: string) -> u64 do return default_hash(([]byte)(s));
|
default_hash_string :: proc(s: string) -> u64 do return default_hash(([]byte)(s));
|
||||||
|
|
||||||
|
|
||||||
source_code_location_hash :: proc(s: Source_Code_Location) -> u64 {
|
source_code_location_hash :: proc(s: Source_Code_Location) -> u64 {
|
||||||
fnv64a :: proc(data: []byte, seed: u64 = 0xcbf29ce484222325) -> u64 {
|
hash := _fnv64a(cast([]byte)s.file_path);
|
||||||
h: u64 = seed;
|
|
||||||
for b in data {
|
|
||||||
h = (h ~ u64(b)) * 0x100000001b3;
|
|
||||||
}
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
hash := fnv64a(cast([]byte)s.file_path);
|
|
||||||
hash = hash ~ (u64(s.line) * 0x100000001b3);
|
hash = hash ~ (u64(s.line) * 0x100000001b3);
|
||||||
hash = hash ~ (u64(s.column) * 0x100000001b3);
|
hash = hash ~ (u64(s.column) * 0x100000001b3);
|
||||||
return hash;
|
return hash;
|
||||||
@@ -857,7 +859,6 @@ source_code_location_hash :: proc(s: Source_Code_Location) -> u64 {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
__slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: mem.Allocator, loc := #caller_location) -> bool {
|
__slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: mem.Allocator, loc := #caller_location) -> bool {
|
||||||
array := (^mem.Raw_Slice)(array_);
|
array := (^mem.Raw_Slice)(array_);
|
||||||
|
|
||||||
@@ -936,7 +937,6 @@ __dynamic_map_get :: proc(h: Map_Header, key: Map_Key) -> rawptr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
__dynamic_map_set :: proc(h: Map_Header, key: Map_Key, value: rawptr, loc := #caller_location) #no_bounds_check {
|
__dynamic_map_set :: proc(h: Map_Header, key: Map_Key, value: rawptr, loc := #caller_location) #no_bounds_check {
|
||||||
|
|
||||||
index: int;
|
index: int;
|
||||||
assert(value != nil);
|
assert(value != nil);
|
||||||
|
|
||||||
|
|||||||
@@ -475,7 +475,7 @@ append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: i
|
|||||||
}
|
}
|
||||||
i-=1; a[i] = digits[u % b];
|
i-=1; a[i] = digits[u % b];
|
||||||
|
|
||||||
if Int_Flag.Prefix in flags {
|
if .Prefix in flags {
|
||||||
ok := true;
|
ok := true;
|
||||||
switch base {
|
switch base {
|
||||||
case 2: i-=1; a[i] = 'b';
|
case 2: i-=1; a[i] = 'b';
|
||||||
@@ -493,9 +493,9 @@ append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: i
|
|||||||
switch {
|
switch {
|
||||||
case neg:
|
case neg:
|
||||||
i-=1; a[i] = '-';
|
i-=1; a[i] = '-';
|
||||||
case Int_Flag.Plus in flags:
|
case .Plus in flags:
|
||||||
i-=1; a[i] = '+';
|
i-=1; a[i] = '+';
|
||||||
case Int_Flag.Space in flags:
|
case .Space in flags:
|
||||||
i-=1; a[i] = ' ';
|
i-=1; a[i] = ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,8 +61,8 @@ write_bytes :: proc(b: ^Builder, x: []byte) {
|
|||||||
append(&b.buf, ..x);
|
append(&b.buf, ..x);
|
||||||
}
|
}
|
||||||
|
|
||||||
@(private)
|
@(private, static)
|
||||||
static DIGITS_LOWER := "0123456789abcdefx";
|
DIGITS_LOWER := "0123456789abcdefx";
|
||||||
|
|
||||||
write_quoted_string :: proc(b: ^Builder, s: string, quote: byte = '"') {
|
write_quoted_string :: proc(b: ^Builder, s: string, quote: byte = '"') {
|
||||||
write_byte(b, quote);
|
write_byte(b, quote);
|
||||||
|
|||||||
@@ -329,6 +329,10 @@ is_space :: proc(r: rune) -> bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is_null :: proc(r: rune) -> bool {
|
||||||
|
return r == 0x0000;
|
||||||
|
}
|
||||||
|
|
||||||
index_proc :: proc(s: string, p: proc(rune) -> bool, truth := true) -> int {
|
index_proc :: proc(s: string, p: proc(rune) -> bool, truth := true) -> int {
|
||||||
for r, i in s {
|
for r, i in s {
|
||||||
if p(r) == truth {
|
if p(r) == truth {
|
||||||
@@ -478,6 +482,19 @@ trim_space :: proc(s: string) -> string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
trim_left_null :: proc(s: string) -> string {
|
||||||
|
return trim_left_proc(s, is_null);
|
||||||
|
}
|
||||||
|
|
||||||
|
trim_right_null :: proc(s: string) -> string {
|
||||||
|
return trim_right_proc(s, is_null);
|
||||||
|
}
|
||||||
|
|
||||||
|
trim_null :: proc(s: string) -> string {
|
||||||
|
return trim_right_null(trim_left_null(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// returns a slice of sub-strings into `s`
|
// returns a slice of sub-strings into `s`
|
||||||
// `allocator` is used only for the slice
|
// `allocator` is used only for the slice
|
||||||
// `skip_empty=true` does not return zero-length substrings
|
// `skip_empty=true` does not return zero-length substrings
|
||||||
|
|||||||
@@ -2,6 +2,11 @@ package sync
|
|||||||
|
|
||||||
import "core:sys/win32"
|
import "core:sys/win32"
|
||||||
|
|
||||||
|
foreign {
|
||||||
|
@(link_name="llvm.x86.sse2.pause")
|
||||||
|
yield_processor :: proc() ---
|
||||||
|
}
|
||||||
|
|
||||||
Semaphore :: struct {
|
Semaphore :: struct {
|
||||||
_handle: win32.Handle,
|
_handle: win32.Handle,
|
||||||
}
|
}
|
||||||
@@ -14,6 +19,12 @@ Condition :: struct {
|
|||||||
event: win32.Handle,
|
event: win32.Handle,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ticket_Mutex :: struct {
|
||||||
|
ticket: u64,
|
||||||
|
serving: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
current_thread_id :: proc() -> i32 {
|
current_thread_id :: proc() -> i32 {
|
||||||
return i32(win32.get_current_thread_id());
|
return i32(win32.get_current_thread_id());
|
||||||
}
|
}
|
||||||
@@ -81,3 +92,20 @@ condition_destroy :: proc(using c: ^Condition) {
|
|||||||
win32.close_handle(event);
|
win32.close_handle(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ticket_mutex_init :: proc(m: ^Ticket_Mutex) {
|
||||||
|
atomic_store(&m.ticket, 0, Ordering.Relaxed);
|
||||||
|
atomic_store(&m.serving, 0, Ordering.Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
ticket_mutex_lock :: inline proc(m: ^Ticket_Mutex) {
|
||||||
|
ticket := atomic_add(&m.ticket, 1, Ordering.Relaxed);
|
||||||
|
for ticket != m.serving {
|
||||||
|
yield_processor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ticket_mutex_unlock :: inline proc(m: ^Ticket_Mutex) {
|
||||||
|
atomic_add(&m.serving, 1, Ordering.Relaxed);
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
package win32
|
package win32
|
||||||
|
|
||||||
foreign import "system:comdlg32.lib"
|
foreign import "system:comdlg32.lib"
|
||||||
|
import "core:strings"
|
||||||
|
|
||||||
OFN_Hook_Proc :: #type proc "stdcall" (hdlg: Hwnd, msg: u32, wparam: Wparam, lparam: Lparam) -> Uint_Ptr;
|
OFN_Hook_Proc :: #type proc "stdcall" (hdlg: Hwnd, msg: u32, wparam: Wparam, lparam: Lparam) -> Uint_Ptr;
|
||||||
|
|
||||||
@@ -61,11 +62,91 @@ Open_File_Name_W :: struct {
|
|||||||
foreign comdlg32 {
|
foreign comdlg32 {
|
||||||
@(link_name="GetOpenFileNameA") get_open_file_name_a :: proc(arg1: ^Open_File_Name_A) -> Bool ---
|
@(link_name="GetOpenFileNameA") get_open_file_name_a :: proc(arg1: ^Open_File_Name_A) -> Bool ---
|
||||||
@(link_name="GetOpenFileNameW") get_open_file_name_w :: proc(arg1: ^Open_File_Name_W) -> Bool ---
|
@(link_name="GetOpenFileNameW") get_open_file_name_w :: proc(arg1: ^Open_File_Name_W) -> Bool ---
|
||||||
|
@(link_name="GetSaveFileNameA") get_save_file_name_a :: proc(arg1: ^Open_File_Name_A) -> Bool ---
|
||||||
|
@(link_name="GetSaveFileNameW") get_save_file_name_w :: proc(arg1: ^Open_File_Name_W) -> Bool ---
|
||||||
@(link_name="CommDlgExtendedError") comm_dlg_extended_error :: proc() -> u32 ---
|
@(link_name="CommDlgExtendedError") comm_dlg_extended_error :: proc() -> u32 ---
|
||||||
}
|
}
|
||||||
|
|
||||||
OFN_ALLOWMULTISELECT :: 0x00000200;
|
OPEN_TITLE :: "Select file to open";
|
||||||
|
OPEN_FLAGS :: u32(OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST);
|
||||||
|
OPEN_FLAGS_MULTI :: u32(OPEN_FLAGS | OFN_ALLOWMULTISELECT | OFN_EXPLORER);
|
||||||
|
|
||||||
|
SAVE_TITLE :: "Select file to save";
|
||||||
|
SAVE_FLAGS :: u32(OFN_OVERWRITEPROMPT | OFN_EXPLORER);
|
||||||
|
SAVE_EXT :: "txt";
|
||||||
|
|
||||||
|
Open_Save_Mode :: enum {
|
||||||
|
Open = 0,
|
||||||
|
Save = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
_open_file_dialog :: proc(title: string, dir: string,
|
||||||
|
filters: []string, default_filter: u32,
|
||||||
|
flags: u32, default_ext: string,
|
||||||
|
mode: Open_Save_Mode, allocator := context.temp_allocator) -> (path: string, ok: bool = true) {
|
||||||
|
file_buf := make([]u16, MAX_PATH_WIDE, allocator);
|
||||||
|
|
||||||
|
// Filters need to be passed as a pair of strings (title, filter)
|
||||||
|
filter_len := u32(len(filters));
|
||||||
|
if filter_len % 2 != 0 do return "", false;
|
||||||
|
default_filter = clamp(default_filter, 1, filter_len / 2);
|
||||||
|
|
||||||
|
filter: string;
|
||||||
|
filter = strings.join(filters, "\u0000", context.temp_allocator);
|
||||||
|
filter = strings.concatenate({filter, "\u0000"}, context.temp_allocator);
|
||||||
|
|
||||||
|
ofn := Open_File_Name_W{
|
||||||
|
struct_size = size_of(Open_File_Name_W),
|
||||||
|
file = Wstring(&file_buf[0]),
|
||||||
|
max_file = MAX_PATH_WIDE,
|
||||||
|
title = utf8_to_wstring(title, context.temp_allocator),
|
||||||
|
filter = utf8_to_wstring(filter, context.temp_allocator),
|
||||||
|
initial_dir = utf8_to_wstring(dir, context.temp_allocator),
|
||||||
|
filter_index = u32(default_filter),
|
||||||
|
def_ext = utf8_to_wstring(default_ext, context.temp_allocator),
|
||||||
|
flags = u32(flags),
|
||||||
|
};
|
||||||
|
|
||||||
|
switch mode {
|
||||||
|
case .Open:
|
||||||
|
ok = bool(get_open_file_name_w(&ofn));
|
||||||
|
case .Save:
|
||||||
|
ok = bool(get_save_file_name_w(&ofn));
|
||||||
|
case:
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
delete(file_buf);
|
||||||
|
return "", false;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_name := ucs2_to_utf8(file_buf[:], allocator);
|
||||||
|
path = strings.trim_right_null(file_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
select_file_to_open :: proc(title := OPEN_TITLE, dir := ".",
|
||||||
|
filters := []string{"All Files", "*.*"}, default_filter := u32(1),
|
||||||
|
flags := OPEN_FLAGS, allocator := context.temp_allocator) -> (path: string, ok: bool) {
|
||||||
|
|
||||||
|
path, ok = _open_file_dialog(title, dir, filters, default_filter, flags, "", Open_Save_Mode.Open, allocator);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
select_file_to_save :: proc(title := SAVE_TITLE, dir := ".",
|
||||||
|
filters := []string{"All Files", "*.*"}, default_filter := u32(1),
|
||||||
|
flags := SAVE_FLAGS, default_ext := SAVE_EXT,
|
||||||
|
allocator := context.temp_allocator) -> (path: string, ok: bool) {
|
||||||
|
|
||||||
|
path, ok = _open_file_dialog(title, dir, filters, default_filter, flags, default_ext, Open_Save_Mode.Save, allocator);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Implement convenience function for select_file_to_open with ALLOW_MULTI_SELECT that takes
|
||||||
|
// it output of the form "path\u0000\file1u\0000file2" and turns it into []string with the path + file pre-concatenated for you.
|
||||||
|
|
||||||
|
OFN_ALLOWMULTISELECT :: 0x00000200; // NOTE(Jeroen): Without OFN_EXPLORER it uses the Win3 dialog.
|
||||||
OFN_CREATEPROMPT :: 0x00002000;
|
OFN_CREATEPROMPT :: 0x00002000;
|
||||||
OFN_DONTADDTORECENT :: 0x02000000;
|
OFN_DONTADDTORECENT :: 0x02000000;
|
||||||
OFN_ENABLEHOOK :: 0x00000020;
|
OFN_ENABLEHOOK :: 0x00000020;
|
||||||
@@ -91,3 +172,18 @@ OFN_PATHMUSTEXIST :: 0x00000800;
|
|||||||
OFN_READONLY :: 0x00000001;
|
OFN_READONLY :: 0x00000001;
|
||||||
OFN_SHAREAWARE :: 0x00004000;
|
OFN_SHAREAWARE :: 0x00004000;
|
||||||
OFN_SHOWHELP :: 0x00000010;
|
OFN_SHOWHELP :: 0x00000010;
|
||||||
|
|
||||||
|
CDERR_DIALOGFAILURE :: 0x0000FFFF;
|
||||||
|
CDERR_GENERALCODES :: 0x00000000;
|
||||||
|
CDERR_STRUCTSIZE :: 0x00000001;
|
||||||
|
CDERR_INITIALIZATION :: 0x00000002;
|
||||||
|
CDERR_NOTEMPLATE :: 0x00000003;
|
||||||
|
CDERR_NOHINSTANCE :: 0x00000004;
|
||||||
|
CDERR_LOADSTRFAILURE :: 0x00000005;
|
||||||
|
CDERR_FINDRESFAILURE :: 0x00000006;
|
||||||
|
CDERR_LOADRESFAILURE :: 0x00000007;
|
||||||
|
CDERR_LOCKRESFAILURE :: 0x00000008;
|
||||||
|
CDERR_MEMALLOCFAILURE :: 0x00000009;
|
||||||
|
CDERR_MEMLOCKFAILURE :: 0x0000000A;
|
||||||
|
CDERR_NOHOOK :: 0x0000000B;
|
||||||
|
CDERR_REGISTERMSGFAIL :: 0x0000000C;
|
||||||
14
core/sys/win32/crt.odin
Normal file
14
core/sys/win32/crt.odin
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package win32
|
||||||
|
|
||||||
|
import "core:strings";
|
||||||
|
|
||||||
|
foreign {
|
||||||
|
@(link_name="_wgetcwd") _get_cwd_wide :: proc(buffer: Wstring, buf_len: int) -> ^Wstring ---
|
||||||
|
}
|
||||||
|
|
||||||
|
get_cwd :: proc(allocator := context.temp_allocator) -> string {
|
||||||
|
buffer := make([]u16, MAX_PATH_WIDE, allocator);
|
||||||
|
_get_cwd_wide(Wstring(&buffer[0]), MAX_PATH_WIDE);
|
||||||
|
file := ucs2_to_utf8(buffer[:], allocator);
|
||||||
|
return strings.trim_right_null(file);
|
||||||
|
}
|
||||||
@@ -108,6 +108,8 @@ File_Attribute_Data :: struct {
|
|||||||
file_size_low: u32,
|
file_size_low: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE(Jeroen): The widechar version might want at least the 32k MAX_PATH_WIDE
|
||||||
|
// https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-findfirstfilew#parameters
|
||||||
Find_Data_W :: struct{
|
Find_Data_W :: struct{
|
||||||
file_attributes: u32,
|
file_attributes: u32,
|
||||||
creation_time: Filetime,
|
creation_time: Filetime,
|
||||||
@@ -798,6 +800,7 @@ is_key_down :: inline proc(key: Key_Code) -> bool { return get_async_key_state(i
|
|||||||
|
|
||||||
|
|
||||||
MAX_PATH :: 0x00000104;
|
MAX_PATH :: 0x00000104;
|
||||||
|
MAX_PATH_WIDE :: 0x8000;
|
||||||
|
|
||||||
HANDLE_FLAG_INHERIT :: 1;
|
HANDLE_FLAG_INHERIT :: 1;
|
||||||
HANDLE_FLAG_PROTECT_FROM_CLOSE :: 2;
|
HANDLE_FLAG_PROTECT_FROM_CLOSE :: 2;
|
||||||
|
|||||||
@@ -56,8 +56,8 @@ foreign kernel32 {
|
|||||||
@(link_name="GetFileSizeEx") get_file_size_ex :: proc(file_handle: Handle, file_size: ^i64) -> Bool ---;
|
@(link_name="GetFileSizeEx") get_file_size_ex :: proc(file_handle: Handle, file_size: ^i64) -> Bool ---;
|
||||||
@(link_name="GetFileAttributesA") get_file_attributes_a :: proc(filename: cstring) -> u32 ---;
|
@(link_name="GetFileAttributesA") get_file_attributes_a :: proc(filename: cstring) -> u32 ---;
|
||||||
@(link_name="GetFileAttributesW") get_file_attributes_w :: proc(filename: Wstring) -> u32 ---;
|
@(link_name="GetFileAttributesW") get_file_attributes_w :: proc(filename: Wstring) -> u32 ---;
|
||||||
@(link_name="GetFileAttributesExA") get_file_attributes_ex_a :: proc(filename: cstring, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> Bool ---;
|
@(link_name="GetFileAttributesExA") get_file_attributes_ex_a :: proc(filename: cstring, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: ^File_Attribute_Data) -> Bool ---;
|
||||||
@(link_name="GetFileAttributesExW") get_file_attributes_ex_w :: proc(filename: Wstring, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> Bool ---;
|
@(link_name="GetFileAttributesExW") get_file_attributes_ex_w :: proc(filename: Wstring, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: ^File_Attribute_Data) -> Bool ---;
|
||||||
@(link_name="GetFileInformationByHandle") get_file_information_by_handle :: proc(file_handle: Handle, file_info: ^By_Handle_File_Information) -> Bool ---;
|
@(link_name="GetFileInformationByHandle") get_file_information_by_handle :: proc(file_handle: Handle, file_info: ^By_Handle_File_Information) -> Bool ---;
|
||||||
|
|
||||||
@(link_name="CreateDirectoryA") create_directory_a :: proc(path: cstring, security_attributes: ^Security_Attributes) -> Bool ---;
|
@(link_name="CreateDirectoryA") create_directory_a :: proc(path: cstring, security_attributes: ^Security_Attributes) -> Bool ---;
|
||||||
@@ -164,7 +164,7 @@ foreign kernel32 {
|
|||||||
|
|
||||||
@(link_name="LoadLibraryA") load_library_a :: proc(c_str: cstring) -> Hmodule ---;
|
@(link_name="LoadLibraryA") load_library_a :: proc(c_str: cstring) -> Hmodule ---;
|
||||||
@(link_name="LoadLibraryW") load_library_w :: proc(c_str: Wstring) -> Hmodule ---;
|
@(link_name="LoadLibraryW") load_library_w :: proc(c_str: Wstring) -> Hmodule ---;
|
||||||
@(link_name="FreeLibrary") free_library :: proc(h: Hmodule) ---;
|
@(link_name="FreeLibrary") free_library :: proc(h: Hmodule) -> Bool ---;
|
||||||
@(link_name="GetProcAddress") get_proc_address :: proc(h: Hmodule, c_str: cstring) -> rawptr ---;
|
@(link_name="GetProcAddress") get_proc_address :: proc(h: Hmodule, c_str: cstring) -> rawptr ---;
|
||||||
|
|
||||||
@(link_name="GetFullPathNameA") get_full_path_name_a :: proc(filename: cstring, buffer_length: u32, buffer: cstring, file_part: ^Wstring) -> u32 ---;
|
@(link_name="GetFullPathNameA") get_full_path_name_a :: proc(filename: cstring, buffer_length: u32, buffer: cstring, file_part: ^Wstring) -> u32 ---;
|
||||||
@@ -177,3 +177,44 @@ foreign kernel32 {
|
|||||||
@(link_name="GetCurrentDirectorya") get_current_directory_a :: proc(buffer_length: u32, buffer: cstring) -> u32 ---;
|
@(link_name="GetCurrentDirectorya") get_current_directory_a :: proc(buffer_length: u32, buffer: cstring) -> u32 ---;
|
||||||
@(link_name="GetCurrentDirectoryW") get_current_directory_w :: proc(buffer_length: u32, buffer: Wstring) -> u32 ---;
|
@(link_name="GetCurrentDirectoryW") get_current_directory_w :: proc(buffer_length: u32, buffer: Wstring) -> u32 ---;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Memory_Basic_Information :: struct {
|
||||||
|
base_address: rawptr,
|
||||||
|
allocation_base: rawptr,
|
||||||
|
allocation_protect: u32,
|
||||||
|
region_size: uint,
|
||||||
|
state: u32,
|
||||||
|
protect: u32,
|
||||||
|
type: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
@(default_calling_convention = "std")
|
||||||
|
foreign kernel32 {
|
||||||
|
@(link_name="VirtualAlloc") virtual_alloc :: proc(address: rawptr, size: uint, allocation_type: u32, protect: u32) -> rawptr ---
|
||||||
|
@(link_name="VirtualAllocEx") virtual_alloc_ex :: proc(process: Handle, address: rawptr, size: uint, allocation_type: u32, protect: u32) -> rawptr ---
|
||||||
|
@(link_name="VirtualFree") virtual_free :: proc(address: rawptr, size: uint, free_type: u32) -> Bool ---
|
||||||
|
@(link_name="VirtualLock") virtual_lock :: proc(address: rawptr, size: uint) -> Bool ---
|
||||||
|
@(link_name="VirtualProtect") virtual_protect :: proc(address: rawptr, size: uint, new_protect: u32, old_protect: ^u32) -> Bool ---
|
||||||
|
@(link_name="VirtualQuery") virtual_query :: proc(address: rawptr, buffer: ^Memory_Basic_Information, length: uint) -> uint ---
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_COMMIT :: 0x00001000;
|
||||||
|
MEM_RESERVE :: 0x00002000;
|
||||||
|
MEM_DECOMMIT :: 0x00004000;
|
||||||
|
MEM_RELEASE :: 0x00008000;
|
||||||
|
MEM_RESET :: 0x00080000;
|
||||||
|
MEM_RESET_UNDO :: 0x01000000;
|
||||||
|
|
||||||
|
MEM_LARGE_PAGES :: 0x20000000;
|
||||||
|
MEM_PHYSICAL :: 0x00400000;
|
||||||
|
MEM_TOP_DOWN :: 0x00100000;
|
||||||
|
MEM_WRITE_WATCH :: 0x00200000;
|
||||||
|
|
||||||
|
PAGE_NOACCESS :: 0x01;
|
||||||
|
PAGE_READONLY :: 0x02;
|
||||||
|
PAGE_READWRITE :: 0x04;
|
||||||
|
PAGE_WRITECOPY :: 0x08;
|
||||||
|
PAGE_EXECUTE :: 0x10;
|
||||||
|
PAGE_EXECUTE_READ :: 0x20;
|
||||||
|
PAGE_EXECUTE_READWRITE :: 0x40;
|
||||||
|
PAGE_EXECUTE_WRITECOPY :: 0x80;
|
||||||
|
|||||||
@@ -267,3 +267,8 @@ is_opaque :: proc(info: ^rt.Type_Info) -> bool {
|
|||||||
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Opaque);
|
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Opaque);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
is_simd_vector :: proc(info: ^rt.Type_Info) -> bool {
|
||||||
|
if info == nil do return false;
|
||||||
|
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Simd_Vector);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ encode_rune :: proc(r: rune) -> ([4]u8, int) {
|
|||||||
buf[0] = 0xf0 | u8(r>>18);
|
buf[0] = 0xf0 | u8(r>>18);
|
||||||
buf[1] = 0x80 | u8(r>>12) & mask;
|
buf[1] = 0x80 | u8(r>>12) & mask;
|
||||||
buf[2] = 0x80 | u8(r>>6) & mask;
|
buf[2] = 0x80 | u8(r>>6) & mask;
|
||||||
buf[3] = 0x80 | u8(r) & mask;
|
buf[3] = 0x80 | u8(r) & mask;
|
||||||
return buf, 4;
|
return buf, 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -530,7 +530,7 @@ parametric_polymorphism :: proc() {
|
|||||||
// `I` is the type of N
|
// `I` is the type of N
|
||||||
// `T` is the type passed
|
// `T` is the type passed
|
||||||
fmt.printf("Generating an array of type %v from the value %v of type %v\n",
|
fmt.printf("Generating an array of type %v from the value %v of type %v\n",
|
||||||
typeid_of(type_of(res)), N, typeid_of(I));
|
typeid_of(type_of(res)), N, typeid_of(I));
|
||||||
for i in 0..N-1 {
|
for i in 0..N-1 {
|
||||||
res[i] = T(i*i);
|
res[i] = T(i*i);
|
||||||
}
|
}
|
||||||
@@ -691,6 +691,89 @@ using_enum :: proc() {
|
|||||||
fmt.println(len(Foo));
|
fmt.println(len(Foo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
map_type :: proc() {
|
||||||
|
fmt.println("# map type");
|
||||||
|
|
||||||
|
// enums of type u16, u32, i16 & i32 also work
|
||||||
|
Enum_u8 :: enum u8 {
|
||||||
|
A = 0,
|
||||||
|
B = 1 << 8 - 1,
|
||||||
|
}
|
||||||
|
Enum_u64 :: enum u64 {
|
||||||
|
A = 0,
|
||||||
|
B = 1 << 64 - 1,
|
||||||
|
}
|
||||||
|
Enum_i8 :: enum i8 {
|
||||||
|
A = 0,
|
||||||
|
B = -(1 << 7),
|
||||||
|
}
|
||||||
|
Enum_i64 :: enum i64 {
|
||||||
|
A = 0,
|
||||||
|
B = -(1 << 63),
|
||||||
|
}
|
||||||
|
|
||||||
|
map_u8: map[Enum_u8]u8;
|
||||||
|
map_u8[Enum_u8.A] = u8(Enum_u8.B);
|
||||||
|
assert(map_u8[Enum_u8.A] == u8(Enum_u8.B));
|
||||||
|
fmt.println(map_u8);
|
||||||
|
|
||||||
|
map_u64: map[Enum_u64]u64;
|
||||||
|
map_u64[Enum_u64.A] = u64(Enum_u64.B);
|
||||||
|
assert(map_u64[Enum_u64.A] == u64(Enum_u64.B));
|
||||||
|
fmt.println(map_u64);
|
||||||
|
|
||||||
|
map_i8: map[Enum_i8]i8;
|
||||||
|
map_i8[Enum_i8.A] = i8(Enum_i8.B);
|
||||||
|
assert(map_i8[Enum_i8.A] == i8(Enum_i8.B));
|
||||||
|
fmt.println(map_i8);
|
||||||
|
|
||||||
|
map_i64: map[Enum_i64]i64;
|
||||||
|
map_i64[Enum_i64.A] = i64(Enum_i64.B);
|
||||||
|
assert(map_i64[Enum_i64.A] == i64(Enum_i64.B));
|
||||||
|
fmt.println(map_i64);
|
||||||
|
|
||||||
|
demo_struct :: struct {
|
||||||
|
member: Enum_i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
map_string: map[string]demo_struct;
|
||||||
|
map_string["Hellope!"] = demo_struct{Enum_i64.B};
|
||||||
|
assert(map_string["Hellope!"].member == Enum_i64.B);
|
||||||
|
assert("Hellope?" notin map_string);
|
||||||
|
fmt.println(map_string);
|
||||||
|
fmt.println("Hellope! in map_string:", "Hellope!" in map_string);
|
||||||
|
fmt.println("Hellope? in map_string:", "Hellope?" in map_string);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
implicit_selector_expression :: proc() {
|
||||||
|
fmt.println("# implicit selector expression");
|
||||||
|
|
||||||
|
Foo :: enum {A, B, C};
|
||||||
|
|
||||||
|
f: Foo;
|
||||||
|
f = .A;
|
||||||
|
|
||||||
|
BAR :: bit_set[Foo]{.B, .C};
|
||||||
|
|
||||||
|
switch f {
|
||||||
|
case .A:
|
||||||
|
fmt.println("HERE");
|
||||||
|
case .B:
|
||||||
|
fmt.println("NEVER");
|
||||||
|
case .C:
|
||||||
|
fmt.println("FOREVER");
|
||||||
|
}
|
||||||
|
|
||||||
|
my_map := make(map[Foo]int);
|
||||||
|
defer delete(my_map);
|
||||||
|
|
||||||
|
my_map[.A] = 123;
|
||||||
|
my_map[Foo.B] = 345;
|
||||||
|
|
||||||
|
fmt.println(my_map[.A] + my_map[Foo.B] + my_map[.C]);
|
||||||
|
}
|
||||||
|
|
||||||
explicit_procedure_overloading :: proc() {
|
explicit_procedure_overloading :: proc() {
|
||||||
fmt.println("# explicit procedure overloading");
|
fmt.println("# explicit procedure overloading");
|
||||||
|
|
||||||
@@ -773,7 +856,7 @@ cstring_example :: proc() {
|
|||||||
fmt.println(len(W), len(X), len(Y));
|
fmt.println(len(W), len(X), len(Y));
|
||||||
// IMPORTANT NOTE for cstring variables
|
// IMPORTANT NOTE for cstring variables
|
||||||
// len(cstring) is O(N)
|
// len(cstring) is O(N)
|
||||||
// cast(cstring)string is O(N)
|
// cast(string)cstring is O(N)
|
||||||
}
|
}
|
||||||
|
|
||||||
deprecated_attribute :: proc() {
|
deprecated_attribute :: proc() {
|
||||||
@@ -884,6 +967,8 @@ main :: proc() {
|
|||||||
array_programming();
|
array_programming();
|
||||||
named_proc_return_parameters();
|
named_proc_return_parameters();
|
||||||
using_enum();
|
using_enum();
|
||||||
|
map_type();
|
||||||
|
implicit_selector_expression();
|
||||||
explicit_procedure_overloading();
|
explicit_procedure_overloading();
|
||||||
complete_switch();
|
complete_switch();
|
||||||
cstring_example();
|
cstring_example();
|
||||||
|
|||||||
@@ -110,6 +110,8 @@ struct BuildContext {
|
|||||||
|
|
||||||
gbAffinity affinity;
|
gbAffinity affinity;
|
||||||
isize thread_count;
|
isize thread_count;
|
||||||
|
|
||||||
|
Map<ExactValue> defined_values; // Key:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -551,20 +551,20 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
|||||||
check_procedure_type(&tmp_ctx, proc_type, pl->type);
|
check_procedure_type(&tmp_ctx, proc_type, pl->type);
|
||||||
|
|
||||||
TypeProc *pt = &proc_type->Proc;
|
TypeProc *pt = &proc_type->Proc;
|
||||||
|
|
||||||
bool is_foreign = e->Procedure.is_foreign;
|
|
||||||
bool is_export = e->Procedure.is_export;
|
|
||||||
bool is_require_results = (pl->tags & ProcTag_require_results) != 0;
|
|
||||||
|
|
||||||
AttributeContext ac = make_attribute_context(e->Procedure.link_prefix);
|
AttributeContext ac = make_attribute_context(e->Procedure.link_prefix);
|
||||||
|
|
||||||
if (d != nullptr) {
|
if (d != nullptr) {
|
||||||
check_decl_attributes(ctx, d->attributes, proc_decl_attribute, &ac);
|
check_decl_attributes(ctx, d->attributes, proc_decl_attribute, &ac);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e->Procedure.is_export = ac.is_export;
|
||||||
e->deprecated_message = ac.deprecated_message;
|
e->deprecated_message = ac.deprecated_message;
|
||||||
ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);
|
ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);
|
||||||
|
|
||||||
|
bool is_foreign = e->Procedure.is_foreign;
|
||||||
|
bool is_export = e->Procedure.is_export;
|
||||||
|
bool is_require_results = (pl->tags & ProcTag_require_results) != 0;
|
||||||
|
|
||||||
if (e->pkg != nullptr && e->token.string == "main") {
|
if (e->pkg != nullptr && e->token.string == "main") {
|
||||||
if (pt->param_count != 0 ||
|
if (pt->param_count != 0 ||
|
||||||
pt->result_count != 0) {
|
pt->result_count != 0) {
|
||||||
@@ -718,8 +718,14 @@ void check_var_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_ex
|
|||||||
check_decl_attributes(ctx, decl->attributes, var_decl_attribute, &ac);
|
check_decl_attributes(ctx, decl->attributes, var_decl_attribute, &ac);
|
||||||
}
|
}
|
||||||
|
|
||||||
ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);
|
|
||||||
e->Variable.thread_local_model = ac.thread_local_model;
|
e->Variable.thread_local_model = ac.thread_local_model;
|
||||||
|
e->Variable.is_export = ac.is_export;
|
||||||
|
if (ac.is_static) {
|
||||||
|
e->flags |= EntityFlag_Static;
|
||||||
|
} else {
|
||||||
|
e->flags &= ~EntityFlag_Static;
|
||||||
|
}
|
||||||
|
ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);
|
||||||
|
|
||||||
String context_name = str_lit("variable declaration");
|
String context_name = str_lit("variable declaration");
|
||||||
|
|
||||||
|
|||||||
@@ -991,7 +991,6 @@ Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Typ
|
|||||||
o->expr = n;
|
o->expr = n;
|
||||||
String name = n->Ident.token.string;
|
String name = n->Ident.token.string;
|
||||||
|
|
||||||
|
|
||||||
Entity *e = scope_lookup(c->scope, name);
|
Entity *e = scope_lookup(c->scope, name);
|
||||||
if (e == nullptr) {
|
if (e == nullptr) {
|
||||||
if (is_blank_ident(name)) {
|
if (is_blank_ident(name)) {
|
||||||
@@ -1241,6 +1240,14 @@ bool check_binary_op(CheckerContext *c, Operand *o, Token op) {
|
|||||||
error(op, "Operator '%.*s' is only allowed with integers", LIT(op.string));
|
error(op, "Operator '%.*s' is only allowed with integers", LIT(op.string));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (is_type_simd_vector(o->type)) {
|
||||||
|
switch (op.kind) {
|
||||||
|
case Token_ModMod:
|
||||||
|
case Token_ModModEq:
|
||||||
|
error(op, "Operator '%.*s' is only allowed with integers", LIT(op.string));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token_AndNot:
|
case Token_AndNot:
|
||||||
@@ -1249,6 +1256,14 @@ bool check_binary_op(CheckerContext *c, Operand *o, Token op) {
|
|||||||
error(op, "Operator '%.*s' is only allowed with integers and bit sets", LIT(op.string));
|
error(op, "Operator '%.*s' is only allowed with integers and bit sets", LIT(op.string));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (is_type_simd_vector(o->type)) {
|
||||||
|
switch (op.kind) {
|
||||||
|
case Token_AndNot:
|
||||||
|
case Token_AndNotEq:
|
||||||
|
error(op, "Operator '%.*s' is only allowed with integers", LIT(op.string));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token_CmpAnd:
|
case Token_CmpAnd:
|
||||||
@@ -2129,8 +2144,20 @@ void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, bool use_lhs_as
|
|||||||
|
|
||||||
case Token_in:
|
case Token_in:
|
||||||
case Token_notin:
|
case Token_notin:
|
||||||
check_expr(c, x, be->left);
|
// IMPORTANT NOTE(bill): This uses right-left evaluation in type checking only no in
|
||||||
|
|
||||||
check_expr(c, y, be->right);
|
check_expr(c, y, be->right);
|
||||||
|
|
||||||
|
if (is_type_bit_set(y->type)) {
|
||||||
|
Type *elem = base_type(y->type)->BitSet.elem;
|
||||||
|
check_expr_with_type_hint(c, x, be->left, elem);
|
||||||
|
} else if (is_type_map(y->type)) {
|
||||||
|
Type *key = base_type(y->type)->Map.key;
|
||||||
|
check_expr_with_type_hint(c, x, be->left, key);
|
||||||
|
} else {
|
||||||
|
check_expr(c, x, be->left);
|
||||||
|
}
|
||||||
|
|
||||||
if (x->mode == Addressing_Invalid) {
|
if (x->mode == Addressing_Invalid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -4072,6 +4099,46 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case BuiltinProc_vector: {
|
||||||
|
Operand x = {};
|
||||||
|
Operand y = {};
|
||||||
|
x = *operand;
|
||||||
|
if (!is_type_integer(x.type) || x.mode != Addressing_Constant) {
|
||||||
|
error(call, "Expected a constant integer for 'intrinsics.vector'");
|
||||||
|
operand->mode = Addressing_Type;
|
||||||
|
operand->type = t_invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (x.value.value_integer.neg) {
|
||||||
|
error(call, "Negative vector element length");
|
||||||
|
operand->mode = Addressing_Type;
|
||||||
|
operand->type = t_invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
i64 count = big_int_to_i64(&x.value.value_integer);
|
||||||
|
|
||||||
|
check_expr_or_type(c, &y, ce->args[1]);
|
||||||
|
if (y.mode != Addressing_Type) {
|
||||||
|
error(call, "Expected a type 'intrinsics.vector'");
|
||||||
|
operand->mode = Addressing_Type;
|
||||||
|
operand->type = t_invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Type *elem = y.type;
|
||||||
|
if (!is_type_valid_vector_elem(elem)) {
|
||||||
|
gbString str = type_to_string(elem);
|
||||||
|
error(call, "Invalid element type for 'intrinsics.vector', expected an integer or float with no specific endianness, got '%s'", str);
|
||||||
|
gb_string_free(str);
|
||||||
|
operand->mode = Addressing_Type;
|
||||||
|
operand->type = t_invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
operand->mode = Addressing_Type;
|
||||||
|
operand->type = alloc_type_simd_vector(count, elem);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case BuiltinProc_atomic_fence:
|
case BuiltinProc_atomic_fence:
|
||||||
case BuiltinProc_atomic_fence_acq:
|
case BuiltinProc_atomic_fence_acq:
|
||||||
case BuiltinProc_atomic_fence_rel:
|
case BuiltinProc_atomic_fence_rel:
|
||||||
@@ -5372,7 +5439,8 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call) {
|
|||||||
operand->mode = Addressing_NoValue;
|
operand->mode = Addressing_NoValue;
|
||||||
} else {
|
} else {
|
||||||
GB_ASSERT(is_type_tuple(result_type));
|
GB_ASSERT(is_type_tuple(result_type));
|
||||||
switch (result_type->Tuple.variables.count) {
|
isize count = result_type->Tuple.variables.count;
|
||||||
|
switch (count) {
|
||||||
case 0:
|
case 0:
|
||||||
operand->mode = Addressing_NoValue;
|
operand->mode = Addressing_NoValue;
|
||||||
break;
|
break;
|
||||||
@@ -5778,7 +5846,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
|||||||
if (cl->elems.count == 0) {
|
if (cl->elems.count == 0) {
|
||||||
break; // NOTE(bill): No need to init
|
break; // NOTE(bill): No need to init
|
||||||
}
|
}
|
||||||
if (!is_type_struct(t)) {
|
if (t->Struct.is_raw_union) {
|
||||||
if (cl->elems.count != 0) {
|
if (cl->elems.count != 0) {
|
||||||
gbString type_str = type_to_string(type);
|
gbString type_str = type_to_string(type);
|
||||||
error(node, "Illegal compound literal type '%s'", type_str);
|
error(node, "Illegal compound literal type '%s'", type_str);
|
||||||
@@ -5902,6 +5970,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
|||||||
case Type_Slice:
|
case Type_Slice:
|
||||||
case Type_Array:
|
case Type_Array:
|
||||||
case Type_DynamicArray:
|
case Type_DynamicArray:
|
||||||
|
case Type_SimdVector:
|
||||||
{
|
{
|
||||||
Type *elem_type = nullptr;
|
Type *elem_type = nullptr;
|
||||||
String context_name = {};
|
String context_name = {};
|
||||||
@@ -5922,6 +5991,10 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
|||||||
|
|
||||||
add_package_dependency(c, "runtime", "__dynamic_array_reserve");
|
add_package_dependency(c, "runtime", "__dynamic_array_reserve");
|
||||||
add_package_dependency(c, "runtime", "__dynamic_array_append");
|
add_package_dependency(c, "runtime", "__dynamic_array_append");
|
||||||
|
} else if (t->kind == Type_SimdVector) {
|
||||||
|
elem_type = t->SimdVector.elem;
|
||||||
|
context_name = str_lit("simd vector literal");
|
||||||
|
max_type_count = t->SimdVector.count;
|
||||||
} else {
|
} else {
|
||||||
GB_PANIC("unreachable");
|
GB_PANIC("unreachable");
|
||||||
}
|
}
|
||||||
@@ -5972,6 +6045,15 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
|||||||
error(node, "Expected %lld values for this array literal, got %lld", cast(long long)t->Array.count, cast(long long)max);
|
error(node, "Expected %lld values for this array literal, got %lld", cast(long long)t->Array.count, cast(long long)max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (t->kind == Type_SimdVector) {
|
||||||
|
if (!is_constant) {
|
||||||
|
error(node, "Expected all constant elements for a simd vector");
|
||||||
|
}
|
||||||
|
if (t->SimdVector.is_x86_mmx) {
|
||||||
|
error(node, "Compound literals are not allowed with intrinsics.x86_mmx");
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6107,7 +6189,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
check_expr(c, o, elem);
|
check_expr_with_type_hint(c, o, elem, et);
|
||||||
|
|
||||||
if (is_constant) {
|
if (is_constant) {
|
||||||
is_constant = o->mode == Addressing_Constant;
|
is_constant = o->mode == Addressing_Constant;
|
||||||
@@ -6338,6 +6420,47 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
|||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
|
||||||
|
case_ast_node(ise, ImplicitSelectorExpr, node);
|
||||||
|
o->type = t_invalid;
|
||||||
|
o->expr = node;
|
||||||
|
o->mode = Addressing_Invalid;
|
||||||
|
|
||||||
|
if (type_hint == nullptr) {
|
||||||
|
gbString str = expr_to_string(node);
|
||||||
|
error(node, "Cannot determine type for implicit selector expression '%s'", str);
|
||||||
|
gb_string_free(str);
|
||||||
|
return Expr_Expr;
|
||||||
|
}
|
||||||
|
o->type = type_hint;
|
||||||
|
if (!is_type_enum(type_hint)) {
|
||||||
|
gbString typ = type_to_string(type_hint);
|
||||||
|
gbString str = expr_to_string(node);
|
||||||
|
error(node, "Invalid type '%s' for implicit selector expression '%s'", typ, str);
|
||||||
|
gb_string_free(str);
|
||||||
|
gb_string_free(typ);
|
||||||
|
return Expr_Expr;
|
||||||
|
}
|
||||||
|
GB_ASSERT(ise->selector->kind == Ast_Ident);
|
||||||
|
String name = ise->selector->Ident.token.string;
|
||||||
|
|
||||||
|
Type *enum_type = base_type(type_hint);
|
||||||
|
GB_ASSERT(enum_type->kind == Type_Enum);
|
||||||
|
Entity *e = scope_lookup_current(enum_type->Enum.scope, name);
|
||||||
|
if (e == nullptr) {
|
||||||
|
gbString typ = type_to_string(type_hint);
|
||||||
|
error(node, "Undeclared name %.*s for type '%s'", LIT(name), typ);
|
||||||
|
gb_string_free(typ);
|
||||||
|
return Expr_Expr;
|
||||||
|
}
|
||||||
|
GB_ASSERT(are_types_identical(base_type(e->type), base_type(type_hint)));
|
||||||
|
GB_ASSERT(e->kind == Entity_Constant);
|
||||||
|
o->value = e->Constant.value;
|
||||||
|
o->mode = Addressing_Constant;
|
||||||
|
o->type = e->type;
|
||||||
|
|
||||||
|
return Expr_Expr;
|
||||||
|
case_end;
|
||||||
|
|
||||||
case_ast_node(ie, IndexExpr, node);
|
case_ast_node(ie, IndexExpr, node);
|
||||||
check_expr(c, o, ie->expr);
|
check_expr(c, o, ie->expr);
|
||||||
if (o->mode == Addressing_Invalid) {
|
if (o->mode == Addressing_Invalid) {
|
||||||
@@ -6351,7 +6474,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
|||||||
|
|
||||||
if (is_type_map(t)) {
|
if (is_type_map(t)) {
|
||||||
Operand key = {};
|
Operand key = {};
|
||||||
check_expr(c, &key, ie->index);
|
check_expr_with_type_hint(c, &key, ie->index, t->Map.key);
|
||||||
check_assignment(c, &key, t->Map.key, str_lit("map index"));
|
check_assignment(c, &key, t->Map.key, str_lit("map index"));
|
||||||
if (key.mode == Addressing_Invalid) {
|
if (key.mode == Addressing_Invalid) {
|
||||||
o->mode = Addressing_Invalid;
|
o->mode = Addressing_Invalid;
|
||||||
@@ -6762,6 +6885,11 @@ gbString write_expr_to_string(gbString str, Ast *node) {
|
|||||||
str = write_expr_to_string(str, se->selector);
|
str = write_expr_to_string(str, se->selector);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(se, ImplicitSelectorExpr, node);
|
||||||
|
str = gb_string_append_rune(str, '.');
|
||||||
|
str = write_expr_to_string(str, se->selector);
|
||||||
|
case_end;
|
||||||
|
|
||||||
case_ast_node(ta, TypeAssertion, node);
|
case_ast_node(ta, TypeAssertion, node);
|
||||||
str = write_expr_to_string(str, ta->expr);
|
str = write_expr_to_string(str, ta->expr);
|
||||||
str = gb_string_appendc(str, ".(");
|
str = gb_string_appendc(str, ".(");
|
||||||
|
|||||||
@@ -686,14 +686,14 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
|||||||
ast_node(ie, BinaryExpr, expr);
|
ast_node(ie, BinaryExpr, expr);
|
||||||
Operand lhs = {};
|
Operand lhs = {};
|
||||||
Operand rhs = {};
|
Operand rhs = {};
|
||||||
check_expr(ctx, &lhs, ie->left);
|
check_expr_with_type_hint(ctx, &lhs, ie->left, x.type);
|
||||||
if (x.mode == Addressing_Invalid) {
|
if (x.mode == Addressing_Invalid) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (lhs.mode == Addressing_Invalid) {
|
if (lhs.mode == Addressing_Invalid) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
check_expr(ctx, &rhs, ie->right);
|
check_expr_with_type_hint(ctx, &rhs, ie->right, x.type);
|
||||||
if (rhs.mode == Addressing_Invalid) {
|
if (rhs.mode == Addressing_Invalid) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -732,7 +732,7 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
|||||||
if (is_type_typeid(x.type)) {
|
if (is_type_typeid(x.type)) {
|
||||||
check_expr_or_type(ctx, &y, expr, x.type);
|
check_expr_or_type(ctx, &y, expr, x.type);
|
||||||
} else {
|
} else {
|
||||||
check_expr(ctx, &y, expr);
|
check_expr_with_type_hint(ctx, &y, expr, x.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x.mode == Addressing_Invalid ||
|
if (x.mode == Addressing_Invalid ||
|
||||||
@@ -1665,8 +1665,6 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
|||||||
if (!is_blank_ident(str)) {
|
if (!is_blank_ident(str)) {
|
||||||
found = scope_lookup_current(ctx->scope, str);
|
found = scope_lookup_current(ctx->scope, str);
|
||||||
new_name_count += 1;
|
new_name_count += 1;
|
||||||
} else if (vd->is_static) {
|
|
||||||
error(name, "'static' is now allowed to be applied to '_'");
|
|
||||||
}
|
}
|
||||||
if (found == nullptr) {
|
if (found == nullptr) {
|
||||||
entity = alloc_entity_variable(ctx->scope, token, nullptr, false);
|
entity = alloc_entity_variable(ctx->scope, token, nullptr, false);
|
||||||
@@ -1678,9 +1676,6 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
|||||||
entity->Variable.is_foreign = true;
|
entity->Variable.is_foreign = true;
|
||||||
entity->Variable.foreign_library_ident = fl;
|
entity->Variable.foreign_library_ident = fl;
|
||||||
}
|
}
|
||||||
if (vd->is_static) {
|
|
||||||
entity->flags |= EntityFlag_Static;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
TokenPos pos = found->token.pos;
|
TokenPos pos = found->token.pos;
|
||||||
error(token,
|
error(token,
|
||||||
@@ -1744,6 +1739,16 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
|||||||
if (ac.link_name.len > 0) {
|
if (ac.link_name.len > 0) {
|
||||||
e->Variable.link_name = ac.link_name;
|
e->Variable.link_name = ac.link_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e->flags &= ~EntityFlag_Static;
|
||||||
|
if (ac.is_static) {
|
||||||
|
String name = e->token.string;
|
||||||
|
if (name == "_") {
|
||||||
|
error(e->token, "The 'static' attribute is not allowed to be applied to '_'");
|
||||||
|
} else {
|
||||||
|
e->flags |= EntityFlag_Static;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
check_arity_match(ctx, vd);
|
check_arity_match(ctx, vd);
|
||||||
@@ -1751,6 +1756,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
|||||||
|
|
||||||
for (isize i = 0; i < entity_count; i++) {
|
for (isize i = 0; i < entity_count; i++) {
|
||||||
Entity *e = entities[i];
|
Entity *e = entities[i];
|
||||||
|
|
||||||
if (e->Variable.is_foreign) {
|
if (e->Variable.is_foreign) {
|
||||||
if (vd->values.count > 0) {
|
if (vd->values.count > 0) {
|
||||||
error(e->token, "A foreign variable declaration cannot have a default value");
|
error(e->token, "A foreign variable declaration cannot have a default value");
|
||||||
@@ -1842,6 +1848,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// constant value declaration
|
// constant value declaration
|
||||||
// NOTE(bill): Check `_` declarations
|
// NOTE(bill): Check `_` declarations
|
||||||
|
|||||||
@@ -1783,13 +1783,21 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type) {
|
|||||||
Type *new_type = original_type;
|
Type *new_type = original_type;
|
||||||
|
|
||||||
if (is_type_boolean(original_type)) {
|
if (is_type_boolean(original_type)) {
|
||||||
return t_llvm_bool;
|
Type *t = core_type(base_type(new_type));
|
||||||
|
if (t == t_bool) {
|
||||||
|
return t_llvm_bool;
|
||||||
|
}
|
||||||
|
return new_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (build_context.ODIN_ARCH == "386") {
|
if (build_context.ODIN_ARCH == "386") {
|
||||||
return new_type;
|
return new_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_type_simd_vector(original_type)) {
|
||||||
|
return new_type;
|
||||||
|
}
|
||||||
|
|
||||||
if (build_context.ODIN_OS == "windows") {
|
if (build_context.ODIN_OS == "windows") {
|
||||||
// NOTE(bill): Changing the passing parameter value type is to match C's ABI
|
// NOTE(bill): Changing the passing parameter value type is to match C's ABI
|
||||||
// IMPORTANT TODO(bill): This only matches the ABI on MSVC at the moment
|
// IMPORTANT TODO(bill): This only matches the ABI on MSVC at the moment
|
||||||
@@ -1893,7 +1901,11 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type) {
|
|||||||
}
|
}
|
||||||
GB_ASSERT(is_type_tuple(original_type));
|
GB_ASSERT(is_type_tuple(original_type));
|
||||||
|
|
||||||
|
Type *single_type = reduce_tuple_to_single_type(original_type);
|
||||||
|
|
||||||
|
if (is_type_simd_vector(single_type)) {
|
||||||
|
return new_type;
|
||||||
|
}
|
||||||
|
|
||||||
if (build_context.ODIN_OS == "windows") {
|
if (build_context.ODIN_OS == "windows") {
|
||||||
Type *bt = core_type(reduce_tuple_to_single_type(original_type));
|
Type *bt = core_type(reduce_tuple_to_single_type(original_type));
|
||||||
@@ -1941,15 +1953,16 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type) {
|
|||||||
return new_type;
|
return new_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool abi_compat_return_by_value(gbAllocator a, ProcCallingConvention cc, Type *abi_return_type) {
|
bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type *abi_return_type) {
|
||||||
if (abi_return_type == nullptr) {
|
if (abi_return_type == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// switch (cc) {
|
|
||||||
// case ProcCC_Odin:
|
Type *single_type = reduce_tuple_to_single_type(abi_return_type);
|
||||||
// case ProcCC_Contextless:
|
|
||||||
// return false;
|
if (is_type_simd_vector(single_type)) {
|
||||||
// }
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (build_context.ODIN_OS == "windows") {
|
if (build_context.ODIN_OS == "windows") {
|
||||||
@@ -2036,6 +2049,7 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node,
|
|||||||
type->Proc.is_polymorphic = pt->generic;
|
type->Proc.is_polymorphic = pt->generic;
|
||||||
type->Proc.specialization_count = specialization_count;
|
type->Proc.specialization_count = specialization_count;
|
||||||
type->Proc.diverging = pt->diverging;
|
type->Proc.diverging = pt->diverging;
|
||||||
|
type->Proc.tags = pt->tags;
|
||||||
|
|
||||||
if (param_count > 0) {
|
if (param_count > 0) {
|
||||||
Entity *end = params->Tuple.variables[param_count-1];
|
Entity *end = params->Tuple.variables[param_count-1];
|
||||||
@@ -2075,7 +2089,7 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node,
|
|||||||
|
|
||||||
// NOTE(bill): The types are the same
|
// NOTE(bill): The types are the same
|
||||||
type->Proc.abi_compat_result_type = type_to_abi_compat_result_type(c->allocator, type->Proc.results);
|
type->Proc.abi_compat_result_type = type_to_abi_compat_result_type(c->allocator, type->Proc.results);
|
||||||
type->Proc.return_by_pointer = abi_compat_return_by_value(c->allocator, pt->calling_convention, type->Proc.abi_compat_result_type);
|
type->Proc.return_by_pointer = abi_compat_return_by_pointer(c->allocator, pt->calling_convention, type->Proc.abi_compat_result_type);
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|||||||
131
src/checker.cpp
131
src/checker.cpp
@@ -712,6 +712,53 @@ void init_universal(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(bill): Set the correct arch for this
|
||||||
|
if (bc->metrics.arch == TargetArch_amd64 || bc->metrics.arch == TargetArch_386) {
|
||||||
|
t_vector_x86_mmx = alloc_type(Type_SimdVector);
|
||||||
|
t_vector_x86_mmx->SimdVector.is_x86_mmx = true;
|
||||||
|
|
||||||
|
Entity *entity = alloc_entity(Entity_TypeName, nullptr, make_token_ident(str_lit("x86_mmx")), t_vector_x86_mmx);
|
||||||
|
add_global_entity(entity, intrinsics_pkg->scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool defined_values_double_declaration = false;
|
||||||
|
for_array(i, bc->defined_values.entries) {
|
||||||
|
String name = bc->defined_values.entries[i].key.string;
|
||||||
|
ExactValue value = bc->defined_values.entries[i].value;
|
||||||
|
GB_ASSERT(value.kind != ExactValue_Invalid);
|
||||||
|
|
||||||
|
Type *type = nullptr;
|
||||||
|
switch (value.kind) {
|
||||||
|
case ExactValue_Bool:
|
||||||
|
type = t_untyped_bool;
|
||||||
|
break;
|
||||||
|
case ExactValue_String:
|
||||||
|
type = t_untyped_string;
|
||||||
|
break;
|
||||||
|
case ExactValue_Integer:
|
||||||
|
type = t_untyped_integer;
|
||||||
|
break;
|
||||||
|
case ExactValue_Float:
|
||||||
|
type = t_untyped_float;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
GB_ASSERT(type != nullptr);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Entity *entity = alloc_entity_constant(nullptr, make_token_ident(name), type, value);
|
||||||
|
entity->state = EntityState_Resolved;
|
||||||
|
if (scope_insert(builtin_pkg->scope, entity)) {
|
||||||
|
error(entity->token, "'%.*s' defined as an argument is already declared at the global scope", LIT(name));
|
||||||
|
defined_values_double_declaration = true;
|
||||||
|
// NOTE(bill): Just exit early before anything, even though the compiler will do that anyway
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defined_values_double_declaration) {
|
||||||
|
gb_exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
t_u8_ptr = alloc_type_pointer(t_u8);
|
t_u8_ptr = alloc_type_pointer(t_u8);
|
||||||
t_int_ptr = alloc_type_pointer(t_int);
|
t_int_ptr = alloc_type_pointer(t_int);
|
||||||
@@ -1248,6 +1295,10 @@ void add_type_info_type(CheckerContext *c, Type *t) {
|
|||||||
add_type_info_type(c, bt->Proc.results);
|
add_type_info_type(c, bt->Proc.results);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Type_SimdVector:
|
||||||
|
add_type_info_type(c, bt->SimdVector.elem);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
GB_PANIC("Unhandled type: %*.s %d", LIT(type_strings[bt->kind]), bt->kind);
|
GB_PANIC("Unhandled type: %*.s %d", LIT(type_strings[bt->kind]), bt->kind);
|
||||||
break;
|
break;
|
||||||
@@ -1419,6 +1470,10 @@ void add_min_dep_type_info(Checker *c, Type *t) {
|
|||||||
add_min_dep_type_info(c, bt->Proc.results);
|
add_min_dep_type_info(c, bt->Proc.results);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Type_SimdVector:
|
||||||
|
add_min_dep_type_info(c, bt->SimdVector.elem);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
GB_PANIC("Unhandled type: %*.s", LIT(type_strings[bt->kind]));
|
GB_PANIC("Unhandled type: %*.s", LIT(type_strings[bt->kind]));
|
||||||
break;
|
break;
|
||||||
@@ -1795,6 +1850,7 @@ void init_core_type_info(Checker *c) {
|
|||||||
t_type_info_bit_field = find_core_type(c, str_lit("Type_Info_Bit_Field"));
|
t_type_info_bit_field = find_core_type(c, str_lit("Type_Info_Bit_Field"));
|
||||||
t_type_info_bit_set = find_core_type(c, str_lit("Type_Info_Bit_Set"));
|
t_type_info_bit_set = find_core_type(c, str_lit("Type_Info_Bit_Set"));
|
||||||
t_type_info_opaque = find_core_type(c, str_lit("Type_Info_Opaque"));
|
t_type_info_opaque = find_core_type(c, str_lit("Type_Info_Opaque"));
|
||||||
|
t_type_info_simd_vector = find_core_type(c, str_lit("Type_Info_Simd_Vector"));
|
||||||
|
|
||||||
t_type_info_named_ptr = alloc_type_pointer(t_type_info_named);
|
t_type_info_named_ptr = alloc_type_pointer(t_type_info_named);
|
||||||
t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer);
|
t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer);
|
||||||
@@ -1818,6 +1874,7 @@ void init_core_type_info(Checker *c) {
|
|||||||
t_type_info_bit_field_ptr = alloc_type_pointer(t_type_info_bit_field);
|
t_type_info_bit_field_ptr = alloc_type_pointer(t_type_info_bit_field);
|
||||||
t_type_info_bit_set_ptr = alloc_type_pointer(t_type_info_bit_set);
|
t_type_info_bit_set_ptr = alloc_type_pointer(t_type_info_bit_set);
|
||||||
t_type_info_opaque_ptr = alloc_type_pointer(t_type_info_opaque);
|
t_type_info_opaque_ptr = alloc_type_pointer(t_type_info_opaque);
|
||||||
|
t_type_info_simd_vector_ptr = alloc_type_pointer(t_type_info_simd_vector);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_mem_allocator(Checker *c) {
|
void init_mem_allocator(Checker *c) {
|
||||||
@@ -1933,7 +1990,18 @@ DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
|
DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
|
||||||
if (name == "deferred") {
|
if (name == "export") {
|
||||||
|
ExactValue ev = check_decl_attribute_value(c, value);
|
||||||
|
if (ev.kind == ExactValue_Invalid) {
|
||||||
|
ac->is_export = true;
|
||||||
|
} else if (ev.kind == ExactValue_Bool) {
|
||||||
|
ac->is_export = ev.value_bool;
|
||||||
|
} else {
|
||||||
|
error(value, "Expected either a boolean or no parameter for 'export'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else if (name == "deferred") {
|
||||||
if (value != nullptr) {
|
if (value != nullptr) {
|
||||||
Operand o = {};
|
Operand o = {};
|
||||||
check_expr(c, &o, value);
|
check_expr(c, &o, value);
|
||||||
@@ -2040,12 +2108,33 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
|
|||||||
DECL_ATTRIBUTE_PROC(var_decl_attribute) {
|
DECL_ATTRIBUTE_PROC(var_decl_attribute) {
|
||||||
ExactValue ev = check_decl_attribute_value(c, value);
|
ExactValue ev = check_decl_attribute_value(c, value);
|
||||||
|
|
||||||
|
if (name == "static") {
|
||||||
|
if (value != nullptr) {
|
||||||
|
error(elem, "'static' does not have any parameters");
|
||||||
|
}
|
||||||
|
ac->is_static = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (c->curr_proc_decl != nullptr) {
|
if (c->curr_proc_decl != nullptr) {
|
||||||
error(elem, "Only a variable at file scope can have a '%.*s'", LIT(name));
|
error(elem, "Only a variable at file scope can have a '%.*s'", LIT(name));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name == "link_name") {
|
if (name == "export") {
|
||||||
|
ExactValue ev = check_decl_attribute_value(c, value);
|
||||||
|
if (ev.kind == ExactValue_Invalid) {
|
||||||
|
ac->is_export = true;
|
||||||
|
} else if (ev.kind == ExactValue_Bool) {
|
||||||
|
ac->is_export = ev.value_bool;
|
||||||
|
} else {
|
||||||
|
error(value, "Expected either a boolean or no parameter for 'export'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ac->thread_local_model != "") {
|
||||||
|
error(elem, "An exported variable cannot be thread local");
|
||||||
|
}
|
||||||
|
} else if (name == "link_name") {
|
||||||
if (ev.kind == ExactValue_String) {
|
if (ev.kind == ExactValue_String) {
|
||||||
ac->link_name = ev.value_string;
|
ac->link_name = ev.value_string;
|
||||||
if (!is_foreign_name_valid(ac->link_name)) {
|
if (!is_foreign_name_valid(ac->link_name)) {
|
||||||
@@ -2068,8 +2157,10 @@ DECL_ATTRIBUTE_PROC(var_decl_attribute) {
|
|||||||
} else if (name == "thread_local") {
|
} else if (name == "thread_local") {
|
||||||
if (ac->init_expr_list_count > 0) {
|
if (ac->init_expr_list_count > 0) {
|
||||||
error(elem, "A thread local variable declaration cannot have initialization values");
|
error(elem, "A thread local variable declaration cannot have initialization values");
|
||||||
} else if (c->foreign_context.curr_library || c->foreign_context.in_export) {
|
} else if (c->foreign_context.curr_library) {
|
||||||
error(elem, "A foreign block variable cannot be thread local");
|
error(elem, "A foreign block variable cannot be thread local");
|
||||||
|
} else if (ac->is_export) {
|
||||||
|
error(elem, "An exported variable cannot be thread local");
|
||||||
} else if (ev.kind == ExactValue_Invalid) {
|
} else if (ev.kind == ExactValue_Invalid) {
|
||||||
ac->thread_local_model = str_lit("default");
|
ac->thread_local_model = str_lit("default");
|
||||||
} else if (ev.kind == ExactValue_String) {
|
} else if (ev.kind == ExactValue_String) {
|
||||||
@@ -2132,9 +2223,17 @@ void check_decl_attributes(CheckerContext *c, Array<Ast *> const &attributes, De
|
|||||||
case_ast_node(i, Ident, elem);
|
case_ast_node(i, Ident, elem);
|
||||||
name = i->token.string;
|
name = i->token.string;
|
||||||
case_end;
|
case_end;
|
||||||
|
case_ast_node(i, Implicit, elem);
|
||||||
|
name = i->string;
|
||||||
|
case_end;
|
||||||
case_ast_node(fv, FieldValue, elem);
|
case_ast_node(fv, FieldValue, elem);
|
||||||
GB_ASSERT(fv->field->kind == Ast_Ident);
|
if (fv->field->kind == Ast_Ident) {
|
||||||
name = fv->field->Ident.token.string;
|
name = fv->field->Ident.token.string;
|
||||||
|
} else if (fv->field->kind == Ast_Implicit) {
|
||||||
|
name = fv->field->Implicit.string;
|
||||||
|
} else {
|
||||||
|
GB_PANIC("Unknown Field Value name");
|
||||||
|
}
|
||||||
value = fv->value;
|
value = fv->value;
|
||||||
case_end;
|
case_end;
|
||||||
default:
|
default:
|
||||||
@@ -2372,10 +2471,6 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
|||||||
e->flags |= EntityFlag_NotExported;
|
e->flags |= EntityFlag_NotExported;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vd->is_static) {
|
|
||||||
e->flags |= EntityFlag_Static;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vd->is_using) {
|
if (vd->is_using) {
|
||||||
vd->is_using = false; // NOTE(bill): This error will be only caught once
|
vd->is_using = false; // NOTE(bill): This error will be only caught once
|
||||||
error(name, "'using' is not allowed at the file scope");
|
error(name, "'using' is not allowed at the file scope");
|
||||||
@@ -2388,9 +2483,6 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
|||||||
e->Variable.foreign_library_ident = fl;
|
e->Variable.foreign_library_ident = fl;
|
||||||
|
|
||||||
e->Variable.link_prefix = c->foreign_context.link_prefix;
|
e->Variable.link_prefix = c->foreign_context.link_prefix;
|
||||||
|
|
||||||
} else if (c->foreign_context.in_export) {
|
|
||||||
e->Variable.is_export = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ast *init_expr = value;
|
Ast *init_expr = value;
|
||||||
@@ -2456,9 +2548,6 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
|||||||
|
|
||||||
GB_ASSERT(cc != ProcCC_Invalid);
|
GB_ASSERT(cc != ProcCC_Invalid);
|
||||||
pl->type->ProcType.calling_convention = cc;
|
pl->type->ProcType.calling_convention = cc;
|
||||||
|
|
||||||
} else if (c->foreign_context.in_export) {
|
|
||||||
e->Procedure.is_export = true;
|
|
||||||
}
|
}
|
||||||
d->proc_lit = init;
|
d->proc_lit = init;
|
||||||
d->type_expr = pl->type;
|
d->type_expr = pl->type;
|
||||||
@@ -2480,14 +2569,6 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
|||||||
e->flags |= EntityFlag_NotExported;
|
e->flags |= EntityFlag_NotExported;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vd->is_static) {
|
|
||||||
if (e->kind == Entity_Constant) {
|
|
||||||
e->flags |= EntityFlag_Static;
|
|
||||||
} else {
|
|
||||||
error(name, "'static' is not allowed on this constant value declaration");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vd->is_using) {
|
if (vd->is_using) {
|
||||||
if (e->kind == Entity_TypeName && init->kind == Ast_EnumType) {
|
if (e->kind == Entity_TypeName && init->kind == Ast_EnumType) {
|
||||||
d->is_using = true;
|
d->is_using = true;
|
||||||
@@ -2497,7 +2578,7 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (e->kind != Entity_Procedure) {
|
if (e->kind != Entity_Procedure) {
|
||||||
if (fl != nullptr || c->foreign_context.in_export) {
|
if (fl != nullptr) {
|
||||||
AstKind kind = init->kind;
|
AstKind kind = init->kind;
|
||||||
error(name, "Only procedures and variables are allowed to be in a foreign block, got %.*s", LIT(ast_strings[kind]));
|
error(name, "Only procedures and variables are allowed to be in a foreign block, got %.*s", LIT(ast_strings[kind]));
|
||||||
if (kind == Ast_ProcType) {
|
if (kind == Ast_ProcType) {
|
||||||
@@ -2525,8 +2606,6 @@ void check_add_foreign_block_decl(CheckerContext *ctx, Ast *decl) {
|
|||||||
CheckerContext c = *ctx;
|
CheckerContext c = *ctx;
|
||||||
if (foreign_library->kind == Ast_Ident) {
|
if (foreign_library->kind == Ast_Ident) {
|
||||||
c.foreign_context.curr_library = foreign_library;
|
c.foreign_context.curr_library = foreign_library;
|
||||||
} else if (foreign_library->kind == Ast_Implicit && foreign_library->Implicit.kind == Token_export) {
|
|
||||||
c.foreign_context.in_export = true;
|
|
||||||
} else {
|
} else {
|
||||||
error(foreign_library, "Foreign block name must be an identifier or 'export'");
|
error(foreign_library, "Foreign block name must be an identifier or 'export'");
|
||||||
c.foreign_context.curr_library = nullptr;
|
c.foreign_context.curr_library = nullptr;
|
||||||
|
|||||||
@@ -89,6 +89,8 @@ enum BuiltinProcId {
|
|||||||
BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures
|
BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures
|
||||||
|
|
||||||
// "Intrinsics"
|
// "Intrinsics"
|
||||||
|
BuiltinProc_vector,
|
||||||
|
|
||||||
BuiltinProc_atomic_fence,
|
BuiltinProc_atomic_fence,
|
||||||
BuiltinProc_atomic_fence_acq,
|
BuiltinProc_atomic_fence_acq,
|
||||||
BuiltinProc_atomic_fence_rel,
|
BuiltinProc_atomic_fence_rel,
|
||||||
@@ -194,6 +196,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
|||||||
|
|
||||||
|
|
||||||
// "Intrinsics"
|
// "Intrinsics"
|
||||||
|
{STR_LIT("vector"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, // Type
|
||||||
|
|
||||||
|
|
||||||
{STR_LIT("atomic_fence"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
{STR_LIT("atomic_fence"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||||
{STR_LIT("atomic_fence_acq"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
{STR_LIT("atomic_fence_acq"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||||
{STR_LIT("atomic_fence_rel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
{STR_LIT("atomic_fence_rel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||||
@@ -300,6 +305,8 @@ struct DeferredProcedure {
|
|||||||
|
|
||||||
|
|
||||||
struct AttributeContext {
|
struct AttributeContext {
|
||||||
|
bool is_export;
|
||||||
|
bool is_static;
|
||||||
String link_name;
|
String link_name;
|
||||||
String link_prefix;
|
String link_prefix;
|
||||||
isize init_expr_list_count;
|
isize init_expr_list_count;
|
||||||
@@ -418,7 +425,6 @@ struct ForeignContext {
|
|||||||
Ast * curr_library;
|
Ast * curr_library;
|
||||||
ProcCallingConvention default_cc;
|
ProcCallingConvention default_cc;
|
||||||
String link_prefix;
|
String link_prefix;
|
||||||
bool in_export;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Array<Entity *> CheckerTypePath;
|
typedef Array<Entity *> CheckerTypePath;
|
||||||
|
|||||||
45
src/ir.cpp
45
src/ir.cpp
@@ -3035,6 +3035,7 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> args, Pro
|
|||||||
break;
|
break;
|
||||||
case DeferredProcedure_in:
|
case DeferredProcedure_in:
|
||||||
result_as_args = in_args;
|
result_as_args = in_args;
|
||||||
|
break;
|
||||||
case DeferredProcedure_out:
|
case DeferredProcedure_out:
|
||||||
result_as_args = ir_value_to_array(p, result);
|
result_as_args = ir_value_to_array(p, result);
|
||||||
break;
|
break;
|
||||||
@@ -3214,6 +3215,8 @@ irValue *ir_gen_map_key(irProcedure *proc, irValue *key, Type *key_type) {
|
|||||||
key = ir_emit_conv(proc, key, key_type);
|
key = ir_emit_conv(proc, key, key_type);
|
||||||
if (is_type_integer(t)) {
|
if (is_type_integer(t)) {
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, key, hash_type));
|
ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, key, hash_type));
|
||||||
|
} else if (is_type_enum(t)) {
|
||||||
|
ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, key, hash_type));
|
||||||
} else if (is_type_typeid(t)) {
|
} else if (is_type_typeid(t)) {
|
||||||
irValue *i = ir_emit_bitcast(proc, key, t_uint);
|
irValue *i = ir_emit_bitcast(proc, key, t_uint);
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, i, hash_type));
|
ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, i, hash_type));
|
||||||
@@ -4644,6 +4647,7 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// bool <-> llvm bool
|
// bool <-> llvm bool
|
||||||
if (is_type_boolean(src) && dst == t_llvm_bool) {
|
if (is_type_boolean(src) && dst == t_llvm_bool) {
|
||||||
return ir_emit(proc, ir_instr_conv(proc, irConv_trunc, value, src_type, t));
|
return ir_emit(proc, ir_instr_conv(proc, irConv_trunc, value, src_type, t));
|
||||||
@@ -4906,7 +4910,13 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
|
|||||||
return ir_emit_load(proc, result);
|
return ir_emit_load(proc, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_type_untyped(src)) {
|
||||||
|
if (is_type_string(src) && is_type_string(dst)) {
|
||||||
|
irValue *result = ir_add_local_generated(proc, t, false);
|
||||||
|
ir_emit_store(proc, result, value);
|
||||||
|
return ir_emit_load(proc, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gb_printf_err("ir_emit_conv: src -> dst\n");
|
gb_printf_err("ir_emit_conv: src -> dst\n");
|
||||||
gb_printf_err("Not Identical %s != %s\n", type_to_string(src_type), type_to_string(t));
|
gb_printf_err("Not Identical %s != %s\n", type_to_string(src_type), type_to_string(t));
|
||||||
@@ -6258,6 +6268,13 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
|
|||||||
return ir_addr_load(proc, ir_build_addr(proc, expr));
|
return ir_addr_load(proc, ir_build_addr(proc, expr));
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(ise, ImplicitSelectorExpr, expr);
|
||||||
|
TypeAndValue tav = type_and_value_of_expr(expr);
|
||||||
|
GB_ASSERT(tav.mode == Addressing_Constant);
|
||||||
|
|
||||||
|
return ir_add_module_constant(proc->module, tv.type, tv.value);
|
||||||
|
case_end;
|
||||||
|
|
||||||
case_ast_node(te, TernaryExpr, expr);
|
case_ast_node(te, TernaryExpr, expr);
|
||||||
ir_emit_comment(proc, str_lit("TernaryExpr"));
|
ir_emit_comment(proc, str_lit("TernaryExpr"));
|
||||||
|
|
||||||
@@ -7260,6 +7277,7 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
|
|||||||
case Type_Array: et = bt->Array.elem; break;
|
case Type_Array: et = bt->Array.elem; break;
|
||||||
case Type_Slice: et = bt->Slice.elem; break;
|
case Type_Slice: et = bt->Slice.elem; break;
|
||||||
case Type_BitSet: et = bt->BitSet.elem; break;
|
case Type_BitSet: et = bt->BitSet.elem; break;
|
||||||
|
case Type_SimdVector: et = bt->SimdVector.elem; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
String proc_name = {};
|
String proc_name = {};
|
||||||
@@ -7351,7 +7369,7 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
|
|||||||
|
|
||||||
case Type_Array: {
|
case Type_Array: {
|
||||||
if (cl->elems.count > 0) {
|
if (cl->elems.count > 0) {
|
||||||
// ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr)));
|
ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr)));
|
||||||
|
|
||||||
auto temp_data = array_make<irCompoundLitElemTempData>(heap_allocator(), 0, cl->elems.count);
|
auto temp_data = array_make<irCompoundLitElemTempData>(heap_allocator(), 0, cl->elems.count);
|
||||||
defer (array_free(&temp_data));
|
defer (array_free(&temp_data));
|
||||||
@@ -8157,7 +8175,16 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) {
|
|||||||
if (vd->is_mutable) {
|
if (vd->is_mutable) {
|
||||||
irModule *m = proc->module;
|
irModule *m = proc->module;
|
||||||
|
|
||||||
if (vd->is_static) {
|
bool is_static = false;
|
||||||
|
if (vd->names.count > 0) {
|
||||||
|
Entity *e = entity_of_ident(vd->names[0]);
|
||||||
|
if (e->flags & EntityFlag_Static) {
|
||||||
|
// NOTE(bill): If one of the entities is static, they all are
|
||||||
|
is_static = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_static) {
|
||||||
for_array(i, vd->names) {
|
for_array(i, vd->names) {
|
||||||
irValue *value = nullptr;
|
irValue *value = nullptr;
|
||||||
if (vd->values.count > 0) {
|
if (vd->values.count > 0) {
|
||||||
@@ -9987,6 +10014,18 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
|
|||||||
tag = ir_emit_conv(proc, variant_ptr, t_type_info_opaque_ptr);
|
tag = ir_emit_conv(proc, variant_ptr, t_type_info_opaque_ptr);
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), ir_get_type_info_ptr(proc, t->Opaque.elem));
|
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), ir_get_type_info_ptr(proc, t->Opaque.elem));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Type_SimdVector:
|
||||||
|
ir_emit_comment(proc, str_lit("Type_SimdVector"));
|
||||||
|
tag = ir_emit_conv(proc, variant_ptr, t_type_info_simd_vector_ptr);
|
||||||
|
if (t->SimdVector.is_x86_mmx) {
|
||||||
|
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), v_true);
|
||||||
|
} else {
|
||||||
|
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), ir_get_type_info_ptr(proc, t->SimdVector.elem));
|
||||||
|
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 1), ir_const_int(type_size_of(t->SimdVector.elem)));
|
||||||
|
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), ir_const_int(t->SimdVector.count));
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -316,8 +316,11 @@ void ir_print_proc_type_without_pointer(irFileBuffer *f, irModule *m, Type *t) {
|
|||||||
if (t->Proc.return_by_pointer) {
|
if (t->Proc.return_by_pointer) {
|
||||||
ir_print_type(f, m, reduce_tuple_to_single_type(t->Proc.results));
|
ir_print_type(f, m, reduce_tuple_to_single_type(t->Proc.results));
|
||||||
// ir_fprintf(f, "* sret noalias ");
|
// ir_fprintf(f, "* sret noalias ");
|
||||||
ir_write_string(f, str_lit("* noalias "));
|
// ir_write_string(f, str_lit("* noalias "));
|
||||||
if (param_count > 0) ir_write_string(f, str_lit(", "));
|
ir_write_string(f, str_lit("*"));
|
||||||
|
if (param_count > 0 || t->Proc.calling_convention == ProcCC_Odin) {
|
||||||
|
ir_write_string(f, str_lit(", "));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
isize param_index = 0;
|
isize param_index = 0;
|
||||||
for (isize i = 0; i < param_count; i++) {
|
for (isize i = 0; i < param_count; i++) {
|
||||||
@@ -574,6 +577,16 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) {
|
|||||||
case Type_Opaque:
|
case Type_Opaque:
|
||||||
ir_print_type(f, m, strip_opaque_type(t));
|
ir_print_type(f, m, strip_opaque_type(t));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case Type_SimdVector:
|
||||||
|
if (t->SimdVector.is_x86_mmx) {
|
||||||
|
ir_write_str_lit(f, "x86_mmx");
|
||||||
|
} else {
|
||||||
|
ir_fprintf(f, "<%lld x ", t->SimdVector.count);;
|
||||||
|
ir_print_type(f, m, t->SimdVector.elem);
|
||||||
|
ir_write_byte(f, '>');
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -802,6 +815,31 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
|||||||
}
|
}
|
||||||
|
|
||||||
ir_write_byte(f, ']');
|
ir_write_byte(f, ']');
|
||||||
|
} else if (is_type_simd_vector(type)) {
|
||||||
|
ast_node(cl, CompoundLit, value.value_compound);
|
||||||
|
|
||||||
|
Type *elem_type = type->SimdVector.elem;
|
||||||
|
isize elem_count = cl->elems.count;
|
||||||
|
if (elem_count == 0) {
|
||||||
|
ir_write_str_lit(f, "zeroinitializer");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
GB_ASSERT_MSG(elem_count == type->SimdVector.count, "%td != %td", elem_count, type->SimdVector.count);
|
||||||
|
|
||||||
|
ir_write_byte(f, '<');
|
||||||
|
|
||||||
|
for (isize i = 0; i < elem_count; i++) {
|
||||||
|
if (i > 0) ir_write_str_lit(f, ", ");
|
||||||
|
TypeAndValue tav = cl->elems[i]->tav;
|
||||||
|
GB_ASSERT(tav.mode != Addressing_Invalid);
|
||||||
|
ir_print_compound_element(f, m, tav.value, elem_type);
|
||||||
|
}
|
||||||
|
for (isize i = elem_count; i < type->SimdVector.count; i++) {
|
||||||
|
if (i >= elem_count) ir_write_str_lit(f, ", ");
|
||||||
|
ir_print_compound_element(f, m, empty_exact_value, elem_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
ir_write_byte(f, '>');
|
||||||
} else if (is_type_struct(type)) {
|
} else if (is_type_struct(type)) {
|
||||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena);
|
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena);
|
||||||
defer (gb_temp_arena_memory_end(tmp));
|
defer (gb_temp_arena_memory_end(tmp));
|
||||||
@@ -1052,6 +1090,7 @@ void ir_print_calling_convention(irFileBuffer *f, irModule *m, ProcCallingConven
|
|||||||
case ProcCC_CDecl: ir_write_str_lit(f, "ccc "); break;
|
case ProcCC_CDecl: ir_write_str_lit(f, "ccc "); break;
|
||||||
case ProcCC_StdCall: ir_write_str_lit(f, "cc 64 "); break;
|
case ProcCC_StdCall: ir_write_str_lit(f, "cc 64 "); break;
|
||||||
case ProcCC_FastCall: ir_write_str_lit(f, "cc 65 "); break;
|
case ProcCC_FastCall: ir_write_str_lit(f, "cc 65 "); break;
|
||||||
|
case ProcCC_None: ir_write_str_lit(f, ""); break;
|
||||||
default: GB_PANIC("unknown calling convention: %d", cc);
|
default: GB_PANIC("unknown calling convention: %d", cc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1664,7 +1703,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
case irInstr_BinaryOp: {
|
case irInstr_BinaryOp: {
|
||||||
irInstrBinaryOp *bo = &value->Instr.BinaryOp;
|
irInstrBinaryOp *bo = &value->Instr.BinaryOp;
|
||||||
Type *type = base_type(ir_type(bo->left));
|
Type *type = base_type(ir_type(bo->left));
|
||||||
Type *elem_type = type;
|
Type *elem_type = base_array_type(type);
|
||||||
|
|
||||||
ir_fprintf(f, "%%%d = ", value->index);
|
ir_fprintf(f, "%%%d = ", value->index);
|
||||||
|
|
||||||
|
|||||||
125
src/main.cpp
125
src/main.cpp
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
#include "common.cpp"
|
#include "common.cpp"
|
||||||
#include "timings.cpp"
|
#include "timings.cpp"
|
||||||
#include "build_settings.cpp"
|
|
||||||
#include "tokenizer.cpp"
|
#include "tokenizer.cpp"
|
||||||
#include "big_int.cpp"
|
#include "big_int.cpp"
|
||||||
#include "exact_value.cpp"
|
#include "exact_value.cpp"
|
||||||
|
#include "build_settings.cpp"
|
||||||
|
|
||||||
#include "parser.hpp"
|
#include "parser.hpp"
|
||||||
#include "checker.hpp"
|
#include "checker.hpp"
|
||||||
@@ -207,6 +207,7 @@ enum BuildFlagKind {
|
|||||||
BuildFlag_ThreadCount,
|
BuildFlag_ThreadCount,
|
||||||
BuildFlag_KeepTempFiles,
|
BuildFlag_KeepTempFiles,
|
||||||
BuildFlag_Collection,
|
BuildFlag_Collection,
|
||||||
|
BuildFlag_Define,
|
||||||
BuildFlag_BuildMode,
|
BuildFlag_BuildMode,
|
||||||
BuildFlag_Debug,
|
BuildFlag_Debug,
|
||||||
BuildFlag_CrossCompile,
|
BuildFlag_CrossCompile,
|
||||||
@@ -242,6 +243,41 @@ void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, Bu
|
|||||||
array_add(build_flags, flag);
|
array_add(build_flags, flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExactValue build_param_to_exact_value(String name, String param) {
|
||||||
|
ExactValue value = {};
|
||||||
|
if (str_eq_ignore_case(param, str_lit("t")) ||
|
||||||
|
str_eq_ignore_case(param, str_lit("true"))) {
|
||||||
|
value = exact_value_bool(true);
|
||||||
|
} else if (str_eq_ignore_case(param, str_lit("f")) ||
|
||||||
|
str_eq_ignore_case(param, str_lit("false"))) {
|
||||||
|
value = exact_value_bool(false);
|
||||||
|
} else if (param.len > 0) {
|
||||||
|
if (param[0] == '"') {
|
||||||
|
value = exact_value_string(param);
|
||||||
|
if (value.kind == ExactValue_String) {
|
||||||
|
String s = value.value_string;
|
||||||
|
if (s.len > 1 && s[0] == '"' && s[s.len-1] == '"') {
|
||||||
|
value.value_string = substring(s, 1, s.len-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (param[0] == '-' || param[0] == '+' || gb_is_between(param[0], '0', '9')) {
|
||||||
|
if (string_contains_char(param, '.')) {
|
||||||
|
value = exact_value_float_from_string(param);
|
||||||
|
} else {
|
||||||
|
value = exact_value_integer_from_string(param);
|
||||||
|
}
|
||||||
|
if (value.kind == ExactValue_Invalid) {
|
||||||
|
gb_printf_err("Invalid flag parameter for '%.*s' = '%.*s'\n", LIT(name), LIT(param));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
gb_printf_err("Invalid flag parameter for '%.*s' = '%.*s'\n", LIT(name), LIT(param));
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool parse_build_flags(Array<String> args) {
|
bool parse_build_flags(Array<String> args) {
|
||||||
auto build_flags = array_make<BuildFlag>(heap_allocator(), 0, BuildFlag_COUNT);
|
auto build_flags = array_make<BuildFlag>(heap_allocator(), 0, BuildFlag_COUNT);
|
||||||
add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String);
|
add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String);
|
||||||
@@ -251,6 +287,7 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
add_flag(&build_flags, BuildFlag_ThreadCount, str_lit("thread-count"), BuildFlagParam_Integer);
|
add_flag(&build_flags, BuildFlag_ThreadCount, str_lit("thread-count"), BuildFlagParam_Integer);
|
||||||
add_flag(&build_flags, BuildFlag_KeepTempFiles, str_lit("keep-temp-files"), BuildFlagParam_None);
|
add_flag(&build_flags, BuildFlag_KeepTempFiles, str_lit("keep-temp-files"), BuildFlagParam_None);
|
||||||
add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String);
|
add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String);
|
||||||
|
add_flag(&build_flags, BuildFlag_Define, str_lit("define"), BuildFlagParam_String);
|
||||||
add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), BuildFlagParam_String);
|
add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), BuildFlagParam_String);
|
||||||
add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None);
|
add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None);
|
||||||
add_flag(&build_flags, BuildFlag_CrossCompile, str_lit("cross-compile"), BuildFlagParam_String);
|
add_flag(&build_flags, BuildFlag_CrossCompile, str_lit("cross-compile"), BuildFlagParam_String);
|
||||||
@@ -276,7 +313,8 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
String name = substring(flag, 1, flag.len);
|
String name = substring(flag, 1, flag.len);
|
||||||
isize end = 0;
|
isize end = 0;
|
||||||
for (; end < name.len; end++) {
|
for (; end < name.len; end++) {
|
||||||
if (name[end] == '=') break;
|
if (name[end] == ':') break;
|
||||||
|
if (name[end] == '=') break; // IMPORTANT TODO(bill): DEPRECATE THIS!!!!
|
||||||
}
|
}
|
||||||
name = substring(name, 0, end);
|
name = substring(name, 0, end);
|
||||||
String param = {};
|
String param = {};
|
||||||
@@ -306,7 +344,9 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
} else {
|
} else {
|
||||||
ok = true;
|
ok = true;
|
||||||
switch (bf.param_kind) {
|
switch (bf.param_kind) {
|
||||||
default: ok = false; break;
|
default:
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
case BuildFlagParam_Boolean: {
|
case BuildFlagParam_Boolean: {
|
||||||
if (str_eq_ignore_case(param, str_lit("t")) ||
|
if (str_eq_ignore_case(param, str_lit("t")) ||
|
||||||
str_eq_ignore_case(param, str_lit("true")) ||
|
str_eq_ignore_case(param, str_lit("true")) ||
|
||||||
@@ -529,6 +569,62 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
case BuildFlag_Define: {
|
||||||
|
GB_ASSERT(value.kind == ExactValue_String);
|
||||||
|
String str = value.value_string;
|
||||||
|
isize eq_pos = -1;
|
||||||
|
for (isize i = 0; i < str.len; i++) {
|
||||||
|
if (str[i] == '=') {
|
||||||
|
eq_pos = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (eq_pos < 0) {
|
||||||
|
gb_printf_err("Expected 'name=value', got '%.*s'\n", LIT(param));
|
||||||
|
bad_flags = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
String name = substring(str, 0, eq_pos);
|
||||||
|
String value = substring(str, eq_pos+1, str.len);
|
||||||
|
if (name.len == 0 || value.len == 0) {
|
||||||
|
gb_printf_err("Expected 'name=value', got '%.*s'\n", LIT(param));
|
||||||
|
bad_flags = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string_is_valid_identifier(name)) {
|
||||||
|
gb_printf_err("Defined constant name '%.*s' must be a valid identifier\n", LIT(name));
|
||||||
|
bad_flags = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name == "_") {
|
||||||
|
gb_printf_err("Defined constant name cannot be an underscore\n");
|
||||||
|
bad_flags = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashKey key = hash_string(name);
|
||||||
|
|
||||||
|
if (map_get(&build_context.defined_values, key) != nullptr) {
|
||||||
|
gb_printf_err("Defined constant '%.*s' already exists\n", LIT(name));
|
||||||
|
bad_flags = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExactValue v = build_param_to_exact_value(name, value);
|
||||||
|
if (v.kind != ExactValue_Invalid) {
|
||||||
|
map_set(&build_context.defined_values, key, v);
|
||||||
|
} else {
|
||||||
|
bad_flags = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
case BuildFlag_BuildMode: {
|
case BuildFlag_BuildMode: {
|
||||||
GB_ASSERT(value.kind == ExactValue_String);
|
GB_ASSERT(value.kind == ExactValue_String);
|
||||||
String str = value.value_string;
|
String str = value.value_string;
|
||||||
@@ -599,8 +695,13 @@ void show_timings(Checker *c, Timings *t) {
|
|||||||
isize tokens = p->total_token_count;
|
isize tokens = p->total_token_count;
|
||||||
isize files = 0;
|
isize files = 0;
|
||||||
isize packages = p->packages.count;
|
isize packages = p->packages.count;
|
||||||
|
isize total_file_size = 0;
|
||||||
for_array(i, p->packages) {
|
for_array(i, p->packages) {
|
||||||
files += p->packages[i]->files.count;
|
files += p->packages[i]->files.count;
|
||||||
|
for_array(j, p->packages[i]->files) {
|
||||||
|
AstFile *file = p->packages[i]->files[j];
|
||||||
|
total_file_size += file->tokenizer.end - file->tokenizer.start;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#if 1
|
#if 1
|
||||||
timings_print_all(t);
|
timings_print_all(t);
|
||||||
@@ -608,10 +709,11 @@ void show_timings(Checker *c, Timings *t) {
|
|||||||
{
|
{
|
||||||
timings_print_all(t);
|
timings_print_all(t);
|
||||||
gb_printf("\n");
|
gb_printf("\n");
|
||||||
gb_printf("Total Lines - %td\n", lines);
|
gb_printf("Total Lines - %td\n", lines);
|
||||||
gb_printf("Total Tokens - %td\n", tokens);
|
gb_printf("Total Tokens - %td\n", tokens);
|
||||||
gb_printf("Total Files - %td\n", files);
|
gb_printf("Total Files - %td\n", files);
|
||||||
gb_printf("Total Packages - %td\n", packages);
|
gb_printf("Total Packages - %td\n", packages);
|
||||||
|
gb_printf("Total File Size - %td\n", total_file_size);
|
||||||
gb_printf("\n");
|
gb_printf("\n");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@@ -623,6 +725,9 @@ void show_timings(Checker *c, Timings *t) {
|
|||||||
gb_printf("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
|
gb_printf("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
|
||||||
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/parse_time);
|
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/parse_time);
|
||||||
gb_printf("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens);
|
gb_printf("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens);
|
||||||
|
gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time);
|
||||||
|
gb_printf("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size);
|
||||||
|
|
||||||
gb_printf("\n");
|
gb_printf("\n");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@@ -634,6 +739,8 @@ void show_timings(Checker *c, Timings *t) {
|
|||||||
gb_printf("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
|
gb_printf("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
|
||||||
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/parse_time);
|
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/parse_time);
|
||||||
gb_printf("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens);
|
gb_printf("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens);
|
||||||
|
gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time);
|
||||||
|
gb_printf("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size);
|
||||||
gb_printf("\n");
|
gb_printf("\n");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@@ -643,6 +750,8 @@ void show_timings(Checker *c, Timings *t) {
|
|||||||
gb_printf("us/LOC - %.3f\n", 1.0e6*total_time/cast(f64)lines);
|
gb_printf("us/LOC - %.3f\n", 1.0e6*total_time/cast(f64)lines);
|
||||||
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/total_time);
|
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/total_time);
|
||||||
gb_printf("us/Token - %.3f\n", 1.0e6*total_time/cast(f64)tokens);
|
gb_printf("us/Token - %.3f\n", 1.0e6*total_time/cast(f64)tokens);
|
||||||
|
gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/total_time);
|
||||||
|
gb_printf("us/bytes - %.3f\n", 1.0e6*total_time/cast(f64)total_file_size);
|
||||||
gb_printf("\n");
|
gb_printf("\n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -741,6 +850,8 @@ int main(int arg_count, char **arg_ptr) {
|
|||||||
// NOTE(bill): 'core' cannot be (re)defined by the user
|
// NOTE(bill): 'core' cannot be (re)defined by the user
|
||||||
add_library_collection(str_lit("core"), get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("core")));
|
add_library_collection(str_lit("core"), get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("core")));
|
||||||
|
|
||||||
|
map_init(&build_context.defined_values, heap_allocator());
|
||||||
|
|
||||||
Array<String> args = setup_args(arg_count, arg_ptr);
|
Array<String> args = setup_args(arg_count, arg_ptr);
|
||||||
|
|
||||||
String command = args[1];
|
String command = args[1];
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ Token ast_token(Ast *node) {
|
|||||||
return ast_token(node->SelectorExpr.selector);
|
return ast_token(node->SelectorExpr.selector);
|
||||||
}
|
}
|
||||||
return node->SelectorExpr.token;
|
return node->SelectorExpr.token;
|
||||||
|
case Ast_ImplicitSelectorExpr:
|
||||||
|
if (node->ImplicitSelectorExpr.selector != nullptr) {
|
||||||
|
return ast_token(node->ImplicitSelectorExpr.selector);
|
||||||
|
}
|
||||||
|
return node->ImplicitSelectorExpr.token;
|
||||||
case Ast_IndexExpr: return node->IndexExpr.open;
|
case Ast_IndexExpr: return node->IndexExpr.open;
|
||||||
case Ast_SliceExpr: return node->SliceExpr.open;
|
case Ast_SliceExpr: return node->SliceExpr.open;
|
||||||
case Ast_Ellipsis: return node->Ellipsis.token;
|
case Ast_Ellipsis: return node->Ellipsis.token;
|
||||||
@@ -165,6 +170,9 @@ Ast *clone_ast(Ast *node) {
|
|||||||
n->SelectorExpr.expr = clone_ast(n->SelectorExpr.expr);
|
n->SelectorExpr.expr = clone_ast(n->SelectorExpr.expr);
|
||||||
n->SelectorExpr.selector = clone_ast(n->SelectorExpr.selector);
|
n->SelectorExpr.selector = clone_ast(n->SelectorExpr.selector);
|
||||||
break;
|
break;
|
||||||
|
case Ast_ImplicitSelectorExpr:
|
||||||
|
n->ImplicitSelectorExpr.selector = clone_ast(n->ImplicitSelectorExpr.selector);
|
||||||
|
break;
|
||||||
case Ast_IndexExpr:
|
case Ast_IndexExpr:
|
||||||
n->IndexExpr.expr = clone_ast(n->IndexExpr.expr);
|
n->IndexExpr.expr = clone_ast(n->IndexExpr.expr);
|
||||||
n->IndexExpr.index = clone_ast(n->IndexExpr.index);
|
n->IndexExpr.index = clone_ast(n->IndexExpr.index);
|
||||||
@@ -504,11 +512,20 @@ Ast *ast_call_expr(AstFile *f, Ast *proc, Array<Ast *> args, Token open, Token c
|
|||||||
|
|
||||||
Ast *ast_selector_expr(AstFile *f, Token token, Ast *expr, Ast *selector) {
|
Ast *ast_selector_expr(AstFile *f, Token token, Ast *expr, Ast *selector) {
|
||||||
Ast *result = alloc_ast_node(f, Ast_SelectorExpr);
|
Ast *result = alloc_ast_node(f, Ast_SelectorExpr);
|
||||||
|
result->SelectorExpr.token = token;
|
||||||
result->SelectorExpr.expr = expr;
|
result->SelectorExpr.expr = expr;
|
||||||
result->SelectorExpr.selector = selector;
|
result->SelectorExpr.selector = selector;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ast *ast_implicit_selector_expr(AstFile *f, Token token, Ast *selector) {
|
||||||
|
Ast *result = alloc_ast_node(f, Ast_ImplicitSelectorExpr);
|
||||||
|
result->ImplicitSelectorExpr.token = token;
|
||||||
|
result->ImplicitSelectorExpr.selector = selector;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Ast *ast_index_expr(AstFile *f, Ast *expr, Ast *index, Token open, Token close) {
|
Ast *ast_index_expr(AstFile *f, Ast *expr, Ast *index, Token open, Token close) {
|
||||||
Ast *result = alloc_ast_node(f, Ast_IndexExpr);
|
Ast *result = alloc_ast_node(f, Ast_IndexExpr);
|
||||||
result->IndexExpr.expr = expr;
|
result->IndexExpr.expr = expr;
|
||||||
@@ -1199,7 +1216,6 @@ void fix_advance_to_next_stmt(AstFile *f) {
|
|||||||
case Token_package:
|
case Token_package:
|
||||||
case Token_foreign:
|
case Token_foreign:
|
||||||
case Token_import:
|
case Token_import:
|
||||||
case Token_export:
|
|
||||||
|
|
||||||
case Token_if:
|
case Token_if:
|
||||||
case Token_for:
|
case Token_for:
|
||||||
@@ -1209,7 +1225,6 @@ void fix_advance_to_next_stmt(AstFile *f) {
|
|||||||
case Token_defer:
|
case Token_defer:
|
||||||
case Token_asm:
|
case Token_asm:
|
||||||
case Token_using:
|
case Token_using:
|
||||||
case Token_static:
|
|
||||||
|
|
||||||
case Token_break:
|
case Token_break:
|
||||||
case Token_continue:
|
case Token_continue:
|
||||||
@@ -1614,7 +1629,6 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
|||||||
case Token_offset_of:
|
case Token_offset_of:
|
||||||
return parse_call_expr(f, ast_implicit(f, advance_token(f)));
|
return parse_call_expr(f, ast_implicit(f, advance_token(f)));
|
||||||
|
|
||||||
|
|
||||||
case Token_String:
|
case Token_String:
|
||||||
return ast_basic_lit(f, advance_token(f));
|
return ast_basic_lit(f, advance_token(f));
|
||||||
|
|
||||||
@@ -2279,6 +2293,12 @@ Ast *parse_unary_expr(AstFile *f, bool lhs) {
|
|||||||
Ast *expr = parse_unary_expr(f, lhs);
|
Ast *expr = parse_unary_expr(f, lhs);
|
||||||
return ast_unary_expr(f, token, expr);
|
return ast_unary_expr(f, token, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Token_Period: {
|
||||||
|
Token token = expect_token(f, Token_Period);
|
||||||
|
Ast *ident = parse_ident(f);
|
||||||
|
return ast_implicit_selector_expr(f, token, ident);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return parse_atom_expr(f, parse_operand(f, lhs), lhs);
|
return parse_atom_expr(f, parse_operand(f, lhs), lhs);
|
||||||
@@ -2452,9 +2472,7 @@ void parse_foreign_block_decl(AstFile *f, Array<Ast *> *decls) {
|
|||||||
Ast *parse_foreign_block(AstFile *f, Token token) {
|
Ast *parse_foreign_block(AstFile *f, Token token) {
|
||||||
CommentGroup *docs = f->lead_comment;
|
CommentGroup *docs = f->lead_comment;
|
||||||
Ast *foreign_library = nullptr;
|
Ast *foreign_library = nullptr;
|
||||||
if (f->curr_token.kind == Token_export) {
|
if (f->curr_token.kind == Token_OpenBrace) {
|
||||||
foreign_library = ast_implicit(f, expect_token(f, Token_export));
|
|
||||||
} else if (f->curr_token.kind == Token_OpenBrace) {
|
|
||||||
foreign_library = ast_ident(f, blank_token);
|
foreign_library = ast_ident(f, blank_token);
|
||||||
} else {
|
} else {
|
||||||
foreign_library = parse_ident(f);
|
foreign_library = parse_ident(f);
|
||||||
@@ -2700,6 +2718,7 @@ ProcCallingConvention string_to_calling_convention(String s) {
|
|||||||
if (s == "std") return ProcCC_StdCall;
|
if (s == "std") return ProcCC_StdCall;
|
||||||
if (s == "fastcall") return ProcCC_FastCall;
|
if (s == "fastcall") return ProcCC_FastCall;
|
||||||
if (s == "fast") return ProcCC_FastCall;
|
if (s == "fast") return ProcCC_FastCall;
|
||||||
|
if (s == "none") return ProcCC_None;
|
||||||
return ProcCC_Invalid;
|
return ProcCC_Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3589,7 +3608,6 @@ Ast *parse_foreign_decl(AstFile *f) {
|
|||||||
Token token = expect_token(f, Token_foreign);
|
Token token = expect_token(f, Token_foreign);
|
||||||
|
|
||||||
switch (f->curr_token.kind) {
|
switch (f->curr_token.kind) {
|
||||||
case Token_export:
|
|
||||||
case Token_Ident:
|
case Token_Ident:
|
||||||
case Token_OpenBrace:
|
case Token_OpenBrace:
|
||||||
return parse_foreign_block(f, token);
|
return parse_foreign_block(f, token);
|
||||||
@@ -3666,6 +3684,7 @@ Ast *parse_attribute(AstFile *f, Token token, TokenKind open_kind, TokenKind clo
|
|||||||
f->curr_token.kind != Token_EOF) {
|
f->curr_token.kind != Token_EOF) {
|
||||||
Ast *elem = nullptr;
|
Ast *elem = nullptr;
|
||||||
elem = parse_ident(f);
|
elem = parse_ident(f);
|
||||||
|
|
||||||
if (f->curr_token.kind == Token_Eq) {
|
if (f->curr_token.kind == Token_Eq) {
|
||||||
Token eq = expect_token(f, Token_Eq);
|
Token eq = expect_token(f, Token_Eq);
|
||||||
Ast *value = parse_value(f);
|
Ast *value = parse_value(f);
|
||||||
@@ -3731,9 +3750,6 @@ Ast *parse_stmt(AstFile *f) {
|
|||||||
case Token_import:
|
case Token_import:
|
||||||
return parse_import_decl(f, ImportDecl_Standard);
|
return parse_import_decl(f, ImportDecl_Standard);
|
||||||
|
|
||||||
// case Token_export:
|
|
||||||
// return parse_export_decl(f);
|
|
||||||
|
|
||||||
|
|
||||||
case Token_if: return parse_if_stmt(f);
|
case Token_if: return parse_if_stmt(f);
|
||||||
case Token_when: return parse_when_stmt(f);
|
case Token_when: return parse_when_stmt(f);
|
||||||
@@ -3756,33 +3772,33 @@ Ast *parse_stmt(AstFile *f) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Token_static: {
|
// case Token_static: {
|
||||||
CommentGroup *docs = f->lead_comment;
|
// CommentGroup *docs = f->lead_comment;
|
||||||
Token token = expect_token(f, Token_static);
|
// Token token = expect_token(f, Token_static);
|
||||||
|
|
||||||
Ast *decl = nullptr;
|
// Ast *decl = nullptr;
|
||||||
Array<Ast *> list = parse_lhs_expr_list(f);
|
// Array<Ast *> list = parse_lhs_expr_list(f);
|
||||||
if (list.count == 0) {
|
// if (list.count == 0) {
|
||||||
syntax_error(token, "Illegal use of 'static' statement");
|
// syntax_error(token, "Illegal use of 'static' statement");
|
||||||
expect_semicolon(f, nullptr);
|
// expect_semicolon(f, nullptr);
|
||||||
return ast_bad_stmt(f, token, f->curr_token);
|
// return ast_bad_stmt(f, token, f->curr_token);
|
||||||
}
|
// }
|
||||||
|
|
||||||
expect_token_after(f, Token_Colon, "identifier list");
|
// expect_token_after(f, Token_Colon, "identifier list");
|
||||||
decl = parse_value_decl(f, list, docs);
|
// decl = parse_value_decl(f, list, docs);
|
||||||
|
|
||||||
if (decl != nullptr && decl->kind == Ast_ValueDecl) {
|
// if (decl != nullptr && decl->kind == Ast_ValueDecl) {
|
||||||
if (decl->ValueDecl.is_mutable) {
|
// if (decl->ValueDecl.is_mutable) {
|
||||||
decl->ValueDecl.is_static = true;
|
// decl->ValueDecl.is_static = true;
|
||||||
} else {
|
// } else {
|
||||||
error(token, "'static' may only be currently used with variable declaration");
|
// error(token, "'static' may only be currently used with variable declaration");
|
||||||
}
|
// }
|
||||||
return decl;
|
// return decl;
|
||||||
}
|
// }
|
||||||
|
|
||||||
syntax_error(token, "Illegal use of 'static' statement");
|
// syntax_error(token, "Illegal use of 'static' statement");
|
||||||
return ast_bad_stmt(f, token, f->curr_token);
|
// return ast_bad_stmt(f, token, f->curr_token);
|
||||||
} break;
|
// } break;
|
||||||
|
|
||||||
case Token_using: {
|
case Token_using: {
|
||||||
CommentGroup *docs = f->lead_comment;
|
CommentGroup *docs = f->lead_comment;
|
||||||
|
|||||||
@@ -151,7 +151,6 @@ enum ProcTag {
|
|||||||
ProcTag_bounds_check = 1<<0,
|
ProcTag_bounds_check = 1<<0,
|
||||||
ProcTag_no_bounds_check = 1<<1,
|
ProcTag_no_bounds_check = 1<<1,
|
||||||
ProcTag_require_results = 1<<4,
|
ProcTag_require_results = 1<<4,
|
||||||
ProcTag_no_context = 1<<6,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ProcCallingConvention {
|
enum ProcCallingConvention {
|
||||||
@@ -166,6 +165,9 @@ enum ProcCallingConvention {
|
|||||||
// ProcCC_VectorCall,
|
// ProcCC_VectorCall,
|
||||||
// ProcCC_ClrCall,
|
// ProcCC_ClrCall,
|
||||||
|
|
||||||
|
ProcCC_None,
|
||||||
|
|
||||||
|
|
||||||
ProcCC_ForeignBlockDefault = -1,
|
ProcCC_ForeignBlockDefault = -1,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -242,6 +244,7 @@ AST_KIND(_ExprBegin, "", bool) \
|
|||||||
AST_KIND(BinaryExpr, "binary expression", struct { Token op; Ast *left, *right; } ) \
|
AST_KIND(BinaryExpr, "binary expression", struct { Token op; Ast *left, *right; } ) \
|
||||||
AST_KIND(ParenExpr, "parentheses expression", struct { Ast *expr; Token open, close; }) \
|
AST_KIND(ParenExpr, "parentheses expression", struct { Ast *expr; Token open, close; }) \
|
||||||
AST_KIND(SelectorExpr, "selector expression", struct { Token token; Ast *expr, *selector; }) \
|
AST_KIND(SelectorExpr, "selector expression", struct { Token token; Ast *expr, *selector; }) \
|
||||||
|
AST_KIND(ImplicitSelectorExpr, "implicit selector expression", struct { Token token; Ast *selector; }) \
|
||||||
AST_KIND(IndexExpr, "index expression", struct { Ast *expr, *index; Token open, close; }) \
|
AST_KIND(IndexExpr, "index expression", struct { Ast *expr, *index; Token open, close; }) \
|
||||||
AST_KIND(DerefExpr, "dereference expression", struct { Token op; Ast *expr; }) \
|
AST_KIND(DerefExpr, "dereference expression", struct { Token op; Ast *expr; }) \
|
||||||
AST_KIND(SliceExpr, "slice expression", struct { \
|
AST_KIND(SliceExpr, "slice expression", struct { \
|
||||||
@@ -373,7 +376,6 @@ AST_KIND(_DeclBegin, "", bool) \
|
|||||||
Array<Ast *> attributes; \
|
Array<Ast *> attributes; \
|
||||||
CommentGroup *docs; \
|
CommentGroup *docs; \
|
||||||
CommentGroup *comment; \
|
CommentGroup *comment; \
|
||||||
bool is_static; \
|
|
||||||
bool is_using; \
|
bool is_using; \
|
||||||
bool is_mutable; \
|
bool is_mutable; \
|
||||||
}) \
|
}) \
|
||||||
|
|||||||
@@ -308,7 +308,6 @@ String directory_from_path(String const &s) {
|
|||||||
return substring(s, 0, i);
|
return substring(s, 0, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
String concatenate_strings(gbAllocator a, String const &x, String const &y) {
|
String concatenate_strings(gbAllocator a, String const &x, String const &y) {
|
||||||
isize len = x.len+y.len;
|
isize len = x.len+y.len;
|
||||||
u8 *data = gb_alloc_array(a, u8, len+1);
|
u8 *data = gb_alloc_array(a, u8, len+1);
|
||||||
|
|||||||
@@ -82,7 +82,6 @@ TOKEN_KIND(Token__OperatorEnd, ""), \
|
|||||||
\
|
\
|
||||||
TOKEN_KIND(Token__KeywordBegin, ""), \
|
TOKEN_KIND(Token__KeywordBegin, ""), \
|
||||||
TOKEN_KIND(Token_import, "import"), \
|
TOKEN_KIND(Token_import, "import"), \
|
||||||
TOKEN_KIND(Token_export, "export"), \
|
|
||||||
TOKEN_KIND(Token_foreign, "foreign"), \
|
TOKEN_KIND(Token_foreign, "foreign"), \
|
||||||
TOKEN_KIND(Token_package, "package"), \
|
TOKEN_KIND(Token_package, "package"), \
|
||||||
TOKEN_KIND(Token_typeid, "typeid"), \
|
TOKEN_KIND(Token_typeid, "typeid"), \
|
||||||
@@ -101,14 +100,12 @@ TOKEN_KIND(Token__KeywordBegin, ""), \
|
|||||||
TOKEN_KIND(Token_defer, "defer"), \
|
TOKEN_KIND(Token_defer, "defer"), \
|
||||||
TOKEN_KIND(Token_return, "return"), \
|
TOKEN_KIND(Token_return, "return"), \
|
||||||
TOKEN_KIND(Token_proc, "proc"), \
|
TOKEN_KIND(Token_proc, "proc"), \
|
||||||
TOKEN_KIND(Token_macro, "macro"), \
|
|
||||||
TOKEN_KIND(Token_struct, "struct"), \
|
TOKEN_KIND(Token_struct, "struct"), \
|
||||||
TOKEN_KIND(Token_union, "union"), \
|
TOKEN_KIND(Token_union, "union"), \
|
||||||
TOKEN_KIND(Token_enum, "enum"), \
|
TOKEN_KIND(Token_enum, "enum"), \
|
||||||
TOKEN_KIND(Token_bit_field, "bit_field"), \
|
TOKEN_KIND(Token_bit_field, "bit_field"), \
|
||||||
TOKEN_KIND(Token_bit_set, "bit_set"), \
|
TOKEN_KIND(Token_bit_set, "bit_set"), \
|
||||||
TOKEN_KIND(Token_map, "map"), \
|
TOKEN_KIND(Token_map, "map"), \
|
||||||
TOKEN_KIND(Token_static, "static"), \
|
|
||||||
TOKEN_KIND(Token_dynamic, "dynamic"), \
|
TOKEN_KIND(Token_dynamic, "dynamic"), \
|
||||||
TOKEN_KIND(Token_auto_cast, "auto_cast"), \
|
TOKEN_KIND(Token_auto_cast, "auto_cast"), \
|
||||||
TOKEN_KIND(Token_cast, "cast"), \
|
TOKEN_KIND(Token_cast, "cast"), \
|
||||||
@@ -123,6 +120,7 @@ TOKEN_KIND(Token__KeywordBegin, ""), \
|
|||||||
TOKEN_KIND(Token_align_of, "align_of"), \
|
TOKEN_KIND(Token_align_of, "align_of"), \
|
||||||
TOKEN_KIND(Token_offset_of, "offset_of"), \
|
TOKEN_KIND(Token_offset_of, "offset_of"), \
|
||||||
TOKEN_KIND(Token_type_of, "type_of"), \
|
TOKEN_KIND(Token_type_of, "type_of"), \
|
||||||
|
TOKEN_KIND(Token_macro, "macro"), \
|
||||||
TOKEN_KIND(Token_const, "const"), \
|
TOKEN_KIND(Token_const, "const"), \
|
||||||
TOKEN_KIND(Token_asm, "asm"), \
|
TOKEN_KIND(Token_asm, "asm"), \
|
||||||
TOKEN_KIND(Token_yield, "yield"), \
|
TOKEN_KIND(Token_yield, "yield"), \
|
||||||
|
|||||||
153
src/types.cpp
153
src/types.cpp
@@ -198,6 +198,7 @@ struct TypeUnion {
|
|||||||
bool has_proc_default_values; \
|
bool has_proc_default_values; \
|
||||||
bool has_named_results; \
|
bool has_named_results; \
|
||||||
bool diverging; /* no return */ \
|
bool diverging; /* no return */ \
|
||||||
|
u64 tags; \
|
||||||
isize specialization_count; \
|
isize specialization_count; \
|
||||||
ProcCallingConvention calling_convention; \
|
ProcCallingConvention calling_convention; \
|
||||||
}) \
|
}) \
|
||||||
@@ -215,6 +216,12 @@ struct TypeUnion {
|
|||||||
i64 lower; \
|
i64 lower; \
|
||||||
i64 upper; \
|
i64 upper; \
|
||||||
}) \
|
}) \
|
||||||
|
TYPE_KIND(SimdVector, struct { \
|
||||||
|
i64 count; \
|
||||||
|
Type *elem; \
|
||||||
|
bool is_x86_mmx; \
|
||||||
|
}) \
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -460,13 +467,13 @@ gb_global Type *t_type_info_map = nullptr;
|
|||||||
gb_global Type *t_type_info_bit_field = nullptr;
|
gb_global Type *t_type_info_bit_field = nullptr;
|
||||||
gb_global Type *t_type_info_bit_set = nullptr;
|
gb_global Type *t_type_info_bit_set = nullptr;
|
||||||
gb_global Type *t_type_info_opaque = nullptr;
|
gb_global Type *t_type_info_opaque = nullptr;
|
||||||
|
gb_global Type *t_type_info_simd_vector = nullptr;
|
||||||
|
|
||||||
gb_global Type *t_type_info_named_ptr = nullptr;
|
gb_global Type *t_type_info_named_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_integer_ptr = nullptr;
|
gb_global Type *t_type_info_integer_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_rune_ptr = nullptr;
|
gb_global Type *t_type_info_rune_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_float_ptr = nullptr;
|
gb_global Type *t_type_info_float_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_complex_ptr = nullptr;
|
gb_global Type *t_type_info_complex_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_quaternion_ptr = nullptr;
|
|
||||||
gb_global Type *t_type_info_any_ptr = nullptr;
|
gb_global Type *t_type_info_any_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_typeid_ptr = nullptr;
|
gb_global Type *t_type_info_typeid_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_string_ptr = nullptr;
|
gb_global Type *t_type_info_string_ptr = nullptr;
|
||||||
@@ -484,6 +491,7 @@ gb_global Type *t_type_info_map_ptr = nullptr;
|
|||||||
gb_global Type *t_type_info_bit_field_ptr = nullptr;
|
gb_global Type *t_type_info_bit_field_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_bit_set_ptr = nullptr;
|
gb_global Type *t_type_info_bit_set_ptr = nullptr;
|
||||||
gb_global Type *t_type_info_opaque_ptr = nullptr;
|
gb_global Type *t_type_info_opaque_ptr = nullptr;
|
||||||
|
gb_global Type *t_type_info_simd_vector_ptr = nullptr;
|
||||||
|
|
||||||
gb_global Type *t_allocator = nullptr;
|
gb_global Type *t_allocator = nullptr;
|
||||||
gb_global Type *t_allocator_ptr = nullptr;
|
gb_global Type *t_allocator_ptr = nullptr;
|
||||||
@@ -496,6 +504,8 @@ gb_global Type *t_source_code_location_ptr = nullptr;
|
|||||||
gb_global Type *t_map_key = nullptr;
|
gb_global Type *t_map_key = nullptr;
|
||||||
gb_global Type *t_map_header = nullptr;
|
gb_global Type *t_map_header = nullptr;
|
||||||
|
|
||||||
|
gb_global Type *t_vector_x86_mmx = nullptr;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
i64 type_size_of (Type *t);
|
i64 type_size_of (Type *t);
|
||||||
@@ -722,6 +732,13 @@ Type *alloc_type_bit_set() {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Type *alloc_type_simd_vector(i64 count, Type *elem) {
|
||||||
|
Type *t = alloc_type(Type_SimdVector);
|
||||||
|
t->SimdVector.count = count;
|
||||||
|
t->SimdVector.elem = elem;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
@@ -958,11 +975,20 @@ bool is_type_poly_proc(Type *t) {
|
|||||||
t = base_type(t);
|
t = base_type(t);
|
||||||
return t->kind == Type_Proc && t->Proc.is_polymorphic;
|
return t->kind == Type_Proc && t->Proc.is_polymorphic;
|
||||||
}
|
}
|
||||||
|
bool is_type_simd_vector(Type *t) {
|
||||||
|
t = base_type(t);
|
||||||
|
return t->kind == Type_SimdVector;
|
||||||
|
}
|
||||||
|
|
||||||
Type *base_array_type(Type *t) {
|
Type *base_array_type(Type *t) {
|
||||||
if (is_type_array(t)) {
|
if (is_type_array(t)) {
|
||||||
t = base_type(t);
|
t = base_type(t);
|
||||||
return t->Array.elem;
|
return t->Array.elem;
|
||||||
}
|
}
|
||||||
|
if (is_type_simd_vector(t)) {
|
||||||
|
t = base_type(t);
|
||||||
|
return t->SimdVector.elem;
|
||||||
|
}
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -972,6 +998,7 @@ bool is_type_generic(Type *t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Type *core_array_type(Type *t) {
|
Type *core_array_type(Type *t) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
Type *prev = t;
|
Type *prev = t;
|
||||||
@@ -1193,6 +1220,25 @@ Type *bit_set_to_int(Type *t) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_type_valid_vector_elem(Type *t) {
|
||||||
|
t = base_type(t);
|
||||||
|
if (t->kind == Type_Basic) {
|
||||||
|
if (t->Basic.flags & BasicFlag_EndianLittle) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (t->Basic.flags & BasicFlag_EndianBig) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (is_type_integer(t)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (is_type_float(t)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool is_type_indexable(Type *t) {
|
bool is_type_indexable(Type *t) {
|
||||||
Type *bt = base_type(t);
|
Type *bt = base_type(t);
|
||||||
@@ -1637,6 +1683,18 @@ bool are_types_identical(Type *x, Type *y) {
|
|||||||
are_types_identical(x->Map.value, y->Map.value);
|
are_types_identical(x->Map.value, y->Map.value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Type_SimdVector:
|
||||||
|
if (y->kind == Type_SimdVector) {
|
||||||
|
if (x->SimdVector.is_x86_mmx == y->SimdVector.is_x86_mmx) {
|
||||||
|
if (x->SimdVector.is_x86_mmx) {
|
||||||
|
return true;
|
||||||
|
} else if (x->SimdVector.count == y->SimdVector.count) {
|
||||||
|
return are_types_identical(x->SimdVector.elem, y->SimdVector.elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -1681,65 +1739,6 @@ Type *default_type(Type *type) {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// NOTE(bill): Valid Compile time execution #run type
|
|
||||||
bool is_type_cte_safe(Type *type) {
|
|
||||||
type = default_type(base_type(type));
|
|
||||||
switch (type->kind) {
|
|
||||||
case Type_Basic:
|
|
||||||
switch (type->Basic.kind) {
|
|
||||||
case Basic_rawptr:
|
|
||||||
case Basic_any:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case Type_Pointer:
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case Type_Array:
|
|
||||||
return is_type_cte_safe(type->Array.elem);
|
|
||||||
|
|
||||||
case Type_DynamicArray:
|
|
||||||
return false;
|
|
||||||
case Type_Map:
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case Type_Slice:
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case Type_Struct: {
|
|
||||||
if (type->Struct.is_raw_union) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for_array(i, type->Struct.fields) {
|
|
||||||
Entity *v = type->Struct.fields[i];
|
|
||||||
if (!is_type_cte_safe(v->type)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Type_Tuple: {
|
|
||||||
for_array(i, type->Tuple.variables) {
|
|
||||||
Entity *v = type->Tuple.variables[i];
|
|
||||||
if (!is_type_cte_safe(v->type)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Type_Proc:
|
|
||||||
// TODO(bill): How should I handle procedures in the CTE stage?
|
|
||||||
// return type->Proc.calling_convention == ProcCC_Odin;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
i64 union_variant_index(Type *u, Type *v) {
|
i64 union_variant_index(Type *u, Type *v) {
|
||||||
u = base_type(u);
|
u = base_type(u);
|
||||||
GB_ASSERT(u->kind == Type_Union);
|
GB_ASSERT(u->kind == Type_Union);
|
||||||
@@ -2389,7 +2388,18 @@ i64 type_align_of_internal(Type *t, TypePath *path) {
|
|||||||
if (bits <= 32) return 4;
|
if (bits <= 32) return 4;
|
||||||
if (bits <= 64) return 8;
|
if (bits <= 64) return 8;
|
||||||
return 8; // NOTE(bill): Could be an invalid range so limit it for now
|
return 8; // NOTE(bill): Could be an invalid range so limit it for now
|
||||||
|
}
|
||||||
|
|
||||||
|
case Type_SimdVector: {
|
||||||
|
if (t->SimdVector.is_x86_mmx) {
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
// align of
|
||||||
|
i64 count = t->SimdVector.count;
|
||||||
|
Type *elem = t->SimdVector.elem;
|
||||||
|
i64 size = count * type_size_of_internal(elem, path);
|
||||||
|
// IMPORTANT TODO(bill): Figure out the alignment of vector types
|
||||||
|
return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.max_align);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2622,6 +2632,15 @@ i64 type_size_of_internal(Type *t, TypePath *path) {
|
|||||||
if (bits <= 64) return 8;
|
if (bits <= 64) return 8;
|
||||||
return 8; // NOTE(bill): Could be an invalid range so limit it for now
|
return 8; // NOTE(bill): Could be an invalid range so limit it for now
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Type_SimdVector: {
|
||||||
|
if (t->SimdVector.is_x86_mmx) {
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
i64 count = t->SimdVector.count;
|
||||||
|
Type *elem = t->SimdVector.elem;
|
||||||
|
return count * type_size_of_internal(elem, path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Catch all
|
// Catch all
|
||||||
@@ -2894,6 +2913,9 @@ gbString write_type_to_string(gbString str, Type *type) {
|
|||||||
case ProcCC_FastCall:
|
case ProcCC_FastCall:
|
||||||
str = gb_string_appendc(str, " \"fastcall\" ");
|
str = gb_string_appendc(str, " \"fastcall\" ");
|
||||||
break;
|
break;
|
||||||
|
case ProcCC_None:
|
||||||
|
str = gb_string_appendc(str, " \"none\" ");
|
||||||
|
break;
|
||||||
// case ProcCC_VectorCall:
|
// case ProcCC_VectorCall:
|
||||||
// str = gb_string_appendc(str, " \"vectorcall\" ");
|
// str = gb_string_appendc(str, " \"vectorcall\" ");
|
||||||
// break;
|
// break;
|
||||||
@@ -2947,6 +2969,17 @@ gbString write_type_to_string(gbString str, Type *type) {
|
|||||||
}
|
}
|
||||||
str = gb_string_appendc(str, "]");
|
str = gb_string_appendc(str, "]");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Type_SimdVector:
|
||||||
|
if (type->SimdVector.is_x86_mmx) {
|
||||||
|
return "intrinsics.x86_mmx";
|
||||||
|
} else {
|
||||||
|
str = gb_string_appendc(str, "intrinsics.vector(");
|
||||||
|
str = gb_string_append_fmt(str, "%d, ", cast(int)type->SimdVector.count);
|
||||||
|
str = write_type_to_string(str, type->SimdVector.elem);
|
||||||
|
str = gb_string_appendc(str, ")");
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
|
|||||||
Reference in New Issue
Block a user