mirror of
https://github.com/odin-lang/Odin.git
synced 2026-08-19 20:01:36 +00:00
Merge branch 'master' into middle-end
This commit is contained in:
@@ -111,6 +111,8 @@ foreign user32 {
|
||||
@(link_name="SetWindowTextW") set_window_text_w :: proc(hwnd: Hwnd, c_string: Wstring) -> Bool ---
|
||||
@(link_name="RegisterClassA") register_class_a :: proc(wc: ^Wnd_Class_A) -> i16 ---
|
||||
@(link_name="RegisterClassW") register_class_w :: proc(wc: ^Wnd_Class_W) -> i16 ---
|
||||
@(link_name="UnregisterClassA") unregister_class_a :: proc(class_name: cstring, instance: Hinstance) -> Bool ---
|
||||
@(link_name="UnregisterClassW") unregister_class_w :: proc(class_name: Wstring, instance: Hinstance) -> Bool ---
|
||||
@(link_name="RegisterClassExA") register_class_ex_a :: proc(wc: ^Wnd_Class_Ex_A) -> i16 ---
|
||||
@(link_name="RegisterClassExW") register_class_ex_w :: proc(wc: ^Wnd_Class_Ex_W) -> i16 ---
|
||||
|
||||
|
||||
@@ -578,7 +578,7 @@ PROCESS_INFORMATION :: struct {
|
||||
}
|
||||
|
||||
// FYI: This is STARTUPINFOW, not STARTUPINFOA
|
||||
STARTUPINFO :: struct #packed {
|
||||
STARTUPINFO :: struct {
|
||||
cb: DWORD,
|
||||
lpReserved: LPWSTR,
|
||||
lpDesktop: LPWSTR,
|
||||
|
||||
@@ -16,140 +16,140 @@ String :: struct {
|
||||
}
|
||||
|
||||
@(private)
|
||||
_len :: builtin.len; // helper procedure
|
||||
_len :: builtin.len // helper procedure
|
||||
|
||||
init :: proc(s: ^String, contents: string) -> ^String {
|
||||
s.contents = contents;
|
||||
s.byte_pos = 0;
|
||||
s.rune_pos = 0;
|
||||
s.contents = contents
|
||||
s.byte_pos = 0
|
||||
s.rune_pos = 0
|
||||
|
||||
for i in 0..<_len(contents) {
|
||||
if contents[i] >= utf8.RUNE_SELF {
|
||||
s.rune_count = utf8.rune_count_in_string(contents);
|
||||
_, s.width = utf8.decode_rune_in_string(contents);
|
||||
s.non_ascii = i;
|
||||
return s;
|
||||
s.rune_count = utf8.rune_count_in_string(contents)
|
||||
_, s.width = utf8.decode_rune_in_string(contents)
|
||||
s.non_ascii = i
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
s.rune_count = _len(contents);
|
||||
s.width = 0;
|
||||
s.non_ascii = _len(contents);
|
||||
return s;
|
||||
s.rune_count = _len(contents)
|
||||
s.width = 0
|
||||
s.non_ascii = _len(contents)
|
||||
return s
|
||||
}
|
||||
|
||||
to_string :: proc(s: ^String) -> string {
|
||||
return s.contents;
|
||||
return s.contents
|
||||
}
|
||||
|
||||
len :: proc(s: ^String) -> int {
|
||||
return s.rune_count;
|
||||
return s.rune_count
|
||||
}
|
||||
|
||||
|
||||
is_ascii :: proc(s: ^String) -> bool {
|
||||
return s.width == 0;
|
||||
return s.width == 0
|
||||
}
|
||||
|
||||
at :: proc(s: ^String, i: int, loc := #caller_location) -> (r: rune) {
|
||||
runtime.bounds_check_error_loc(loc, i, s.rune_count);
|
||||
runtime.bounds_check_error_loc(loc, i, s.rune_count)
|
||||
|
||||
if i < s.non_ascii {
|
||||
return rune(s.contents[i]);
|
||||
return rune(s.contents[i])
|
||||
}
|
||||
|
||||
switch i {
|
||||
case 0:
|
||||
r, s.width = utf8.decode_rune_in_string(s.contents);
|
||||
s.rune_pos = 0;
|
||||
s.byte_pos = 0;
|
||||
return;
|
||||
r, s.width = utf8.decode_rune_in_string(s.contents)
|
||||
s.rune_pos = 0
|
||||
s.byte_pos = 0
|
||||
return
|
||||
|
||||
case s.rune_count-1:
|
||||
r, s.width = utf8.decode_rune_in_string(s.contents);
|
||||
s.rune_pos = i;
|
||||
s.byte_pos = _len(s.contents) - s.width;
|
||||
return;
|
||||
r, s.width = utf8.decode_rune_in_string(s.contents)
|
||||
s.rune_pos = i
|
||||
s.byte_pos = _len(s.contents) - s.width
|
||||
return
|
||||
|
||||
case s.rune_pos-1:
|
||||
r, s.width = utf8.decode_rune_in_string(s.contents[0:s.byte_pos]);
|
||||
s.rune_pos = i;
|
||||
s.byte_pos -= s.width;
|
||||
return;
|
||||
r, s.width = utf8.decode_rune_in_string(s.contents[0:s.byte_pos])
|
||||
s.rune_pos = i
|
||||
s.byte_pos -= s.width
|
||||
return
|
||||
|
||||
case s.rune_pos+1:
|
||||
s.rune_pos = i;
|
||||
s.byte_pos += s.width;
|
||||
fallthrough;
|
||||
s.rune_pos = i
|
||||
s.byte_pos += s.width
|
||||
fallthrough
|
||||
case s.rune_pos:
|
||||
r, s.width = utf8.decode_rune_in_string(s.contents[s.byte_pos:]);
|
||||
return;
|
||||
r, s.width = utf8.decode_rune_in_string(s.contents[s.byte_pos:])
|
||||
return
|
||||
}
|
||||
|
||||
// Linear scan
|
||||
scan_forward := true;
|
||||
scan_forward := true
|
||||
if i < s.rune_pos {
|
||||
if i < (s.rune_pos-s.non_ascii)/2 {
|
||||
s.byte_pos, s.rune_pos = s.non_ascii, s.non_ascii;
|
||||
s.byte_pos, s.rune_pos = s.non_ascii, s.non_ascii
|
||||
} else {
|
||||
scan_forward = false;
|
||||
scan_forward = false
|
||||
}
|
||||
} else if i-s.rune_pos < (s.rune_count-s.rune_pos)/2 {
|
||||
// scan_forward = true;
|
||||
// scan_forward = true
|
||||
} else {
|
||||
s.byte_pos, s.rune_pos = _len(s.contents), s.rune_count;
|
||||
scan_forward = false;
|
||||
s.byte_pos, s.rune_pos = _len(s.contents), s.rune_count
|
||||
scan_forward = false
|
||||
}
|
||||
|
||||
if scan_forward {
|
||||
for {
|
||||
r, s.width = utf8.decode_rune_in_string(s.contents[s.byte_pos:]);
|
||||
r, s.width = utf8.decode_rune_in_string(s.contents[s.byte_pos:])
|
||||
if s.rune_pos == i {
|
||||
return;
|
||||
return
|
||||
}
|
||||
s.rune_pos += 1;
|
||||
s.byte_pos += s.width;
|
||||
s.rune_pos += 1
|
||||
s.byte_pos += s.width
|
||||
|
||||
}
|
||||
} else {
|
||||
for {
|
||||
r, s.width = utf8.decode_last_rune_in_string(s.contents[:s.byte_pos]);
|
||||
s.rune_pos -= 1;
|
||||
s.byte_pos -= s.width;
|
||||
r, s.width = utf8.decode_last_rune_in_string(s.contents[:s.byte_pos])
|
||||
s.rune_pos -= 1
|
||||
s.byte_pos -= s.width
|
||||
if s.rune_pos == i {
|
||||
return;
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
slice :: proc(s: ^String, i, j: int, loc := #caller_location) -> string {
|
||||
runtime.slice_expr_error_lo_hi_loc(loc, i, j, s.rune_count);
|
||||
runtime.slice_expr_error_lo_hi_loc(loc, i, j, s.rune_count)
|
||||
|
||||
if j < s.non_ascii {
|
||||
return s.contents[i:j];
|
||||
return s.contents[i:j]
|
||||
}
|
||||
|
||||
if i == j {
|
||||
return "";
|
||||
return ""
|
||||
}
|
||||
|
||||
lo, hi: int;
|
||||
lo, hi: int
|
||||
if i < s.non_ascii {
|
||||
lo = i;
|
||||
lo = i
|
||||
} else if i == s.rune_count {
|
||||
lo = _len(s.contents);
|
||||
lo = _len(s.contents)
|
||||
} else {
|
||||
at(s, i, loc);
|
||||
lo = s.byte_pos;
|
||||
at(s, i, loc)
|
||||
lo = s.byte_pos
|
||||
}
|
||||
|
||||
if j == s.rune_count {
|
||||
hi = _len(s.contents);
|
||||
hi = _len(s.contents)
|
||||
} else {
|
||||
at(s, j, loc);
|
||||
hi = s.byte_pos;
|
||||
at(s, j, loc)
|
||||
hi = s.byte_pos
|
||||
}
|
||||
|
||||
return s.contents[lo:hi];
|
||||
return s.contents[lo:hi]
|
||||
}
|
||||
|
||||
@@ -104,6 +104,7 @@ import time "core:time"
|
||||
|
||||
import unicode "core:unicode"
|
||||
import utf8 "core:unicode/utf8"
|
||||
import utf8string "core:unicode/utf8/utf8string"
|
||||
import utf16 "core:unicode/utf16"
|
||||
|
||||
main :: proc(){}
|
||||
@@ -193,4 +194,5 @@ _ :: thread
|
||||
_ :: time
|
||||
_ :: unicode
|
||||
_ :: utf8
|
||||
_ :: utf8string
|
||||
_ :: utf16
|
||||
@@ -4881,25 +4881,16 @@ bool is_expr_constant_zero(Ast *expr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
||||
ast_node(ce, CallExpr, call);
|
||||
GB_ASSERT(is_type_proc(proc_type));
|
||||
proc_type = base_type(proc_type);
|
||||
TypeProc *pt = &proc_type->Proc;
|
||||
|
||||
isize get_procedure_param_count_excluding_defaults(Type *pt, isize *param_count_) {
|
||||
GB_ASSERT(pt != nullptr);
|
||||
GB_ASSERT(pt->kind == Type_Proc);
|
||||
isize param_count = 0;
|
||||
isize param_count_excluding_defaults = 0;
|
||||
bool variadic = pt->variadic;
|
||||
bool vari_expand = (ce->ellipsis.pos.line != 0);
|
||||
i64 score = 0;
|
||||
bool show_error = show_error_mode == CallArgumentMode_ShowErrors;
|
||||
|
||||
|
||||
bool variadic = pt->Proc.variadic;
|
||||
TypeTuple *param_tuple = nullptr;
|
||||
|
||||
if (pt->params != nullptr) {
|
||||
param_tuple = &pt->params->Tuple;
|
||||
if (pt->Proc.params != nullptr) {
|
||||
param_tuple = &pt->Proc.params->Tuple;
|
||||
|
||||
param_count = param_tuple->variables.count;
|
||||
if (variadic) {
|
||||
@@ -4939,6 +4930,31 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
||||
}
|
||||
}
|
||||
|
||||
if (param_count_) *param_count_ = param_count;
|
||||
return param_count_excluding_defaults;
|
||||
}
|
||||
|
||||
|
||||
CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
||||
ast_node(ce, CallExpr, call);
|
||||
GB_ASSERT(is_type_proc(proc_type));
|
||||
proc_type = base_type(proc_type);
|
||||
TypeProc *pt = &proc_type->Proc;
|
||||
|
||||
isize param_count = 0;
|
||||
isize param_count_excluding_defaults = get_procedure_param_count_excluding_defaults(proc_type, ¶m_count);
|
||||
bool variadic = pt->variadic;
|
||||
bool vari_expand = (ce->ellipsis.pos.line != 0);
|
||||
i64 score = 0;
|
||||
bool show_error = show_error_mode == CallArgumentMode_ShowErrors;
|
||||
|
||||
|
||||
TypeTuple *param_tuple = nullptr;
|
||||
if (pt->params != nullptr) {
|
||||
param_tuple = &pt->params->Tuple;
|
||||
}
|
||||
|
||||
|
||||
CallArgumentError err = CallArgumentError_None;
|
||||
Type *final_proc_type = proc_type;
|
||||
Entity *gen_entity = nullptr;
|
||||
@@ -5611,7 +5627,37 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type
|
||||
if (operand->mode == Addressing_ProcGroup) {
|
||||
check_entity_decl(c, operand->proc_group, nullptr, nullptr);
|
||||
|
||||
Array<Entity *> procs = proc_group_entities(c, *operand);
|
||||
auto procs = proc_group_entities_cloned(c, *operand);
|
||||
|
||||
if (procs.count > 1) {
|
||||
isize max_arg_count = args.count;
|
||||
for_array(i, args) {
|
||||
// NOTE(bill): The only thing that may have multiple values
|
||||
// will be a call expression (assuming `or_return` and `()` will be stripped)
|
||||
Ast *arg = strip_or_return_expr(args[i]);
|
||||
if (arg && arg->kind == Ast_CallExpr) {
|
||||
max_arg_count = ISIZE_MAX;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (isize proc_index = 0; proc_index < procs.count; /**/) {
|
||||
Entity *proc = procs[proc_index];
|
||||
Type *pt = base_type(proc->type);
|
||||
if (!(pt != nullptr && is_type_proc(pt))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
isize param_count = 0;
|
||||
isize param_count_excluding_defaults = get_procedure_param_count_excluding_defaults(pt, ¶m_count);
|
||||
|
||||
if (param_count_excluding_defaults > max_arg_count) {
|
||||
array_unordered_remove(&procs, proc_index);
|
||||
} else {
|
||||
proc_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (procs.count == 1) {
|
||||
Ast *ident = operand->expr;
|
||||
@@ -5641,6 +5687,7 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
Entity **lhs = nullptr;
|
||||
isize lhs_count = -1;
|
||||
|
||||
|
||||
@@ -1960,20 +1960,6 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node,
|
||||
if (params) param_count = params ->Tuple.variables.count;
|
||||
if (results) result_count = results->Tuple.variables.count;
|
||||
|
||||
if (param_count > 0) {
|
||||
for_array(i, params->Tuple.variables) {
|
||||
Entity *param = params->Tuple.variables[i];
|
||||
if (param->kind == Entity_Variable) {
|
||||
ParameterValue pv = param->Variable.param_value;
|
||||
if (pv.kind == ParameterValue_Constant &&
|
||||
pv.value.kind == ExactValue_Procedure) {
|
||||
type->Proc.has_proc_default_values = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result_count > 0) {
|
||||
Entity *first = results->Tuple.variables[0];
|
||||
type->Proc.has_named_results = first->token.string != "";
|
||||
|
||||
@@ -2657,6 +2657,15 @@ Array<Entity *> proc_group_entities(CheckerContext *c, Operand o) {
|
||||
return procs;
|
||||
}
|
||||
|
||||
Array<Entity *> proc_group_entities_cloned(CheckerContext *c, Operand o) {
|
||||
auto entities = proc_group_entities(c, o);
|
||||
if (entities.count == 0) {
|
||||
return {};
|
||||
}
|
||||
return array_clone(permanent_allocator(), entities);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void init_core_type_info(Checker *c) {
|
||||
|
||||
@@ -118,6 +118,16 @@ struct ParameterValue {
|
||||
};
|
||||
};
|
||||
|
||||
bool has_parameter_value(ParameterValue const ¶m_value) {
|
||||
if (param_value.kind != ParameterValue_Invalid) {
|
||||
return true;
|
||||
}
|
||||
if (param_value.original_ast_expr != nullptr) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
enum EntityConstantFlags : u32 {
|
||||
EntityConstantFlag_ImplicitEnumValue = 1<<0,
|
||||
};
|
||||
|
||||
@@ -186,7 +186,6 @@ struct TypeProc {
|
||||
bool c_vararg;
|
||||
bool is_polymorphic;
|
||||
bool is_poly_specialized;
|
||||
bool has_proc_default_values;
|
||||
bool has_named_results;
|
||||
bool diverging; // no return
|
||||
bool return_by_pointer;
|
||||
|
||||
Reference in New Issue
Block a user