mirror of
https://github.com/odin-lang/Odin.git
synced 2026-01-01 02:42:09 +00:00
Merge branch 'master' into master
This commit is contained in:
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 {
|
||||
src: []byte,
|
||||
src: []byte,
|
||||
|
||||
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_manitissa :: proc(t: ^Tokenizer, base: int) {
|
||||
scan_mantissa :: proc(t: ^Tokenizer, base: int) {
|
||||
for digit_value(t.curr_rune) < base || t.curr_rune == '_' {
|
||||
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);
|
||||
}
|
||||
if digit_value(t.curr_rune) < 10 {
|
||||
scan_manitissa(t, 10);
|
||||
scan_mantissa(t, 10);
|
||||
} else {
|
||||
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 == '.' {
|
||||
tok = Float;
|
||||
advance_to_next_rune(t);
|
||||
scan_manitissa(t, 10);
|
||||
scan_mantissa(t, 10);
|
||||
}
|
||||
|
||||
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 {
|
||||
offset -= 1;
|
||||
tok = Float;
|
||||
scan_manitissa(t, 10);
|
||||
scan_mantissa(t, 10);
|
||||
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 {
|
||||
case 'b', 'B':
|
||||
advance_to_next_rune(t);
|
||||
scan_manitissa(t, 2);
|
||||
scan_mantissa(t, 2);
|
||||
if t.offset - offset <= 2 {
|
||||
token_error(t, "Illegal binary number");
|
||||
}
|
||||
case 'o', 'O':
|
||||
advance_to_next_rune(t);
|
||||
scan_manitissa(t, 8);
|
||||
scan_mantissa(t, 8);
|
||||
if t.offset - offset <= 2 {
|
||||
token_error(t, "Illegal octal number");
|
||||
}
|
||||
case 'x', 'X':
|
||||
advance_to_next_rune(t);
|
||||
scan_manitissa(t, 16);
|
||||
scan_mantissa(t, 16);
|
||||
if t.offset - offset <= 2 {
|
||||
token_error(t, "Illegal hexadecimal number");
|
||||
}
|
||||
case:
|
||||
scan_manitissa(t, 10);
|
||||
scan_mantissa(t, 10);
|
||||
switch t.curr_rune {
|
||||
case '.', 'e', 'E':
|
||||
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]);
|
||||
}
|
||||
|
||||
scan_manitissa(t, 10);
|
||||
scan_mantissa(t, 10);
|
||||
|
||||
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;
|
||||
start := 0;
|
||||
|
||||
using strconv.Int_Flag;
|
||||
flags: strconv.Int_Flags;
|
||||
if fi.hash && !fi.zero do flags |= {Prefix};
|
||||
if fi.plus do flags |= {Plus};
|
||||
if fi.space do flags |= {Space};
|
||||
if fi.hash && !fi.zero do flags |= {.Prefix};
|
||||
if fi.plus do flags |= {.Plus};
|
||||
if fi.space do flags |= {.Space};
|
||||
s := strconv.append_bits(buf[start:], u, base, is_signed, bit_size, digits, flags);
|
||||
|
||||
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);
|
||||
switch info in ti.variant {
|
||||
case runtime.Type_Info_Integer:
|
||||
using runtime.Type_Info_Endianness;
|
||||
switch info.endianness {
|
||||
case Platform: return false;
|
||||
case Little: return ODIN_ENDIAN != "little";
|
||||
case Big: return ODIN_ENDIAN != "big";
|
||||
case .Platform: return false;
|
||||
case .Little: return ODIN_ENDIAN != "little";
|
||||
case .Big: return ODIN_ENDIAN != "big";
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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:
|
||||
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_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,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64, location := #caller_location) -> rawptr {
|
||||
using Allocator_Mode;
|
||||
arena := cast(^Arena)allocator_data;
|
||||
|
||||
|
||||
switch mode {
|
||||
case Alloc:
|
||||
case .Alloc:
|
||||
total_size := size + alignment;
|
||||
|
||||
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);
|
||||
return zero(ptr, size);
|
||||
|
||||
case Free:
|
||||
case .Free:
|
||||
// NOTE(bill): Free all at once
|
||||
// Use Arena_Temp_Memory if you want to free a block
|
||||
|
||||
case Free_All:
|
||||
case .Free_All:
|
||||
arena.offset = 0;
|
||||
|
||||
case Resize:
|
||||
case .Resize:
|
||||
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,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64, location := #caller_location) -> rawptr {
|
||||
using Allocator_Mode;
|
||||
s := cast(^Stack)allocator_data;
|
||||
|
||||
if s.data == nil {
|
||||
@@ -256,9 +253,9 @@ stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
}
|
||||
|
||||
switch mode {
|
||||
case Alloc:
|
||||
case .Alloc:
|
||||
return raw_alloc(s, size, alignment);
|
||||
case Free:
|
||||
case .Free:
|
||||
if old_memory == nil {
|
||||
return nil;
|
||||
}
|
||||
@@ -288,11 +285,11 @@ stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
s.prev_offset = int(header.prev_offset);
|
||||
|
||||
|
||||
case Free_All:
|
||||
case .Free_All:
|
||||
s.prev_offset = 0;
|
||||
s.curr_offset = 0;
|
||||
|
||||
case Resize:
|
||||
case .Resize:
|
||||
if old_memory == nil {
|
||||
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,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64, location := #caller_location) -> rawptr {
|
||||
using Allocator_Mode;
|
||||
s := cast(^Small_Stack)allocator_data;
|
||||
|
||||
if s.data == 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 {
|
||||
curr_addr := uintptr(&s.data[0]) + uintptr(s.offset);
|
||||
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 {
|
||||
case Alloc:
|
||||
case .Alloc:
|
||||
return raw_alloc(s, size, alignment);
|
||||
case Free:
|
||||
case .Free:
|
||||
if old_memory == nil {
|
||||
return nil;
|
||||
}
|
||||
@@ -426,10 +424,10 @@ small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
|
||||
s.offset = int(old_offset);
|
||||
|
||||
case Free_All:
|
||||
case .Free_All:
|
||||
s.offset = 0;
|
||||
|
||||
case Resize:
|
||||
case .Resize:
|
||||
if old_memory == nil {
|
||||
return raw_alloc(s, size, alignment);
|
||||
}
|
||||
|
||||
@@ -183,6 +183,14 @@ align_forward_uintptr :: proc(ptr, align: uintptr) -> uintptr {
|
||||
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.allocator = a;
|
||||
return context;
|
||||
|
||||
@@ -144,6 +144,10 @@ Selector_Expr :: struct {
|
||||
field: ^Ident,
|
||||
}
|
||||
|
||||
Implicit_Selector_Expr :: struct {
|
||||
using node: Expr,
|
||||
field: ^Ident,
|
||||
}
|
||||
|
||||
Index_Expr :: struct {
|
||||
using node: Expr,
|
||||
@@ -365,7 +369,6 @@ Value_Decl :: struct {
|
||||
type: ^Expr,
|
||||
values: []^Expr,
|
||||
comment: ^Comment_Group,
|
||||
is_static: bool,
|
||||
is_using: bool,
|
||||
is_mutable: bool,
|
||||
}
|
||||
|
||||
@@ -857,10 +857,6 @@ parse_foreign_block :: proc(p: ^Parser, tok: token.Token) -> ^ast.Foreign_Block_
|
||||
|
||||
foreign_library: ^ast.Expr;
|
||||
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:
|
||||
i := ast.new(ast.Ident, tok.pos, end_pos(tok));
|
||||
i.name = "_";
|
||||
@@ -903,7 +899,7 @@ parse_foreign_decl :: proc(p: ^Parser) -> ^ast.Decl {
|
||||
tok := expect_token(p, token.Foreign);
|
||||
|
||||
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);
|
||||
|
||||
case token.Import:
|
||||
@@ -1033,37 +1029,6 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
||||
expect_semicolon(p, 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:
|
||||
docs := p.lead_comment;
|
||||
tok := expect_token(p, token.Using);
|
||||
@@ -1112,9 +1077,9 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
||||
stmt := parse_stmt(p);
|
||||
switch name {
|
||||
case "bounds_check":
|
||||
stmt.state_flags |= {ast.Node_State_Flag.Bounds_Check};
|
||||
stmt.state_flags |= {.Bounds_Check};
|
||||
case "no_bounds_check":
|
||||
stmt.state_flags |= {ast.Node_State_Flag.No_Bounds_Check};
|
||||
stmt.state_flags |= {.No_Bounds_Check};
|
||||
}
|
||||
return stmt;
|
||||
case "complete":
|
||||
@@ -1758,6 +1723,29 @@ string_to_calling_convention :: proc(s: string) -> ast.Proc_Calling_Convention {
|
||||
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 {
|
||||
cc := ast.Proc_Calling_Convention.Invalid;
|
||||
if p.curr_tok.kind == token.String {
|
||||
@@ -2616,6 +2604,13 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||
ue.expr = expr;
|
||||
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);
|
||||
}
|
||||
@@ -2707,7 +2702,7 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt {
|
||||
return stmt;
|
||||
|
||||
case op.kind == token.In:
|
||||
if Stmt_Allow_Flag.In in flags {
|
||||
if .In in flags {
|
||||
allow_token(p, token.In);
|
||||
prev_allow_range := p.allow_range;
|
||||
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:
|
||||
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 {
|
||||
case token.Open_Brace, token.If, token.For, token.Switch:
|
||||
label := lhs[0];
|
||||
|
||||
@@ -28,7 +28,7 @@ pos_compare :: proc(lhs, rhs: Pos) -> int {
|
||||
return strings.compare(lhs.file, rhs.file);
|
||||
}
|
||||
|
||||
using Kind :: enum u16 {
|
||||
using Kind :: enum u32 {
|
||||
Invalid,
|
||||
EOF,
|
||||
Comment,
|
||||
@@ -113,7 +113,6 @@ using Kind :: enum u16 {
|
||||
|
||||
B_Keyword_Begin,
|
||||
Import,
|
||||
Export,
|
||||
Foreign,
|
||||
Package,
|
||||
Typeid,
|
||||
@@ -139,7 +138,6 @@ using Kind :: enum u16 {
|
||||
Bit_Field,
|
||||
Bit_Set,
|
||||
Map,
|
||||
Static,
|
||||
Dynamic,
|
||||
Auto_Cast,
|
||||
Cast,
|
||||
@@ -161,6 +159,9 @@ using Kind :: enum u16 {
|
||||
B_Keyword_End,
|
||||
|
||||
COUNT,
|
||||
|
||||
B_Custom_Keyword_Begin = COUNT+1,
|
||||
// ... Custom keywords
|
||||
};
|
||||
|
||||
tokens := [Kind.COUNT]string {
|
||||
@@ -248,7 +249,6 @@ tokens := [Kind.COUNT]string {
|
||||
|
||||
"",
|
||||
"import",
|
||||
"export",
|
||||
"foreign",
|
||||
"package",
|
||||
"typeid",
|
||||
@@ -274,7 +274,6 @@ tokens := [Kind.COUNT]string {
|
||||
"bit_field",
|
||||
"bit_set",
|
||||
"map",
|
||||
"static",
|
||||
"dynamic",
|
||||
"auto_cast",
|
||||
"cast",
|
||||
@@ -296,10 +295,19 @@ tokens := [Kind.COUNT]string {
|
||||
"",
|
||||
};
|
||||
|
||||
custom_keyword_tokens: []string;
|
||||
|
||||
to_string :: proc(kind: Kind) -> string {
|
||||
if min(Kind) <= kind && kind <= max(Kind) {
|
||||
if Invalid <= kind && kind < COUNT {
|
||||
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";
|
||||
}
|
||||
|
||||
@@ -316,4 +324,12 @@ is_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;
|
||||
}
|
||||
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):
|
||||
lit = scan_identifier(t);
|
||||
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
|
||||
for i in token.B_Keyword_Begin .. token.B_Keyword_End {
|
||||
if lit == token.tokens[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) {
|
||||
fd, err := open(name, O_RDONLY, 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,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr {
|
||||
using mem.Allocator_Mode;
|
||||
|
||||
switch mode {
|
||||
case Alloc:
|
||||
case .Alloc:
|
||||
return heap_alloc(size);
|
||||
|
||||
case Free:
|
||||
case .Free:
|
||||
heap_free(old_memory);
|
||||
return nil;
|
||||
|
||||
case Free_All:
|
||||
case .Free_All:
|
||||
// NOTE(bill): Does nothing
|
||||
|
||||
case Resize:
|
||||
case .Resize:
|
||||
if old_memory == nil {
|
||||
return heap_alloc(size);
|
||||
}
|
||||
|
||||
@@ -112,9 +112,14 @@ Type_Info_Bit_Set :: struct {
|
||||
lower: i64,
|
||||
upper: i64,
|
||||
};
|
||||
|
||||
Type_Info_Opaque :: struct {
|
||||
elem: ^Type_Info,
|
||||
};
|
||||
Type_Info_Simd_Vector :: struct {
|
||||
elem: ^Type_Info,
|
||||
elem_size: int,
|
||||
count: int,
|
||||
is_x86_mmx: bool,
|
||||
}
|
||||
|
||||
Type_Info :: struct {
|
||||
@@ -145,6 +150,7 @@ Type_Info :: struct {
|
||||
Type_Info_Bit_Field,
|
||||
Type_Info_Bit_Set,
|
||||
Type_Info_Opaque,
|
||||
Type_Info_Simd_Vector,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -245,8 +251,10 @@ Map_Entry_Header :: struct {
|
||||
Map_Header :: struct {
|
||||
m: ^mem.Raw_Map,
|
||||
is_key_string: bool,
|
||||
|
||||
entry_size: int,
|
||||
entry_align: int,
|
||||
|
||||
value_offset: uintptr,
|
||||
value_size: int,
|
||||
}
|
||||
@@ -827,29 +835,23 @@ __get_map_key :: proc "contextless" (key: $K) -> 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 {
|
||||
fnv64a :: proc(data: []byte) -> u64 {
|
||||
h: u64 = 0xcbf29ce484222325;
|
||||
for b in data {
|
||||
h = (h ~ u64(b)) * 0x100000001b3;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
return fnv64a(data);
|
||||
return _fnv64a(data);
|
||||
}
|
||||
default_hash_string :: proc(s: string) -> u64 do return default_hash(([]byte)(s));
|
||||
|
||||
|
||||
source_code_location_hash :: proc(s: Source_Code_Location) -> u64 {
|
||||
fnv64a :: proc(data: []byte, seed: u64 = 0xcbf29ce484222325) -> u64 {
|
||||
h: u64 = seed;
|
||||
for b in data {
|
||||
h = (h ~ u64(b)) * 0x100000001b3;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
hash := fnv64a(cast([]byte)s.file_path);
|
||||
hash := _fnv64a(cast([]byte)s.file_path);
|
||||
hash = hash ~ (u64(s.line) * 0x100000001b3);
|
||||
hash = hash ~ (u64(s.column) * 0x100000001b3);
|
||||
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 {
|
||||
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 {
|
||||
|
||||
index: int;
|
||||
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];
|
||||
|
||||
if Int_Flag.Prefix in flags {
|
||||
if .Prefix in flags {
|
||||
ok := true;
|
||||
switch base {
|
||||
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 {
|
||||
case neg:
|
||||
i-=1; a[i] = '-';
|
||||
case Int_Flag.Plus in flags:
|
||||
case .Plus in flags:
|
||||
i-=1; a[i] = '+';
|
||||
case Int_Flag.Space in flags:
|
||||
case .Space in flags:
|
||||
i-=1; a[i] = ' ';
|
||||
}
|
||||
|
||||
|
||||
@@ -61,8 +61,8 @@ write_bytes :: proc(b: ^Builder, x: []byte) {
|
||||
append(&b.buf, ..x);
|
||||
}
|
||||
|
||||
@(private)
|
||||
static DIGITS_LOWER := "0123456789abcdefx";
|
||||
@(private, static)
|
||||
DIGITS_LOWER := "0123456789abcdefx";
|
||||
|
||||
write_quoted_string :: proc(b: ^Builder, s: string, quote: byte = '"') {
|
||||
write_byte(b, quote);
|
||||
|
||||
@@ -329,6 +329,10 @@ is_space :: proc(r: rune) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
is_null :: proc(r: rune) -> bool {
|
||||
return r == 0x0000;
|
||||
}
|
||||
|
||||
index_proc :: proc(s: string, p: proc(rune) -> bool, truth := true) -> int {
|
||||
for r, i in s {
|
||||
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`
|
||||
// `allocator` is used only for the slice
|
||||
// `skip_empty=true` does not return zero-length substrings
|
||||
|
||||
@@ -2,6 +2,11 @@ package sync
|
||||
|
||||
import "core:sys/win32"
|
||||
|
||||
foreign {
|
||||
@(link_name="llvm.x86.sse2.pause")
|
||||
yield_processor :: proc() ---
|
||||
}
|
||||
|
||||
Semaphore :: struct {
|
||||
_handle: win32.Handle,
|
||||
}
|
||||
@@ -14,6 +19,12 @@ Condition :: struct {
|
||||
event: win32.Handle,
|
||||
}
|
||||
|
||||
Ticket_Mutex :: struct {
|
||||
ticket: u64,
|
||||
serving: u64,
|
||||
}
|
||||
|
||||
|
||||
current_thread_id :: proc() -> i32 {
|
||||
return i32(win32.get_current_thread_id());
|
||||
}
|
||||
@@ -81,3 +92,20 @@ condition_destroy :: proc(using c: ^Condition) {
|
||||
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
|
||||
|
||||
foreign import "system:comdlg32.lib"
|
||||
import "core:strings"
|
||||
|
||||
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 {
|
||||
@(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="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 ---
|
||||
}
|
||||
|
||||
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_DONTADDTORECENT :: 0x02000000;
|
||||
OFN_ENABLEHOOK :: 0x00000020;
|
||||
@@ -91,3 +172,18 @@ OFN_PATHMUSTEXIST :: 0x00000800;
|
||||
OFN_READONLY :: 0x00000001;
|
||||
OFN_SHAREAWARE :: 0x00004000;
|
||||
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,
|
||||
}
|
||||
|
||||
// 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{
|
||||
file_attributes: u32,
|
||||
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_WIDE :: 0x8000;
|
||||
|
||||
HANDLE_FLAG_INHERIT :: 1;
|
||||
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="GetFileAttributesA") get_file_attributes_a :: proc(filename: cstring) -> 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="GetFileAttributesExW") get_file_attributes_ex_w :: proc(filename: Wstring, 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: ^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="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="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="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="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);
|
||||
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[1] = 0x80 | u8(r>>12) & mask;
|
||||
buf[2] = 0x80 | u8(r>>6) & mask;
|
||||
buf[3] = 0x80 | u8(r) & mask;
|
||||
buf[3] = 0x80 | u8(r) & mask;
|
||||
return buf, 4;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user