Replace deferred with deferred_none, deferred_in, deferred_out

This commit is contained in:
gingerBill
2019-01-13 19:34:08 +00:00
parent 493f11521d
commit 8fc24fd6f2
6 changed files with 169 additions and 41 deletions
+1 -1
View File
@@ -872,7 +872,7 @@ diverging_procedures :: proc() {
} }
deferred_procedure_associations :: proc() { deferred_procedure_associations :: proc() {
@(deferred=closure) @(deferred_out=closure)
open :: proc(s: string) -> bool { open :: proc(s: string) -> bool {
fmt.println(s); fmt.println(s);
return true; return true;
+1 -1
View File
@@ -633,7 +633,7 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
e->Procedure.link_name = ac.link_name; e->Procedure.link_name = ac.link_name;
} }
if (ac.deferred_procedure != nullptr) { if (ac.deferred_procedure.entity != nullptr) {
e->Procedure.deferred_procedure = ac.deferred_procedure; e->Procedure.deferred_procedure = ac.deferred_procedure;
array_add(&ctx->checker->procs_with_deferred_to_check, e); array_add(&ctx->checker->procs_with_deferred_to_check, e);
} }
+138 -34
View File
@@ -1038,7 +1038,7 @@ void add_entity_use(CheckerContext *c, Ast *identifier, Entity *entity) {
entity->flags |= EntityFlag_Used; entity->flags |= EntityFlag_Used;
add_declaration_dependency(c, entity); add_declaration_dependency(c, entity);
if (entity_has_deferred_procedure(entity)) { if (entity_has_deferred_procedure(entity)) {
Entity *deferred = entity->Procedure.deferred_procedure; Entity *deferred = entity->Procedure.deferred_procedure.entity;
add_entity_use(c, nullptr, deferred); add_entity_use(c, nullptr, deferred);
} }
} }
@@ -1933,24 +1933,71 @@ DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) {
} }
DECL_ATTRIBUTE_PROC(proc_decl_attribute) { DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
ExactValue ev = {};
if (name != "deferred") {
ev = check_decl_attribute_value(c, value);
}
if (name == "deferred") { if (name == "deferred") {
if (value != nullptr) { if (value != nullptr) {
Operand o = {}; Operand o = {};
check_expr(c, &o, value); check_expr(c, &o, value);
Entity *e = entity_of_ident(o.expr); Entity *e = entity_of_ident(o.expr);
if (e != nullptr && e->kind == Entity_Procedure) { if (e != nullptr && e->kind == Entity_Procedure) {
ac->deferred_procedure = e; warning(elem, "'%.*s' is deprecated, please use one of the following instead: 'deferred_none', 'deferred_in', 'deferred_out'", LIT(name));
if (ac->deferred_procedure.entity != nullptr) {
error(elem, "Previous usage of a 'deferred_*' attribute");
}
ac->deferred_procedure.kind = DeferredProcedure_out;
ac->deferred_procedure.entity = e;
return true;
}
}
error(elem, "Expected a procedure entity for '%.*s'", LIT(name));
return false;
} else if (name == "deferred_none") {
if (value != nullptr) {
Operand o = {};
check_expr(c, &o, value);
Entity *e = entity_of_ident(o.expr);
if (e != nullptr && e->kind == Entity_Procedure) {
ac->deferred_procedure.kind = DeferredProcedure_none;
ac->deferred_procedure.entity = e;
return true;
}
}
error(elem, "Expected a procedure entity for '%.*s'", LIT(name));
return false;
} else if (name == "deferred_in") {
if (value != nullptr) {
Operand o = {};
check_expr(c, &o, value);
Entity *e = entity_of_ident(o.expr);
if (e != nullptr && e->kind == Entity_Procedure) {
if (ac->deferred_procedure.entity != nullptr) {
error(elem, "Previous usage of a 'deferred_*' attribute");
}
ac->deferred_procedure.kind = DeferredProcedure_in;
ac->deferred_procedure.entity = e;
return true;
}
}
error(elem, "Expected a procedure entity for '%.*s'", LIT(name));
return false;
} else if (name == "deferred_out") {
if (value != nullptr) {
Operand o = {};
check_expr(c, &o, value);
Entity *e = entity_of_ident(o.expr);
if (e != nullptr && e->kind == Entity_Procedure) {
if (ac->deferred_procedure.entity != nullptr) {
error(elem, "Previous usage of a 'deferred_*' attribute");
}
ac->deferred_procedure.kind = DeferredProcedure_out;
ac->deferred_procedure.entity = e;
return true; return true;
} }
} }
error(elem, "Expected a procedure entity for '%.*s'", LIT(name)); error(elem, "Expected a procedure entity for '%.*s'", LIT(name));
return false; return false;
} else if (name == "link_name") { } else if (name == "link_name") {
ExactValue ev = check_decl_attribute_value(c, value);
if (ev.kind == ExactValue_String) { if (ev.kind == ExactValue_String) {
ac->link_name = ev.value_string; ac->link_name = ev.value_string;
if (!is_foreign_name_valid(ac->link_name)) { if (!is_foreign_name_valid(ac->link_name)) {
@@ -1961,6 +2008,8 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
} }
return true; return true;
} else if (name == "link_prefix") { } else if (name == "link_prefix") {
ExactValue ev = check_decl_attribute_value(c, value);
if (ev.kind == ExactValue_String) { if (ev.kind == ExactValue_String) {
ac->link_prefix = ev.value_string; ac->link_prefix = ev.value_string;
if (!is_foreign_name_valid(ac->link_prefix)) { if (!is_foreign_name_valid(ac->link_prefix)) {
@@ -1971,6 +2020,8 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
} }
return true; return true;
} else if (name == "deprecated") { } else if (name == "deprecated") {
ExactValue ev = check_decl_attribute_value(c, value);
if (ev.kind == ExactValue_String) { if (ev.kind == ExactValue_String) {
String msg = ev.value_string; String msg = ev.value_string;
if (msg.len == 0) { if (msg.len == 0) {
@@ -3617,47 +3668,100 @@ void check_parsed_files(Checker *c) {
Entity *src = c->procs_with_deferred_to_check[i]; Entity *src = c->procs_with_deferred_to_check[i];
GB_ASSERT(src->kind == Entity_Procedure); GB_ASSERT(src->kind == Entity_Procedure);
Entity *dst = src->Procedure.deferred_procedure; DeferredProcedureKind dst_kind = src->Procedure.deferred_procedure.kind;
Entity *dst = src->Procedure.deferred_procedure.entity;
GB_ASSERT(dst != nullptr); GB_ASSERT(dst != nullptr);
GB_ASSERT(dst->kind == Entity_Procedure); GB_ASSERT(dst->kind == Entity_Procedure);
if (is_type_polymorphic(src->type) || is_type_polymorphic(dst->type)) { if (is_type_polymorphic(src->type) || is_type_polymorphic(dst->type)) {
error(src->token, "'deferred' cannot be used with a polymorphic procedure"); switch (dst_kind) {
case DeferredProcedure_none:
error(src->token, "'deferred_none' cannot be used with a polymorphic procedure");
break;
case DeferredProcedure_in:
error(src->token, "'deferred_in' cannot be used with a polymorphic procedure");
break;
case DeferredProcedure_out:
error(src->token, "'deferred_out' cannot be used with a polymorphic procedure");
break;
}
continue; continue;
} }
GB_ASSERT(is_type_proc(src->type)); GB_ASSERT(is_type_proc(src->type));
GB_ASSERT(is_type_proc(dst->type)); GB_ASSERT(is_type_proc(dst->type));
Type *src_params = base_type(src->type)->Proc.params;
Type *src_results = base_type(src->type)->Proc.results; Type *src_results = base_type(src->type)->Proc.results;
Type *dst_params = base_type(dst->type)->Proc.params; Type *dst_params = base_type(dst->type)->Proc.params;
if (src_results == nullptr && dst_params == nullptr) {
// Okay
continue;
}
if ((src_results == nullptr && dst_params != nullptr) ||
(src_results != nullptr && dst_params == nullptr)) {
error(src->token, "Deferred procedure '%.*s' parameters do not match the results of initial procedure '%.*s'", LIT(src->token.string), LIT(dst->token.string));
continue;
}
GB_ASSERT(src_results->kind == Type_Tuple); if (dst_kind == DeferredProcedure_none) {
GB_ASSERT(dst_params->kind == Type_Tuple); if (dst_params == nullptr) {
// Okay
continue;
}
auto const &sv = src_results->Tuple.variables; error(src->token, "Deferred procedure '%.*s' must have no input parameters", LIT(dst->token.string));
auto const &dv = dst_params->Tuple.variables; } else if (dst_kind == DeferredProcedure_in) {
if (src_params == nullptr && dst_params == nullptr) {
// Okay
continue;
}
if ((src_params == nullptr && dst_params != nullptr) ||
(src_params != nullptr && dst_params == nullptr)) {
error(src->token, "Deferred procedure '%.*s' parameters do not match the inputs of initial procedure '%.*s'", LIT(src->token.string), LIT(dst->token.string));
continue;
}
if (are_types_identical(src_results, dst_params)) { GB_ASSERT(src_params->kind == Type_Tuple);
// Okay! GB_ASSERT(dst_params->kind == Type_Tuple);
} else {
gbString s = type_to_string(src_results); auto const &sv = src_params->Tuple.variables;
gbString d = type_to_string(dst_params); auto const &dv = dst_params->Tuple.variables;
error(src->token, "Deferred procedure '%.*s' parameters do not match the results of initial procedure '%.*s':\n\t(%s) =/= (%s)",
LIT(src->token.string), LIT(dst->token.string), if (are_types_identical(src_params, dst_params)) {
s, d // Okay!
); } else {
gb_string_free(d); gbString s = type_to_string(src_params);
gb_string_free(s); gbString d = type_to_string(dst_params);
continue; error(src->token, "Deferred procedure '%.*s' parameters do not match the inputs of initial procedure '%.*s':\n\t(%s) =/= (%s)",
LIT(src->token.string), LIT(dst->token.string),
s, d
);
gb_string_free(d);
gb_string_free(s);
continue;
}
} else if (dst_kind == DeferredProcedure_out) {
if (src_results == nullptr && dst_params == nullptr) {
// Okay
continue;
}
if ((src_results == nullptr && dst_params != nullptr) ||
(src_results != nullptr && dst_params == nullptr)) {
error(src->token, "Deferred procedure '%.*s' parameters do not match the results of initial procedure '%.*s'", LIT(src->token.string), LIT(dst->token.string));
continue;
}
GB_ASSERT(src_results->kind == Type_Tuple);
GB_ASSERT(dst_params->kind == Type_Tuple);
auto const &sv = src_results->Tuple.variables;
auto const &dv = dst_params->Tuple.variables;
if (are_types_identical(src_results, dst_params)) {
// Okay!
} else {
gbString s = type_to_string(src_results);
gbString d = type_to_string(dst_params);
error(src->token, "Deferred procedure '%.*s' parameters do not match the results of initial procedure '%.*s':\n\t(%s) =/= (%s)",
LIT(src->token.string), LIT(dst->token.string),
s, d
);
gb_string_free(d);
gb_string_free(s);
continue;
}
} }
} }
+12 -1
View File
@@ -288,13 +288,24 @@ struct BlockLabel {
Ast *label; // Ast_Label; Ast *label; // Ast_Label;
}; };
enum DeferredProcedureKind {
DeferredProcedure_none,
DeferredProcedure_in,
DeferredProcedure_out,
};
struct DeferredProcedure {
DeferredProcedureKind kind;
Entity *entity;
};
struct AttributeContext { struct AttributeContext {
String link_name; String link_name;
String link_prefix; String link_prefix;
isize init_expr_list_count; isize init_expr_list_count;
String thread_local_model; String thread_local_model;
String deprecated_message; String deprecated_message;
Entity *deferred_procedure; DeferredProcedure deferred_procedure;
}; };
AttributeContext make_attribute_context(String link_prefix) { AttributeContext make_attribute_context(String link_prefix) {
+3 -2
View File
@@ -77,6 +77,7 @@ struct ParameterValue {
}; };
// An Entity is a named "thing" in the language // An Entity is a named "thing" in the language
struct Entity { struct Entity {
EntityKind kind; EntityKind kind;
@@ -128,7 +129,7 @@ struct Entity {
Ast * foreign_library_ident; Ast * foreign_library_ident;
String link_name; String link_name;
String link_prefix; String link_prefix;
Entity *deferred_procedure; DeferredProcedure deferred_procedure;
bool is_foreign; bool is_foreign;
bool is_export; bool is_export;
} Procedure; } Procedure;
@@ -189,7 +190,7 @@ bool is_entity_exported(Entity *e, bool allow_builtin = false) {
bool entity_has_deferred_procedure(Entity *e) { bool entity_has_deferred_procedure(Entity *e) {
GB_ASSERT(e != nullptr); GB_ASSERT(e != nullptr);
if (e->kind == Entity_Procedure) { if (e->kind == Entity_Procedure) {
return e->Procedure.deferred_procedure != nullptr; return e->Procedure.deferred_procedure.entity != nullptr;
} }
return false; return false;
} }
+14 -2
View File
@@ -2905,12 +2905,24 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> args, Pro
irProcedure *the_proc = &value->Proc; irProcedure *the_proc = &value->Proc;
Entity *e = the_proc->entity; Entity *e = the_proc->entity;
if (entity_has_deferred_procedure(e)) { if (entity_has_deferred_procedure(e)) {
Entity *deferred_entity = e->Procedure.deferred_procedure; DeferredProcedureKind kind = e->Procedure.deferred_procedure.kind;
Entity *deferred_entity = e->Procedure.deferred_procedure.entity;
irValue **deferred_found = map_get(&p->module->values, hash_entity(deferred_entity)); irValue **deferred_found = map_get(&p->module->values, hash_entity(deferred_entity));
GB_ASSERT(deferred_found != nullptr); GB_ASSERT(deferred_found != nullptr);
irValue *deferred = *deferred_found; irValue *deferred = *deferred_found;
Array<irValue *> result_as_args = ir_value_to_array(p, result);
auto in_args = args;
Array<irValue *> result_as_args = {};
switch (kind) {
case DeferredProcedure_none:
break;
case DeferredProcedure_in:
result_as_args = in_args;
case DeferredProcedure_out:
result_as_args = ir_value_to_array(p, result);
break;
}
irValue *deferred_call = ir_de_emit(p, ir_emit_call(p, deferred, result_as_args)); irValue *deferred_call = ir_de_emit(p, ir_emit_call(p, deferred, result_as_args));
ir_add_defer_instr(p, p->scope_index, deferred_call); ir_add_defer_instr(p, p->scope_index, deferred_call);