Browse Source

Add `deferred_in_out` attribute

gingerBill 5 years ago
parent
commit
781395ada1
4 changed files with 83 additions and 0 deletions
  1. 66 0
      src/checker.cpp
  2. 1 0
      src/checker.hpp
  3. 8 0
      src/ir.cpp
  4. 8 0
      src/llvm_backend.cpp

+ 66 - 0
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;
+			}
 		}
 	}
 

+ 1 - 0
src/checker.hpp

@@ -89,6 +89,7 @@ enum DeferredProcedureKind {
 	DeferredProcedure_none,
 	DeferredProcedure_in,
 	DeferredProcedure_out,
+	DeferredProcedure_in_out,
 };
 struct DeferredProcedure {
 	DeferredProcedureKind kind;

+ 8 - 0
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);

+ 8 - 0
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);