mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
Named procedure calls
This commit is contained in:
+3
-3
@@ -13,7 +13,7 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
|
|||||||
// TODO(bill): is this a good enough error message?
|
// TODO(bill): is this a good enough error message?
|
||||||
// TODO(bill): Actually allow built in procedures to be passed around and thus be created on use
|
// TODO(bill): Actually allow built in procedures to be passed around and thus be created on use
|
||||||
error_node(operand->expr,
|
error_node(operand->expr,
|
||||||
"Cannot assign builtin procedure `%s` in %.*s",
|
"Cannot assign built-in procedure `%s` in %.*s",
|
||||||
expr_str,
|
expr_str,
|
||||||
LIT(context_name));
|
LIT(context_name));
|
||||||
|
|
||||||
@@ -145,7 +145,7 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) {
|
|||||||
|
|
||||||
// gb_printf_err("%.*s %p\n", LIT(e->token.string), e);
|
// gb_printf_err("%.*s %p\n", LIT(e->token.string), e);
|
||||||
|
|
||||||
Type *bt = check_type_extra(c, type_expr, named);
|
Type *bt = check_type(c, type_expr, named);
|
||||||
named->Named.base = base_type(bt);
|
named->Named.base = base_type(bt);
|
||||||
if (named->Named.base == t_invalid) {
|
if (named->Named.base == t_invalid) {
|
||||||
// gb_printf("check_type_decl: %s\n", type_to_string(named));
|
// gb_printf("check_type_decl: %s\n", type_to_string(named));
|
||||||
@@ -408,7 +408,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
|||||||
e->flags |= EntityFlag_Visited;
|
e->flags |= EntityFlag_Visited;
|
||||||
|
|
||||||
if (type_expr != NULL) {
|
if (type_expr != NULL) {
|
||||||
e->type = check_type_extra(c, type_expr, NULL);
|
e->type = check_type(c, type_expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (init_expr == NULL) {
|
if (init_expr == NULL) {
|
||||||
|
|||||||
+310
-143
@@ -2,8 +2,7 @@ void check_expr (Checker *c, Operand *operand, AstNode *
|
|||||||
void check_multi_expr (Checker *c, Operand *operand, AstNode *expression);
|
void check_multi_expr (Checker *c, Operand *operand, AstNode *expression);
|
||||||
void check_expr_or_type (Checker *c, Operand *operand, AstNode *expression);
|
void check_expr_or_type (Checker *c, Operand *operand, AstNode *expression);
|
||||||
ExprKind check_expr_base (Checker *c, Operand *operand, AstNode *expression, Type *type_hint);
|
ExprKind check_expr_base (Checker *c, Operand *operand, AstNode *expression, Type *type_hint);
|
||||||
Type * check_type_extra (Checker *c, AstNode *expression, Type *named_type);
|
Type * check_type (Checker *c, AstNode *expression, Type *named_type = NULL);
|
||||||
Type * check_type (Checker *c, AstNode *expression);
|
|
||||||
void check_type_decl (Checker *c, Entity *e, AstNode *type_expr, Type *def);
|
void check_type_decl (Checker *c, Entity *e, AstNode *type_expr, Type *def);
|
||||||
Entity * check_selector (Checker *c, Operand *operand, AstNode *node, Type *type_hint);
|
Entity * check_selector (Checker *c, Operand *operand, AstNode *node, Type *type_hint);
|
||||||
void check_not_tuple (Checker *c, Operand *operand);
|
void check_not_tuple (Checker *c, Operand *operand);
|
||||||
@@ -22,11 +21,6 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *
|
|||||||
Type * check_call_arguments (Checker *c, Operand *operand, Type *proc_type, AstNode *call);
|
Type * check_call_arguments (Checker *c, Operand *operand, Type *proc_type, AstNode *call);
|
||||||
|
|
||||||
|
|
||||||
gb_inline Type *check_type(Checker *c, AstNode *expression) {
|
|
||||||
return check_type_extra(c, expression, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void error_operand_not_expression(Operand *o) {
|
void error_operand_not_expression(Operand *o) {
|
||||||
if (o->mode == Addressing_Type) {
|
if (o->mode == Addressing_Type) {
|
||||||
gbString err = expr_to_string(o->expr);
|
gbString err = expr_to_string(o->expr);
|
||||||
@@ -326,7 +320,7 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
|
|||||||
// TODO(bill): is this a good enough error message?
|
// TODO(bill): is this a good enough error message?
|
||||||
// TODO(bill): Actually allow built in procedures to be passed around and thus be created on use
|
// TODO(bill): Actually allow built in procedures to be passed around and thus be created on use
|
||||||
error_node(operand->expr,
|
error_node(operand->expr,
|
||||||
"Cannot assign builtin procedure `%s` in %.*s",
|
"Cannot assign built-in procedure `%s` in %.*s",
|
||||||
expr_str,
|
expr_str,
|
||||||
LIT(context_name));
|
LIT(context_name));
|
||||||
} else {
|
} else {
|
||||||
@@ -1605,8 +1599,8 @@ void check_map_type(Checker *c, Type *type, AstNode *node) {
|
|||||||
ast_node(mt, MapType, node);
|
ast_node(mt, MapType, node);
|
||||||
|
|
||||||
i64 count = check_array_or_map_count(c, mt->count, true);
|
i64 count = check_array_or_map_count(c, mt->count, true);
|
||||||
Type *key = check_type_extra(c, mt->key, NULL);
|
Type *key = check_type(c, mt->key);
|
||||||
Type *value = check_type_extra(c, mt->value, NULL);
|
Type *value = check_type(c, mt->value);
|
||||||
|
|
||||||
if (!is_type_valid_for_keys(key)) {
|
if (!is_type_valid_for_keys(key)) {
|
||||||
if (is_type_boolean(key)) {
|
if (is_type_boolean(key)) {
|
||||||
@@ -1702,7 +1696,7 @@ void check_map_type(Checker *c, Type *type, AstNode *node) {
|
|||||||
// error_node(node, "`map` types are not yet implemented");
|
// error_node(node, "`map` types are not yet implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_type_extra_internal(Checker *c, AstNode *e, Type **type, Type *named_type) {
|
bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type) {
|
||||||
GB_ASSERT_NOT_NULL(type);
|
GB_ASSERT_NOT_NULL(type);
|
||||||
if (e == NULL) {
|
if (e == NULL) {
|
||||||
*type = t_invalid;
|
*type = t_invalid;
|
||||||
@@ -1759,7 +1753,7 @@ bool check_type_extra_internal(Checker *c, AstNode *e, Type **type, Type *named_
|
|||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(pe, ParenExpr, e);
|
case_ast_node(pe, ParenExpr, e);
|
||||||
*type = check_type_extra(c, pe->expr, named_type);
|
*type = check_type(c, pe->expr, named_type);
|
||||||
return true;
|
return true;
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
@@ -1794,7 +1788,7 @@ bool check_type_extra_internal(Checker *c, AstNode *e, Type **type, Type *named_
|
|||||||
|
|
||||||
case_ast_node(at, ArrayType, e);
|
case_ast_node(at, ArrayType, e);
|
||||||
if (at->count != NULL) {
|
if (at->count != NULL) {
|
||||||
Type *elem = check_type_extra(c, at->elem, NULL);
|
Type *elem = check_type(c, at->elem, NULL);
|
||||||
i64 count = check_array_or_map_count(c, at->count, false);
|
i64 count = check_array_or_map_count(c, at->count, false);
|
||||||
if (count < 0) {
|
if (count < 0) {
|
||||||
error_node(at->count, ".. can only be used in conjuction with compound literals");
|
error_node(at->count, ".. can only be used in conjuction with compound literals");
|
||||||
@@ -1825,7 +1819,7 @@ bool check_type_extra_internal(Checker *c, AstNode *e, Type **type, Type *named_
|
|||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(dat, DynamicArrayType, e);
|
case_ast_node(dat, DynamicArrayType, e);
|
||||||
Type *elem = check_type_extra(c, dat->elem, NULL);
|
Type *elem = check_type(c, dat->elem);
|
||||||
i64 esz = type_size_of(c->allocator, elem);
|
i64 esz = type_size_of(c->allocator, elem);
|
||||||
#if 0
|
#if 0
|
||||||
if (esz == 0) {
|
if (esz == 0) {
|
||||||
@@ -1934,9 +1928,9 @@ bool check_type_extra_internal(Checker *c, AstNode *e, Type **type, Type *named_
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) {
|
Type *check_type(Checker *c, AstNode *e, Type *named_type) {
|
||||||
Type *type = NULL;
|
Type *type = NULL;
|
||||||
bool ok = check_type_extra_internal(c, e, &type, named_type);
|
bool ok = check_type_internal(c, e, &type, named_type);
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
gbString err_str = expr_to_string(e);
|
gbString err_str = expr_to_string(e);
|
||||||
@@ -3533,6 +3527,14 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ce->args.count > 0) {
|
||||||
|
if (ce->args[0]->kind == AstNode_FieldValue) {
|
||||||
|
error_node(call, "`field = value` calling is not allowed on built-in procedures");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool vari_expand = (ce->ellipsis.pos.line != 0);
|
bool vari_expand = (ce->ellipsis.pos.line != 0);
|
||||||
if (vari_expand && id != BuiltinProc_append) {
|
if (vari_expand && id != BuiltinProc_append) {
|
||||||
error(ce->ellipsis, "Invalid use of `..` with built-in procedure `append`");
|
error(ce->ellipsis, "Invalid use of `..` with built-in procedure `append`");
|
||||||
@@ -3556,7 +3558,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
|
|||||||
|
|
||||||
switch (id) {
|
switch (id) {
|
||||||
default:
|
default:
|
||||||
GB_PANIC("Implement builtin procedure: %.*s", LIT(builtin_procs[id].name));
|
GB_PANIC("Implement built-in procedure: %.*s", LIT(builtin_procs[id].name));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BuiltinProc_len:
|
case BuiltinProc_len:
|
||||||
@@ -4707,6 +4709,10 @@ enum CallArgumentError {
|
|||||||
CallArgumentError_ArgumentCount,
|
CallArgumentError_ArgumentCount,
|
||||||
CallArgumentError_TooFewArguments,
|
CallArgumentError_TooFewArguments,
|
||||||
CallArgumentError_TooManyArguments,
|
CallArgumentError_TooManyArguments,
|
||||||
|
CallArgumentError_InvalidFieldValue,
|
||||||
|
CallArgumentError_ParameterNotFound,
|
||||||
|
CallArgumentError_ParameterMissing,
|
||||||
|
CallArgumentError_DuplicateParameter,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum CallArgumentErrorMode {
|
enum CallArgumentErrorMode {
|
||||||
@@ -4714,114 +4720,6 @@ enum CallArgumentErrorMode {
|
|||||||
CallArgumentMode_ShowErrors,
|
CallArgumentMode_ShowErrors,
|
||||||
};
|
};
|
||||||
|
|
||||||
CallArgumentError check_call_arguments_internal(Checker *c, AstNode *call, Type *proc_type, Operand *operands, isize operand_count,
|
|
||||||
CallArgumentErrorMode show_error_mode, i64 *score_) {
|
|
||||||
ast_node(ce, CallExpr, call);
|
|
||||||
isize param_count = 0;
|
|
||||||
bool variadic = proc_type->Proc.variadic;
|
|
||||||
bool vari_expand = (ce->ellipsis.pos.line != 0);
|
|
||||||
i64 score = 0;
|
|
||||||
bool show_error = show_error_mode == CallArgumentMode_ShowErrors;
|
|
||||||
|
|
||||||
if (proc_type->Proc.params != NULL) {
|
|
||||||
param_count = proc_type->Proc.params->Tuple.variable_count;
|
|
||||||
if (variadic) {
|
|
||||||
param_count--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vari_expand && !variadic) {
|
|
||||||
if (show_error) {
|
|
||||||
error(ce->ellipsis,
|
|
||||||
"Cannot use `..` in call to a non-variadic procedure: `%.*s`",
|
|
||||||
LIT(ce->proc->Ident.string));
|
|
||||||
}
|
|
||||||
if (score_) *score_ = score;
|
|
||||||
return CallArgumentError_NonVariadicExpand;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (operand_count == 0 && param_count == 0) {
|
|
||||||
if (score_) *score_ = score;
|
|
||||||
return CallArgumentError_None;
|
|
||||||
}
|
|
||||||
|
|
||||||
i32 error_code = 0;
|
|
||||||
if (operand_count < param_count) {
|
|
||||||
error_code = -1;
|
|
||||||
} else if (!variadic && operand_count > param_count) {
|
|
||||||
error_code = +1;
|
|
||||||
}
|
|
||||||
if (error_code != 0) {
|
|
||||||
CallArgumentError err = CallArgumentError_TooManyArguments;
|
|
||||||
char *err_fmt = "Too many arguments for `%s`, expected %td arguments";
|
|
||||||
if (error_code < 0) {
|
|
||||||
err = CallArgumentError_TooFewArguments;
|
|
||||||
err_fmt = "Too few arguments for `%s`, expected %td arguments";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (show_error) {
|
|
||||||
gbString proc_str = expr_to_string(ce->proc);
|
|
||||||
error_node(call, err_fmt, proc_str, param_count);
|
|
||||||
gb_string_free(proc_str);
|
|
||||||
}
|
|
||||||
if (score_) *score_ = score;
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
CallArgumentError err = CallArgumentError_None;
|
|
||||||
|
|
||||||
GB_ASSERT(proc_type->Proc.params != NULL);
|
|
||||||
Entity **sig_params = proc_type->Proc.params->Tuple.variables;
|
|
||||||
isize operand_index = 0;
|
|
||||||
for (; operand_index < param_count; operand_index++) {
|
|
||||||
Type *t = sig_params[operand_index]->type;
|
|
||||||
Operand o = operands[operand_index];
|
|
||||||
if (variadic) {
|
|
||||||
o = operands[operand_index];
|
|
||||||
}
|
|
||||||
i64 s = 0;
|
|
||||||
if (!check_is_assignable_to_with_score(c, &o, t, &s)) {
|
|
||||||
if (show_error) {
|
|
||||||
check_assignment(c, &o, t, str_lit("argument"));
|
|
||||||
}
|
|
||||||
err = CallArgumentError_WrongTypes;
|
|
||||||
}
|
|
||||||
score += s;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (variadic) {
|
|
||||||
bool variadic_expand = false;
|
|
||||||
Type *slice = sig_params[param_count]->type;
|
|
||||||
GB_ASSERT(is_type_slice(slice));
|
|
||||||
Type *elem = base_type(slice)->Slice.elem;
|
|
||||||
Type *t = elem;
|
|
||||||
for (; operand_index < operand_count; operand_index++) {
|
|
||||||
Operand o = operands[operand_index];
|
|
||||||
if (vari_expand) {
|
|
||||||
variadic_expand = true;
|
|
||||||
t = slice;
|
|
||||||
if (operand_index != param_count) {
|
|
||||||
if (show_error) {
|
|
||||||
error_node(o.expr, "`..` in a variadic procedure can only have one variadic argument at the end");
|
|
||||||
}
|
|
||||||
if (score_) *score_ = score;
|
|
||||||
return CallArgumentError_MultipleVariadicExpand;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i64 s = 0;
|
|
||||||
if (!check_is_assignable_to_with_score(c, &o, t, &s)) {
|
|
||||||
if (show_error) {
|
|
||||||
check_assignment(c, &o, t, str_lit("argument"));
|
|
||||||
}
|
|
||||||
err = CallArgumentError_WrongTypes;
|
|
||||||
}
|
|
||||||
score += s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (score_) *score_ = score;
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ValidProcAndScore {
|
struct ValidProcAndScore {
|
||||||
isize index;
|
isize index;
|
||||||
@@ -4870,14 +4768,248 @@ bool check_unpack_arguments(Checker *c, isize lhs_count, Array<Operand> *operand
|
|||||||
return optional_ok;
|
return optional_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode *call) {
|
#define CALL_ARGUMENT_CHECKER(name) CallArgumentError name(Checker *c, AstNode *call, Type *proc_type, Array<Operand> operands, CallArgumentErrorMode show_error_mode, i64 *score_)
|
||||||
GB_ASSERT(call->kind == AstNode_CallExpr);
|
typedef CALL_ARGUMENT_CHECKER(CallArgumentCheckerType);
|
||||||
|
|
||||||
|
|
||||||
|
CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
||||||
|
ast_node(ce, CallExpr, call);
|
||||||
|
isize param_count = 0;
|
||||||
|
bool variadic = proc_type->Proc.variadic;
|
||||||
|
bool vari_expand = (ce->ellipsis.pos.line != 0);
|
||||||
|
i64 score = 0;
|
||||||
|
bool show_error = show_error_mode == CallArgumentMode_ShowErrors;
|
||||||
|
|
||||||
|
if (proc_type->Proc.params != NULL) {
|
||||||
|
param_count = proc_type->Proc.params->Tuple.variable_count;
|
||||||
|
if (variadic) {
|
||||||
|
param_count--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vari_expand && !variadic) {
|
||||||
|
if (show_error) {
|
||||||
|
error(ce->ellipsis,
|
||||||
|
"Cannot use `..` in call to a non-variadic procedure: `%.*s`",
|
||||||
|
LIT(ce->proc->Ident.string));
|
||||||
|
}
|
||||||
|
if (score_) *score_ = score;
|
||||||
|
return CallArgumentError_NonVariadicExpand;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operands.count == 0 && param_count == 0) {
|
||||||
|
if (score_) *score_ = score;
|
||||||
|
return CallArgumentError_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 error_code = 0;
|
||||||
|
if (operands.count < param_count) {
|
||||||
|
error_code = -1;
|
||||||
|
} else if (!variadic && operands.count > param_count) {
|
||||||
|
error_code = +1;
|
||||||
|
}
|
||||||
|
if (error_code != 0) {
|
||||||
|
CallArgumentError err = CallArgumentError_TooManyArguments;
|
||||||
|
char *err_fmt = "Too many arguments for `%s`, expected %td arguments";
|
||||||
|
if (error_code < 0) {
|
||||||
|
err = CallArgumentError_TooFewArguments;
|
||||||
|
err_fmt = "Too few arguments for `%s`, expected %td arguments";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_error) {
|
||||||
|
gbString proc_str = expr_to_string(ce->proc);
|
||||||
|
error_node(call, err_fmt, proc_str, param_count);
|
||||||
|
gb_string_free(proc_str);
|
||||||
|
}
|
||||||
|
if (score_) *score_ = score;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
CallArgumentError err = CallArgumentError_None;
|
||||||
|
|
||||||
|
GB_ASSERT(proc_type->Proc.params != NULL);
|
||||||
|
Entity **sig_params = proc_type->Proc.params->Tuple.variables;
|
||||||
|
isize operand_index = 0;
|
||||||
|
for (; operand_index < param_count; operand_index++) {
|
||||||
|
Type *t = sig_params[operand_index]->type;
|
||||||
|
Operand o = operands[operand_index];
|
||||||
|
if (variadic) {
|
||||||
|
o = operands[operand_index];
|
||||||
|
}
|
||||||
|
i64 s = 0;
|
||||||
|
if (!check_is_assignable_to_with_score(c, &o, t, &s)) {
|
||||||
|
if (show_error) {
|
||||||
|
check_assignment(c, &o, t, str_lit("argument"));
|
||||||
|
}
|
||||||
|
err = CallArgumentError_WrongTypes;
|
||||||
|
}
|
||||||
|
score += s;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (variadic) {
|
||||||
|
bool variadic_expand = false;
|
||||||
|
Type *slice = sig_params[param_count]->type;
|
||||||
|
GB_ASSERT(is_type_slice(slice));
|
||||||
|
Type *elem = base_type(slice)->Slice.elem;
|
||||||
|
Type *t = elem;
|
||||||
|
for (; operand_index < operands.count; operand_index++) {
|
||||||
|
Operand o = operands[operand_index];
|
||||||
|
if (vari_expand) {
|
||||||
|
variadic_expand = true;
|
||||||
|
t = slice;
|
||||||
|
if (operand_index != param_count) {
|
||||||
|
if (show_error) {
|
||||||
|
error_node(o.expr, "`..` in a variadic procedure can only have one variadic argument at the end");
|
||||||
|
}
|
||||||
|
if (score_) *score_ = score;
|
||||||
|
return CallArgumentError_MultipleVariadicExpand;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i64 s = 0;
|
||||||
|
if (!check_is_assignable_to_with_score(c, &o, t, &s)) {
|
||||||
|
if (show_error) {
|
||||||
|
check_assignment(c, &o, t, str_lit("argument"));
|
||||||
|
}
|
||||||
|
err = CallArgumentError_WrongTypes;
|
||||||
|
}
|
||||||
|
score += s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (score_) *score_ = score;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_call_expr_field_value(AstNodeCallExpr *ce) {
|
||||||
|
GB_ASSERT(ce != NULL);
|
||||||
|
|
||||||
|
if (ce->args.count == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ce->args[0]->kind == AstNode_FieldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
isize lookup_procedure_parameter(TypeProc *pt, String parameter_name) {
|
||||||
|
isize param_count = pt->param_count;
|
||||||
|
for (isize i = 0; i < param_count; i++) {
|
||||||
|
Entity *e = pt->params->Tuple.variables[i];
|
||||||
|
String name = e->token.string;
|
||||||
|
if (name == "_") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (name == parameter_name) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
|
||||||
|
ast_node(ce, CallExpr, call);
|
||||||
|
GB_ASSERT(is_type_proc(proc_type));
|
||||||
|
TypeProc *pt = &base_type(proc_type)->Proc;
|
||||||
|
|
||||||
|
i64 score = 0;
|
||||||
|
bool show_error = show_error_mode == CallArgumentMode_ShowErrors;
|
||||||
|
CallArgumentError err = CallArgumentError_None;
|
||||||
|
|
||||||
|
isize param_count = pt->param_count;
|
||||||
|
bool *params_visited = gb_alloc_array(c->allocator, bool, param_count);
|
||||||
|
|
||||||
|
for_array(i, ce->args) {
|
||||||
|
AstNode *arg = ce->args[i];
|
||||||
|
ast_node(fv, FieldValue, arg);
|
||||||
|
if (fv->field->kind != AstNode_Ident) {
|
||||||
|
if (show_error) {
|
||||||
|
gbString expr_str = expr_to_string(fv->field);
|
||||||
|
error_node(arg, "Invalid parameter name `%s` in procedure call", expr_str);
|
||||||
|
gb_string_free(expr_str);
|
||||||
|
}
|
||||||
|
err = CallArgumentError_InvalidFieldValue;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String name = fv->field->Ident.string;
|
||||||
|
isize index = lookup_procedure_parameter(pt, name);
|
||||||
|
if (index < 0) {
|
||||||
|
if (show_error) {
|
||||||
|
error_node(arg, "No parameter named `%.*s` for this procedure type", LIT(name));
|
||||||
|
}
|
||||||
|
err = CallArgumentError_ParameterNotFound;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (params_visited[index]) {
|
||||||
|
if (show_error) {
|
||||||
|
error_node(arg, "Duplicate parameter `%.*s` in procedure call", LIT(name));
|
||||||
|
}
|
||||||
|
err = CallArgumentError_DuplicateParameter;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
params_visited[index] = true;
|
||||||
|
Operand *o = &operands[i];
|
||||||
|
|
||||||
|
Type *param_type = pt->params->Tuple.variables[index]->type;
|
||||||
|
|
||||||
|
i64 s = 0;
|
||||||
|
if (!check_is_assignable_to_with_score(c, o, param_type, &s)) {
|
||||||
|
if (show_error) {
|
||||||
|
check_assignment(c, o, param_type, str_lit("procedure argument"));
|
||||||
|
}
|
||||||
|
err = CallArgumentError_WrongTypes;
|
||||||
|
}
|
||||||
|
score += s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
isize param_count_to_check = param_count;
|
||||||
|
if (pt->variadic) {
|
||||||
|
param_count_to_check--;
|
||||||
|
}
|
||||||
|
for (isize i = 0; i < param_count_to_check; i++) {
|
||||||
|
if (!params_visited[i]) {
|
||||||
|
if (show_error) {
|
||||||
|
Entity *e = pt->params->Tuple.variables[i];
|
||||||
|
gbString str = type_to_string(e->type);
|
||||||
|
error_node(call, "Parameter `%.*s` of type `%s` is missing in procedure call",
|
||||||
|
LIT(e->token.string), str);
|
||||||
|
gb_string_free(str);
|
||||||
|
}
|
||||||
|
err = CallArgumentError_ParameterMissing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (score_) *score_ = score;
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode *call) {
|
||||||
ast_node(ce, CallExpr, call);
|
ast_node(ce, CallExpr, call);
|
||||||
|
|
||||||
Array<Operand> operands;
|
CallArgumentCheckerType *call_checker = NULL;
|
||||||
array_init(&operands, heap_allocator(), 2*ce->args.count);
|
Array<Operand> operands = {};
|
||||||
check_unpack_arguments(c, -1, &operands, ce->args, false);
|
defer (array_free(&operands));
|
||||||
|
|
||||||
|
if (is_call_expr_field_value(ce)) {
|
||||||
|
call_checker = check_named_call_arguments;
|
||||||
|
|
||||||
|
array_init_count(&operands, heap_allocator(), ce->args.count);
|
||||||
|
for_array(i, ce->args) {
|
||||||
|
AstNode *arg = ce->args[i];
|
||||||
|
ast_node(fv, FieldValue, arg);
|
||||||
|
check_expr(c, &operands[i], fv->value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
call_checker = check_call_arguments_internal;
|
||||||
|
|
||||||
|
array_init(&operands, heap_allocator(), 2*ce->args.count);
|
||||||
|
check_unpack_arguments(c, -1, &operands, ce->args, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
GB_ASSERT(call_checker != NULL);
|
||||||
|
|
||||||
if (operand->mode == Addressing_Overload) {
|
if (operand->mode == Addressing_Overload) {
|
||||||
GB_ASSERT(operand->overload_entities != NULL &&
|
GB_ASSERT(operand->overload_entities != NULL &&
|
||||||
@@ -4888,6 +5020,9 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod
|
|||||||
ValidProcAndScore *valids = gb_alloc_array(heap_allocator(), ValidProcAndScore, overload_count);
|
ValidProcAndScore *valids = gb_alloc_array(heap_allocator(), ValidProcAndScore, overload_count);
|
||||||
isize valid_count = 0;
|
isize valid_count = 0;
|
||||||
|
|
||||||
|
defer (gb_free(heap_allocator(), procs));
|
||||||
|
defer (gb_free(heap_allocator(), valids));
|
||||||
|
|
||||||
String name = procs[0]->token.string;
|
String name = procs[0]->token.string;
|
||||||
|
|
||||||
for (isize i = 0; i < overload_count; i++) {
|
for (isize i = 0; i < overload_count; i++) {
|
||||||
@@ -4903,7 +5038,7 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod
|
|||||||
Type *proc_type = base_type(p->type);
|
Type *proc_type = base_type(p->type);
|
||||||
if (proc_type != NULL && is_type_proc(proc_type)) {
|
if (proc_type != NULL && is_type_proc(proc_type)) {
|
||||||
i64 score = 0;
|
i64 score = 0;
|
||||||
CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.data, operands.count, CallArgumentMode_NoErrors, &score);
|
CallArgumentError err = call_checker(c, call, proc_type, operands, CallArgumentMode_NoErrors, &score);
|
||||||
if (err == CallArgumentError_None) {
|
if (err == CallArgumentError_None) {
|
||||||
valids[valid_count].index = i;
|
valids[valid_count].index = i;
|
||||||
valids[valid_count].score = score;
|
valids[valid_count].score = score;
|
||||||
@@ -4948,16 +5083,14 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod
|
|||||||
add_entity_use(c, expr, e);
|
add_entity_use(c, expr, e);
|
||||||
proc_type = e->type;
|
proc_type = e->type;
|
||||||
i64 score = 0;
|
i64 score = 0;
|
||||||
CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.data, operands.count, CallArgumentMode_ShowErrors, &score);
|
CallArgumentError err = call_checker(c, call, proc_type, operands, CallArgumentMode_ShowErrors, &score);
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_free(heap_allocator(), valids);
|
|
||||||
gb_free(heap_allocator(), procs);
|
|
||||||
} else {
|
} else {
|
||||||
i64 score = 0;
|
i64 score = 0;
|
||||||
CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.data, operands.count, CallArgumentMode_ShowErrors, &score);
|
CallArgumentError err = call_checker(c, call, proc_type, operands, CallArgumentMode_ShowErrors, &score);
|
||||||
array_free(&operands);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return proc_type;
|
return proc_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4990,9 +5123,37 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
|
|||||||
ast_node(ce, CallExpr, call);
|
ast_node(ce, CallExpr, call);
|
||||||
check_expr_or_type(c, operand, ce->proc);
|
check_expr_or_type(c, operand, ce->proc);
|
||||||
|
|
||||||
|
if (ce->args.count > 0) {
|
||||||
|
bool fail = false;
|
||||||
|
bool first_is_field_value = (ce->args[0]->kind == AstNode_FieldValue);
|
||||||
|
for_array(i, ce->args) {
|
||||||
|
AstNode *arg = ce->args[i];
|
||||||
|
bool mix = false;
|
||||||
|
if (first_is_field_value) {
|
||||||
|
mix = arg->kind != AstNode_FieldValue;
|
||||||
|
} else {
|
||||||
|
mix = arg->kind == AstNode_FieldValue;
|
||||||
|
}
|
||||||
|
if (mix) {
|
||||||
|
error_node(arg, "Mixture of `field = value` and value elements in a procedure all is not allowed");
|
||||||
|
fail = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fail) {
|
||||||
|
operand->mode = Addressing_Invalid;
|
||||||
|
operand->expr = call;
|
||||||
|
return Expr_Stmt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (operand->mode == Addressing_Invalid) {
|
if (operand->mode == Addressing_Invalid) {
|
||||||
for_array(i, ce->args) {
|
for_array(i, ce->args) {
|
||||||
check_expr_base(c, operand, ce->args[i], NULL);
|
AstNode *arg = ce->args[i];
|
||||||
|
if (arg->kind == AstNode_FieldValue) {
|
||||||
|
arg = arg->FieldValue.value;
|
||||||
|
}
|
||||||
|
check_expr_base(c, operand, arg, NULL);
|
||||||
}
|
}
|
||||||
operand->mode = Addressing_Invalid;
|
operand->mode = Addressing_Invalid;
|
||||||
operand->expr = call;
|
operand->expr = call;
|
||||||
@@ -5005,14 +5166,20 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
|
|||||||
operand->mode = Addressing_Invalid;
|
operand->mode = Addressing_Invalid;
|
||||||
isize arg_count = ce->args.count;
|
isize arg_count = ce->args.count;
|
||||||
switch (arg_count) {
|
switch (arg_count) {
|
||||||
case 0: error_node(call, "Missing argument in convertion to `%s`", str); break;
|
case 0: error_node(call, "Missing argument in conversion to `%s`", str); break;
|
||||||
default: error_node(call, "Too many arguments in convertion to `%s`", str); break;
|
default: error_node(call, "Too many arguments in conversion to `%s`", str); break;
|
||||||
case 1:
|
case 1: {
|
||||||
check_expr(c, operand, ce->args[0]);
|
AstNode *arg = ce->args[0];
|
||||||
|
if (arg->kind == AstNode_FieldValue) {
|
||||||
|
error_node(call, "`field = value` cannot be used in a type conversion");
|
||||||
|
arg = arg->FieldValue.value;
|
||||||
|
// NOTE(bill): Carry on the cast regardless
|
||||||
|
}
|
||||||
|
check_expr(c, operand, arg);
|
||||||
if (operand->mode != Addressing_Invalid) {
|
if (operand->mode != Addressing_Invalid) {
|
||||||
check_cast(c, operand, t);
|
check_cast(c, operand, t);
|
||||||
}
|
}
|
||||||
break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
|
|||||||
+1
-1
@@ -1583,7 +1583,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
|
|
||||||
Type *init_type = NULL;
|
Type *init_type = NULL;
|
||||||
if (vd->type) {
|
if (vd->type) {
|
||||||
init_type = check_type_extra(c, vd->type, NULL);
|
init_type = check_type(c, vd->type, NULL);
|
||||||
if (init_type == NULL) {
|
if (init_type == NULL) {
|
||||||
init_type = t_invalid;
|
init_type = t_invalid;
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -1631,7 +1631,7 @@ void check_all_global_entities(Checker *c) {
|
|||||||
|
|
||||||
for_array(i, c->info.entities.entries) {
|
for_array(i, c->info.entities.entries) {
|
||||||
auto *entry = &c->info.entities.entries[i];
|
auto *entry = &c->info.entities.entries[i];
|
||||||
Entity *e = cast(Entity *)cast(uintptr)entry->key.key;
|
Entity *e = cast(Entity *)entry->key.ptr;
|
||||||
DeclInfo *d = entry->value;
|
DeclInfo *d = entry->value;
|
||||||
|
|
||||||
if (d->scope != e->scope) {
|
if (d->scope != e->scope) {
|
||||||
@@ -1669,7 +1669,7 @@ void check_all_global_entities(Checker *c) {
|
|||||||
|
|
||||||
for_array(i, c->info.entities.entries) {
|
for_array(i, c->info.entities.entries) {
|
||||||
auto *entry = &c->info.entities.entries[i];
|
auto *entry = &c->info.entities.entries[i];
|
||||||
Entity *e = cast(Entity *)cast(uintptr)entry->key.key;
|
Entity *e = cast(Entity *)entry->key.ptr;
|
||||||
if (e->kind != Entity_Procedure) {
|
if (e->kind != Entity_Procedure) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -2063,7 +2063,7 @@ void check_parsed_files(Checker *c) {
|
|||||||
for_array(i, c->info.untyped.entries) {
|
for_array(i, c->info.untyped.entries) {
|
||||||
auto *entry = &c->info.untyped.entries[i];
|
auto *entry = &c->info.untyped.entries[i];
|
||||||
HashKey key = entry->key;
|
HashKey key = entry->key;
|
||||||
AstNode *expr = cast(AstNode *)cast(uintptr)key.key;
|
AstNode *expr = cast(AstNode *)key.ptr;
|
||||||
ExprInfo *info = &entry->value;
|
ExprInfo *info = &entry->value;
|
||||||
if (info != NULL && expr != NULL) {
|
if (info != NULL && expr != NULL) {
|
||||||
if (is_type_typed(info->type)) {
|
if (is_type_typed(info->type)) {
|
||||||
|
|||||||
+7
-3
@@ -3,7 +3,7 @@
|
|||||||
#include <xmmintrin.h>
|
#include <xmmintrin.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define GB_NO_DEFER
|
// #define GB_NO_DEFER
|
||||||
#define GB_IMPLEMENTATION
|
#define GB_IMPLEMENTATION
|
||||||
#include "gb/gb.h"
|
#include "gb/gb.h"
|
||||||
|
|
||||||
@@ -18,18 +18,22 @@ gbAllocator heap_allocator(void) {
|
|||||||
#include "array.cpp"
|
#include "array.cpp"
|
||||||
#include "integer128.cpp"
|
#include "integer128.cpp"
|
||||||
#include "murmurhash3.cpp"
|
#include "murmurhash3.cpp"
|
||||||
#include "map.cpp"
|
|
||||||
|
|
||||||
u128 fnv128a(void const *data, isize len) {
|
u128 fnv128a(void const *data, isize len) {
|
||||||
u128 o = u128_lo_hi(0x13bull, 0x1000000ull);
|
u128 o = u128_lo_hi(0x13bull, 0x1000000ull);
|
||||||
u128 h = u128_lo_hi(0x62b821756295c58dull, 0x6c62272e07bb0142ull);
|
u128 h = u128_lo_hi(0x62b821756295c58dull, 0x6c62272e07bb0142ull);
|
||||||
u8 const *bytes = cast(u8 const *)data;
|
u8 const *bytes = cast(u8 const *)data;
|
||||||
for (isize i = 0; i < len; i++) {
|
for (isize i = 0; i < len; i++) {
|
||||||
h = u128_mul(u128_xor(h, u128_from_u64(bytes[i])), o);
|
h.lo ^= bytes[i];
|
||||||
|
h = h * o;
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "map.cpp"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
gb_global String global_module_path = {0};
|
gb_global String global_module_path = {0};
|
||||||
gb_global bool global_module_path_set = false;
|
gb_global bool global_module_path_set = false;
|
||||||
|
|
||||||
|
|||||||
+56
-3
@@ -1,3 +1,10 @@
|
|||||||
|
|
||||||
|
#if defined(GB_COMPILER_MSVC) && defined(GB_ARCH_64_BIT) && defined(GB_CPU_X86)
|
||||||
|
#define MSVC_AMD64_INTRINSICS
|
||||||
|
#include <intrin.h>
|
||||||
|
#pragma intrinsic(_mul128)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define BIT128_U64_HIGHBIT 0x8000000000000000ull
|
#define BIT128_U64_HIGHBIT 0x8000000000000000ull
|
||||||
#define BIT128_U64_BITS62 0x7fffffffffffffffull
|
#define BIT128_U64_BITS62 0x7fffffffffffffffull
|
||||||
#define BIT128_U64_ALLBITS 0xffffffffffffffffull
|
#define BIT128_U64_ALLBITS 0xffffffffffffffffull
|
||||||
@@ -376,7 +383,11 @@ u128 u128_shl(u128 a, u32 n) {
|
|||||||
if (n >= 128) {
|
if (n >= 128) {
|
||||||
return u128_lo_hi(0, 0);
|
return u128_lo_hi(0, 0);
|
||||||
}
|
}
|
||||||
|
#if 0 && defined(MSVC_AMD64_INTRINSICS)
|
||||||
|
a.hi = __shiftleft128(a.lo, a.hi, n);
|
||||||
|
a.lo = a.lo << n;
|
||||||
|
return a;
|
||||||
|
#else
|
||||||
if (n >= 64) {
|
if (n >= 64) {
|
||||||
n -= 64;
|
n -= 64;
|
||||||
a.hi = a.lo;
|
a.hi = a.lo;
|
||||||
@@ -391,13 +402,18 @@ u128 u128_shl(u128 a, u32 n) {
|
|||||||
a.lo <<= n;
|
a.lo <<= n;
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
u128 u128_shr(u128 a, u32 n) {
|
u128 u128_shr(u128 a, u32 n) {
|
||||||
if (n >= 128) {
|
if (n >= 128) {
|
||||||
return u128_lo_hi(0, 0);
|
return u128_lo_hi(0, 0);
|
||||||
}
|
}
|
||||||
|
#if 0 && defined(MSVC_AMD64_INTRINSICS)
|
||||||
|
a.lo = __shiftright128(a.lo, a.hi, n);
|
||||||
|
a.hi = a.hi >> n;
|
||||||
|
return a;
|
||||||
|
#else
|
||||||
if (n >= 64) {
|
if (n >= 64) {
|
||||||
n -= 64;
|
n -= 64;
|
||||||
a.lo = a.hi;
|
a.lo = a.hi;
|
||||||
@@ -411,6 +427,7 @@ u128 u128_shr(u128 a, u32 n) {
|
|||||||
a.hi >>= n;
|
a.hi >>= n;
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -427,6 +444,14 @@ u128 u128_mul(u128 a, u128 b) {
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(MSVC_AMD64_INTRINSICS)
|
||||||
|
if (a.hi == 0 && b.hi == 0) {
|
||||||
|
a.lo = _umul128(a.lo, b.lo, &a.hi);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
u128 res = {0};
|
u128 res = {0};
|
||||||
u128 t = b;
|
u128 t = b;
|
||||||
for (u32 i = 0; i < 128; i++) {
|
for (u32 i = 0; i < 128; i++) {
|
||||||
@@ -440,6 +465,8 @@ u128 u128_mul(u128 a, u128 b) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool u128_hibit(u128 *d) { return (d->hi & BIT128_U64_HIGHBIT) != 0; }
|
||||||
|
|
||||||
void u128_divide(u128 num, u128 den, u128 *quo, u128 *rem) {
|
void u128_divide(u128 num, u128 den, u128 *quo, u128 *rem) {
|
||||||
if (u128_eq(den, U128_ZERO)) {
|
if (u128_eq(den, U128_ZERO)) {
|
||||||
if (quo) *quo = u128_from_u64(num.lo/den.lo);
|
if (quo) *quo = u128_from_u64(num.lo/den.lo);
|
||||||
@@ -450,7 +477,7 @@ void u128_divide(u128 num, u128 den, u128 *quo, u128 *rem) {
|
|||||||
u128 x = U128_ONE;
|
u128 x = U128_ONE;
|
||||||
u128 r = U128_ZERO;
|
u128 r = U128_ZERO;
|
||||||
|
|
||||||
while (u128_ge(n, d) && ((u128_shr(d, 128-1).lo&1) == 0)) {
|
while (u128_ge(n, d) && !u128_hibit(&d)) {
|
||||||
x = u128_shl(x, 1);
|
x = u128_shl(x, 1);
|
||||||
d = u128_shl(d, 1);
|
d = u128_shl(d, 1);
|
||||||
}
|
}
|
||||||
@@ -471,11 +498,18 @@ void u128_divide(u128 num, u128 den, u128 *quo, u128 *rem) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u128 u128_quo(u128 a, u128 b) {
|
u128 u128_quo(u128 a, u128 b) {
|
||||||
|
if (a.hi == 0 && b.hi == 0) {
|
||||||
|
return u128_from_u64(a.lo/b.lo);
|
||||||
|
}
|
||||||
|
|
||||||
u128 res = {0};
|
u128 res = {0};
|
||||||
u128_divide(a, b, &res, NULL);
|
u128_divide(a, b, &res, NULL);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
u128 u128_mod(u128 a, u128 b) {
|
u128 u128_mod(u128 a, u128 b) {
|
||||||
|
if (a.hi == 0 && b.hi == 0) {
|
||||||
|
return u128_from_u64(a.lo%b.lo);
|
||||||
|
}
|
||||||
u128 res = {0};
|
u128 res = {0};
|
||||||
u128_divide(a, b, NULL, &res);
|
u128_divide(a, b, NULL, &res);
|
||||||
return res;
|
return res;
|
||||||
@@ -535,6 +569,11 @@ i128 i128_shl(i128 a, u32 n) {
|
|||||||
return i128_lo_hi(0, 0);
|
return i128_lo_hi(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0 && defined(MSVC_AMD64_INTRINSICS)
|
||||||
|
a.hi = __shiftleft128(a.lo, a.hi, n);
|
||||||
|
a.lo = a.lo << n;
|
||||||
|
return a;
|
||||||
|
#else
|
||||||
if (n >= 64) {
|
if (n >= 64) {
|
||||||
n -= 64;
|
n -= 64;
|
||||||
a.hi = a.lo;
|
a.hi = a.lo;
|
||||||
@@ -549,6 +588,7 @@ i128 i128_shl(i128 a, u32 n) {
|
|||||||
a.lo <<= n;
|
a.lo <<= n;
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
i128 i128_shr(i128 a, u32 n) {
|
i128 i128_shr(i128 a, u32 n) {
|
||||||
@@ -556,6 +596,11 @@ i128 i128_shr(i128 a, u32 n) {
|
|||||||
return i128_lo_hi(0, 0);
|
return i128_lo_hi(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0 && defined(MSVC_AMD64_INTRINSICS)
|
||||||
|
a.lo = __shiftright128(a.lo, a.hi, n);
|
||||||
|
a.hi = a.hi >> n;
|
||||||
|
return a;
|
||||||
|
#else
|
||||||
if (n >= 64) {
|
if (n >= 64) {
|
||||||
n -= 64;
|
n -= 64;
|
||||||
a.lo = a.hi;
|
a.lo = a.hi;
|
||||||
@@ -569,6 +614,7 @@ i128 i128_shr(i128 a, u32 n) {
|
|||||||
a.hi >>= n;
|
a.hi >>= n;
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -585,6 +631,13 @@ i128 i128_mul(i128 a, i128 b) {
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(MSVC_AMD64_INTRINSICS)
|
||||||
|
if (a.hi == 0 && b.hi == 0) {
|
||||||
|
a.lo = _mul128(a.lo, b.lo, &a.hi);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
i128 res = {0};
|
i128 res = {0};
|
||||||
i128 t = b;
|
i128 t = b;
|
||||||
for (u32 i = 0; i < 128; i++) {
|
for (u32 i = 0; i < 128; i++) {
|
||||||
|
|||||||
+35
-6
@@ -4599,6 +4599,35 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
|
|||||||
GB_ASSERT(proc_type_->kind == Type_Proc);
|
GB_ASSERT(proc_type_->kind == Type_Proc);
|
||||||
TypeProc *type = &proc_type_->Proc;
|
TypeProc *type = &proc_type_->Proc;
|
||||||
|
|
||||||
|
if (is_call_expr_field_value(ce)) {
|
||||||
|
isize param_count = type->param_count;
|
||||||
|
irValue **args = gb_alloc_array(proc->module->allocator, irValue *, param_count);
|
||||||
|
|
||||||
|
for_array(arg_index, ce->args) {
|
||||||
|
AstNode *arg = ce->args[arg_index];
|
||||||
|
ast_node(fv, FieldValue, arg);
|
||||||
|
GB_ASSERT(fv->field->kind == AstNode_Ident);
|
||||||
|
String name = fv->field->Ident.string;
|
||||||
|
isize index = lookup_procedure_parameter(type, name);
|
||||||
|
GB_ASSERT(index >= 0);
|
||||||
|
irValue *expr = ir_build_expr(proc, fv->value);
|
||||||
|
args[index] = expr;
|
||||||
|
|
||||||
|
}
|
||||||
|
TypeTuple *pt = &type->params->Tuple;
|
||||||
|
for (isize i = 0; i < param_count; i++) {
|
||||||
|
Type *param_type = pt->variables[i]->type;
|
||||||
|
if (args[i] == NULL) {
|
||||||
|
args[i] = ir_value_nil(proc->module->allocator, param_type);
|
||||||
|
} else {
|
||||||
|
args[i] = ir_emit_conv(proc, args[i], param_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ir_emit_call(proc, value, args, param_count);
|
||||||
|
// GB_PANIC("HERE!\n");
|
||||||
|
}
|
||||||
|
|
||||||
isize arg_index = 0;
|
isize arg_index = 0;
|
||||||
|
|
||||||
isize arg_count = 0;
|
isize arg_count = 0;
|
||||||
@@ -4612,7 +4641,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
irValue **args = gb_alloc_array(proc->module->allocator, irValue *, arg_count);
|
irValue **args = gb_alloc_array(proc->module->allocator, irValue *, arg_count);
|
||||||
bool variadic = proc_type_->Proc.variadic;
|
bool variadic = type->variadic;
|
||||||
bool vari_expand = ce->ellipsis.pos.line != 0;
|
bool vari_expand = ce->ellipsis.pos.line != 0;
|
||||||
|
|
||||||
for_array(i, ce->args) {
|
for_array(i, ce->args) {
|
||||||
@@ -6855,7 +6884,7 @@ void ir_init_module(irModule *m, Checker *c) {
|
|||||||
isize max_index = -1;
|
isize max_index = -1;
|
||||||
for_array(type_info_map_index, m->info->type_info_map.entries) {
|
for_array(type_info_map_index, m->info->type_info_map.entries) {
|
||||||
auto *entry = &m->info->type_info_map.entries[type_info_map_index];
|
auto *entry = &m->info->type_info_map.entries[type_info_map_index];
|
||||||
Type *t = cast(Type *)cast(uintptr)entry->key.key;
|
Type *t = cast(Type *)entry->key.ptr;
|
||||||
t = default_type(t);
|
t = default_type(t);
|
||||||
isize entry_index = ir_type_info_index(m->info, t);
|
isize entry_index = ir_type_info_index(m->info, t);
|
||||||
if (max_index < entry_index) {
|
if (max_index < entry_index) {
|
||||||
@@ -6880,7 +6909,7 @@ void ir_init_module(irModule *m, Checker *c) {
|
|||||||
|
|
||||||
for_array(entry_index, m->info->type_info_map.entries) {
|
for_array(entry_index, m->info->type_info_map.entries) {
|
||||||
auto *entry = &m->info->type_info_map.entries[entry_index];
|
auto *entry = &m->info->type_info_map.entries[entry_index];
|
||||||
Type *t = cast(Type *)cast(uintptr)entry->key.key;
|
Type *t = cast(Type *)entry->key.ptr;
|
||||||
|
|
||||||
switch (t->kind) {
|
switch (t->kind) {
|
||||||
case Type_Record:
|
case Type_Record:
|
||||||
@@ -7083,7 +7112,7 @@ void ir_gen_tree(irGen *s) {
|
|||||||
|
|
||||||
for_array(i, info->entities.entries) {
|
for_array(i, info->entities.entries) {
|
||||||
auto *entry = &info->entities.entries[i];
|
auto *entry = &info->entities.entries[i];
|
||||||
Entity *e = cast(Entity *)cast(uintptr)entry->key.key;
|
Entity *e = cast(Entity *)entry->key.ptr;
|
||||||
String name = e->token.string;
|
String name = e->token.string;
|
||||||
if (e->kind == Entity_Variable) {
|
if (e->kind == Entity_Variable) {
|
||||||
global_variable_max_count++;
|
global_variable_max_count++;
|
||||||
@@ -7446,7 +7475,7 @@ void ir_gen_tree(irGen *s) {
|
|||||||
|
|
||||||
for_array(type_info_map_index, info->type_info_map.entries) {
|
for_array(type_info_map_index, info->type_info_map.entries) {
|
||||||
auto *entry = &info->type_info_map.entries[type_info_map_index];
|
auto *entry = &info->type_info_map.entries[type_info_map_index];
|
||||||
Type *t = cast(Type *)cast(uintptr)entry->key.key;
|
Type *t = cast(Type *)entry->key.ptr;
|
||||||
t = default_type(t);
|
t = default_type(t);
|
||||||
isize entry_index = ir_type_info_index(info, t);
|
isize entry_index = ir_type_info_index(info, t);
|
||||||
|
|
||||||
@@ -7909,7 +7938,7 @@ void ir_gen_tree(irGen *s) {
|
|||||||
|
|
||||||
for_array(type_info_map_index, info->type_info_map.entries) {
|
for_array(type_info_map_index, info->type_info_map.entries) {
|
||||||
auto *entry = &info->type_info_map.entries[type_info_map_index];
|
auto *entry = &info->type_info_map.entries[type_info_map_index];
|
||||||
Type *t = cast(Type *)cast(uintptr)entry->key.key;
|
Type *t = cast(Type *)entry->key.ptr;
|
||||||
t = default_type(t);
|
t = default_type(t);
|
||||||
isize entry_index = entry->value;
|
isize entry_index = entry->value;
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -19,6 +19,7 @@ enum HashKeyKind {
|
|||||||
|
|
||||||
struct HashKey {
|
struct HashKey {
|
||||||
HashKeyKind kind;
|
HashKeyKind kind;
|
||||||
|
// u128 key;
|
||||||
u64 key;
|
u64 key;
|
||||||
union {
|
union {
|
||||||
String string; // if String, s.len > 0
|
String string; // if String, s.len > 0
|
||||||
@@ -29,9 +30,8 @@ struct HashKey {
|
|||||||
gb_inline HashKey hashing_proc(void const *data, isize len) {
|
gb_inline HashKey hashing_proc(void const *data, isize len) {
|
||||||
HashKey h = {HashKey_Default};
|
HashKey h = {HashKey_Default};
|
||||||
h.kind = HashKey_Default;
|
h.kind = HashKey_Default;
|
||||||
// h.key = gb_murmur64(data, len);
|
// h.key = u128_from_u64(gb_fnv64a(data, len));
|
||||||
h.key = gb_fnv64a(data, len);
|
h.key = gb_fnv64a(data, len);
|
||||||
// h.key = MurmurHash3_128(data, len, 0x3803cb8e);
|
|
||||||
|
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
@@ -136,7 +136,8 @@ template <typename T>
|
|||||||
gb_internal MapFindResult map__find(Map<T> *h, HashKey key) {
|
gb_internal MapFindResult map__find(Map<T> *h, HashKey key) {
|
||||||
MapFindResult fr = {-1, -1, -1};
|
MapFindResult fr = {-1, -1, -1};
|
||||||
if (h->hashes.count > 0) {
|
if (h->hashes.count > 0) {
|
||||||
fr.hash_index = key.key % h->hashes.count;
|
// fr.hash_index = u128_to_i64(key.key % u128_from_i64(h->hashes.count));
|
||||||
|
fr.hash_index = key.key % h->hashes.count;
|
||||||
fr.entry_index = h->hashes[fr.hash_index];
|
fr.entry_index = h->hashes[fr.hash_index];
|
||||||
while (fr.entry_index >= 0) {
|
while (fr.entry_index >= 0) {
|
||||||
if (hash_key_equal(h->entries[fr.entry_index].key, key)) {
|
if (hash_key_equal(h->entries[fr.entry_index].key, key)) {
|
||||||
|
|||||||
+22
-17
@@ -41,15 +41,15 @@ gb_inline u64 fmix64(u64 k) {
|
|||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_inline u32 mm3_getblock32(u32 *const p, isize i) {
|
gb_inline u32 mm3_getblock32(u32 const *p, isize i) {
|
||||||
return p[i];
|
return p[i];
|
||||||
}
|
}
|
||||||
gb_inline u64 mm3_getblock64(u64 *const p, isize i) {
|
gb_inline u64 mm3_getblock64(u64 const *p, isize i) {
|
||||||
return p[i];
|
return p[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
u128 MurmurHash3_x64_128(void *const key, isize len, u32 seed) {
|
void MurmurHash3_x64_128(void const *key, isize len, u32 seed, void *out) {
|
||||||
u8 *const data = cast(u8 *const)key;
|
u8 const * data = cast(u8 const *)key;
|
||||||
isize nblocks = len / 16;
|
isize nblocks = len / 16;
|
||||||
|
|
||||||
u64 h1 = seed;
|
u64 h1 = seed;
|
||||||
@@ -58,7 +58,7 @@ u128 MurmurHash3_x64_128(void *const key, isize len, u32 seed) {
|
|||||||
u64 const c1 = 0x87c37b91114253d5ULL;
|
u64 const c1 = 0x87c37b91114253d5ULL;
|
||||||
u64 const c2 = 0x4cf5ad432745937fULL;
|
u64 const c2 = 0x4cf5ad432745937fULL;
|
||||||
|
|
||||||
u64 *const blocks = cast(u64 *const)data;
|
u64 const * blocks = cast(u64 const *)data;
|
||||||
|
|
||||||
for (isize i = 0; i < nblocks; i++) {
|
for (isize i = 0; i < nblocks; i++) {
|
||||||
u64 k1 = mm3_getblock64(blocks, i*2 + 0);
|
u64 k1 = mm3_getblock64(blocks, i*2 + 0);
|
||||||
@@ -70,7 +70,7 @@ u128 MurmurHash3_x64_128(void *const key, isize len, u32 seed) {
|
|||||||
h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
|
h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 *const tail = cast(u8 *const)(data + nblocks*16);
|
u8 const * tail = cast(u8 const *)(data + nblocks*16);
|
||||||
|
|
||||||
u64 k1 = 0;
|
u64 k1 = 0;
|
||||||
u64 k2 = 0;
|
u64 k2 = 0;
|
||||||
@@ -108,11 +108,12 @@ u128 MurmurHash3_x64_128(void *const key, isize len, u32 seed) {
|
|||||||
h1 += h2;
|
h1 += h2;
|
||||||
h2 += h1;
|
h2 += h1;
|
||||||
|
|
||||||
return u128_lo_hi(h1, h2);
|
((u64 *)out)[0] = h1;
|
||||||
|
((u64 *)out)[1] = h2;
|
||||||
}
|
}
|
||||||
|
|
||||||
u128 MurmurHash3_x86_128(void *const key, isize len, u32 seed) {
|
void MurmurHash3_x86_128(void const *key, isize len, u32 seed, void *out) {
|
||||||
u8 *const data = cast(u8 * const)key;
|
u8 const * data = cast(u8 * const)key;
|
||||||
isize nblocks = len / 16;
|
isize nblocks = len / 16;
|
||||||
|
|
||||||
u32 h1 = seed;
|
u32 h1 = seed;
|
||||||
@@ -128,7 +129,7 @@ u128 MurmurHash3_x86_128(void *const key, isize len, u32 seed) {
|
|||||||
//----------
|
//----------
|
||||||
// body
|
// body
|
||||||
|
|
||||||
u32 *const blocks = cast(u32 *const)(data + nblocks*16);
|
u32 const * blocks = cast(u32 const *)(data + nblocks*16);
|
||||||
|
|
||||||
for (isize i = -nblocks; i != 0; i++) {
|
for (isize i = -nblocks; i != 0; i++) {
|
||||||
u32 k1 = mm3_getblock32(blocks, i*4 + 0);
|
u32 k1 = mm3_getblock32(blocks, i*4 + 0);
|
||||||
@@ -156,7 +157,7 @@ u128 MurmurHash3_x86_128(void *const key, isize len, u32 seed) {
|
|||||||
//----------
|
//----------
|
||||||
// tail
|
// tail
|
||||||
|
|
||||||
u8 *const tail = cast(u8 *const)(data + nblocks*16);
|
u8 const * tail = cast(u8 const *)(data + nblocks*16);
|
||||||
|
|
||||||
u32 k1 = 0;
|
u32 k1 = 0;
|
||||||
u32 k2 = 0;
|
u32 k2 = 0;
|
||||||
@@ -204,17 +205,21 @@ u128 MurmurHash3_x86_128(void *const key, isize len, u32 seed) {
|
|||||||
h1 += h2; h1 += h3; h1 += h4;
|
h1 += h2; h1 += h3; h1 += h4;
|
||||||
h2 += h1; h3 += h1; h4 += h1;
|
h2 += h1; h3 += h1; h4 += h1;
|
||||||
|
|
||||||
u64 lo = (u64)h1 | ((u64)h2 << 32);
|
|
||||||
u64 hi = (u64)h3 | ((u64)h4 << 32);
|
((u32 *)out)[0] = h1;
|
||||||
return u128_lo_hi(lo, hi);
|
((u32 *)out)[1] = h2;
|
||||||
|
((u32 *)out)[2] = h3;
|
||||||
|
((u32 *)out)[3] = h4;
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_inline u128 MurmurHash3_128(void *const key, isize len, u32 seed) {
|
gb_inline u128 MurmurHash3_128(void const *key, isize len, u32 seed) {
|
||||||
|
u128 res;
|
||||||
#if defined(GB_ARCH_64_BIT)
|
#if defined(GB_ARCH_64_BIT)
|
||||||
return MurmurHash3_x64_128(key, len, seed);
|
MurmurHash3_x64_128(key, len, seed, &res);
|
||||||
#else
|
#else
|
||||||
return MurmurHash3_x86_128(key, len, seed);
|
MurmurHash3_x86_128(key, len, seed, &res);
|
||||||
#endif
|
#endif
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2128,6 +2128,11 @@ AstNode *parse_call_expr(AstFile *f, AstNode *operand) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AstNode *arg = parse_expr(f, false);
|
AstNode *arg = parse_expr(f, false);
|
||||||
|
if (f->curr_token.kind == Token_Eq) {
|
||||||
|
Token eq = expect_token(f, Token_Eq);
|
||||||
|
AstNode *value = parse_value(f);
|
||||||
|
arg = ast_field_value(f, arg, value, eq);
|
||||||
|
}
|
||||||
array_add(&args, arg);
|
array_add(&args, arg);
|
||||||
|
|
||||||
if (!allow_token(f, Token_Comma)) {
|
if (!allow_token(f, Token_Comma)) {
|
||||||
|
|||||||
+1
-1
@@ -2493,7 +2493,7 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) {
|
|||||||
|
|
||||||
for_array(i, info->entities.entries) {
|
for_array(i, info->entities.entries) {
|
||||||
auto *entry = &info->entities.entries[i];
|
auto *entry = &info->entities.entries[i];
|
||||||
Entity *e = cast(Entity *)cast(uintptr)entry->key.key;
|
Entity *e = cast(Entity *)entry->key.ptr;
|
||||||
String name = e->token.string;
|
String name = e->token.string;
|
||||||
if (e->kind == Entity_Variable) {
|
if (e->kind == Entity_Variable) {
|
||||||
global_variable_max_count++;
|
global_variable_max_count++;
|
||||||
|
|||||||
+1
-1
@@ -110,7 +110,7 @@ f64 time_stamp_as_ms(TimeStamp ts, u64 freq) {
|
|||||||
|
|
||||||
void timings_print_all(Timings *t) {
|
void timings_print_all(Timings *t) {
|
||||||
char const SPACES[] = " ";
|
char const SPACES[] = " ";
|
||||||
isize max_len, i;
|
isize max_len;
|
||||||
|
|
||||||
timings__stop_current_section(t);
|
timings__stop_current_section(t);
|
||||||
t->total.finish = time_stamp_time_now();
|
t->total.finish = time_stamp_time_now();
|
||||||
|
|||||||
Reference in New Issue
Block a user