diff options
| author | gingerBill <bill@gingerbill.org> | 2020-06-16 16:21:44 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2020-06-16 16:21:44 +0100 |
| commit | 781395ada1883203582adec70e5ab1a2eda316bb (patch) | |
| tree | 3064a744c0b406c83c74b9d05c9c87fd392f8b8f /src | |
| parent | 9635ea8706e462bf5c42c8fbaf792b96137ad21a (diff) | |
Add `deferred_in_out` attribute
Diffstat (limited to 'src')
| -rw-r--r-- | src/checker.cpp | 66 | ||||
| -rw-r--r-- | src/checker.hpp | 1 | ||||
| -rw-r--r-- | src/ir.cpp | 8 | ||||
| -rw-r--r-- | src/llvm_backend.cpp | 8 |
4 files changed, 83 insertions, 0 deletions
diff --git a/src/checker.cpp b/src/checker.cpp index 2ca4d794f..df15ffc67 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2337,6 +2337,22 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) { } error(elem, "Expected a procedure entity for '%.*s'", LIT(name)); return false; + } else if (name == "deferred_in_out") { + if (value != nullptr) { + Operand o = {}; + check_expr(c, &o, value); + Entity *e = entity_of_node(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_out; + ac->deferred_procedure.entity = e; + return true; + } + } + error(elem, "Expected a procedure entity for '%.*s'", LIT(name)); + return false; } else if (name == "link_name") { ExactValue ev = check_decl_attribute_value(c, value); @@ -4379,6 +4395,9 @@ void check_parsed_files(Checker *c) { case DeferredProcedure_out: error(src->token, "'deferred_out' cannot be used with a polymorphic procedure"); break; + case DeferredProcedure_in_out: + error(src->token, "'deferred_in_out' cannot be used with a polymorphic procedure"); + break; } continue; } @@ -4457,6 +4476,53 @@ void check_parsed_files(Checker *c) { gb_string_free(s); continue; } + } else if (dst_kind == DeferredProcedure_in_out) { + if (src_params == nullptr && src_results == nullptr && dst_params == nullptr) { + // Okay + continue; + } + + GB_ASSERT(dst_params->kind == Type_Tuple); + + Type *tsrc = alloc_type_tuple(); + auto &sv = tsrc->Tuple.variables; + auto const &dv = dst_params->Tuple.variables; + + isize len = 0; + if (src_params != nullptr) { + GB_ASSERT(src_params->kind == Type_Tuple); + len += src_params->Tuple.variables.count; + } + if (src_results != nullptr) { + GB_ASSERT(src_results->kind == Type_Tuple); + len += src_results->Tuple.variables.count; + } + array_init(&sv, heap_allocator(), 0, len); + if (src_params != nullptr) { + for_array(i, src_params->Tuple.variables) { + array_add(&sv, src_params->Tuple.variables[i]); + } + } + if (src_results != nullptr) { + for_array(i, src_results->Tuple.variables) { + array_add(&sv, src_results->Tuple.variables[i]); + } + } + + + if (are_types_identical(tsrc, dst_params)) { + // Okay! + } else { + gbString s = type_to_string(tsrc); + 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; + } } } diff --git a/src/checker.hpp b/src/checker.hpp index 161c6b72e..3d21a4cec 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -89,6 +89,7 @@ enum DeferredProcedureKind { DeferredProcedure_none, DeferredProcedure_in, DeferredProcedure_out, + DeferredProcedure_in_out, }; struct DeferredProcedure { DeferredProcedureKind kind; diff --git a/src/ir.cpp b/src/ir.cpp index fb1a20f6d..60f1a1192 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3319,6 +3319,14 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> const &ar case DeferredProcedure_out: result_as_args = ir_value_to_array(p, result); break; + case DeferredProcedure_in_out: + { + auto out_args = ir_value_to_array(p, result); + array_init(&result_as_args, heap_allocator(), in_args.count + out_args.count); + array_copy(&result_as_args, in_args, 0); + array_copy(&result_as_args, out_args, in_args.count); + } + break; } ir_add_defer_proc(p, p->scope_index, deferred, result_as_args); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index bc3cba109..994e0f29e 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -7113,6 +7113,14 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, case DeferredProcedure_out: result_as_args = lb_value_to_array(p, result); break; + case DeferredProcedure_in_out: + { + auto out_args = lb_value_to_array(p, result); + array_init(&result_as_args, heap_allocator(), in_args.count + out_args.count); + array_copy(&result_as_args, in_args, 0); + array_copy(&result_as_args, out_args, in_args.count); + } + break; } lb_add_defer_proc(p, p->scope_index, deferred, result_as_args); |